| #include <chrono> |
| #include <filesystem> // NOLINT |
| #include <fstream> |
| #include <memory> |
| #include <sstream> |
| #include <string> |
| #include <system_error> // NOLINT |
| #include <thread> // NOLINT |
| #include <unordered_map> |
| |
| #include "bios_settings.grpc.pb.h" |
| #include <gtest/gtest.h> |
| #include "absl/time/clock.h" |
| #include "absl/time/time.h" |
| #include "grpcblob_server.h" |
| #include "grpcpp/client_context.h" |
| #include "grpcpp/create_channel.h" |
| #include "grpcpp/security/credentials.h" |
| #include "grpcpp/server_context.h" |
| #include "grpcpp/support/status.h" |
| |
| #ifndef EXPECT_OK |
| #define EXPECT_OK(x) EXPECT_TRUE(x.ok()) |
| #endif |
| |
| namespace blobs { |
| namespace { |
| |
| using ::google::protobuf::Empty; |
| using ::grpc::Channel; |
| using ::grpc::ClientContext; |
| using ::phosphor::bios::BiosSettings; |
| using ::phosphor::bios::OpaqueSettings; |
| using phosphor::bios::grpc_gen::BiosSettingsService; |
| |
| class BiosSettingsTest : public ::testing::Test { |
| protected: |
| static void SetUpTestSuite() { |
| server_ = std::make_unique<GrpcBlobServer>("/tmp"); |
| server_->start(); |
| std::shared_ptr<Channel> channel = grpc::CreateChannel( |
| "localhost:10166", grpc::InsecureChannelCredentials()); |
| biossettings_stub_ = BiosSettingsService::NewStub(channel); |
| } |
| |
| static void TearDownTestSuite() { |
| absl::SleepFor(absl::Seconds(5)); |
| server_->stop(); |
| server_.reset(); |
| biossettings_stub_.reset(); |
| } |
| |
| static void removeFile(const std::filesystem::path& path) { |
| std::error_code ec; // For error handling during removal |
| if (std::filesystem::exists(path)) { // Only try to remove if it exists |
| std::filesystem::remove(path, ec); |
| ASSERT_FALSE(std::filesystem::exists(path)) |
| << "Failed to remove file: " << path << " Error: " << ec.message(); |
| } |
| } |
| |
| static std::unique_ptr<GrpcBlobServer> server_; |
| static std::unique_ptr<BiosSettingsService::Stub> biossettings_stub_; |
| const std::string kConfiguredFilepath = |
| "/tmp/var/google/bios/configured-settings.txt"; |
| const std::string kReportedFilepath = |
| "/tmp/var/google/bios/reported-settings.txt"; |
| }; |
| |
| std::unique_ptr<GrpcBlobServer> BiosSettingsTest::server_; |
| std::unique_ptr<BiosSettingsService::Stub> BiosSettingsTest::biossettings_stub_; |
| |
| TEST_F(BiosSettingsTest, SetBiosSettings) { |
| BiosSettings request; |
| request.set_grace_egm_enabled(true); |
| request.set_grace_egm_hypervisor_reserved_memory_mb(1024); |
| Empty response; |
| ClientContext context; |
| |
| std::error_code ec; |
| std::filesystem::path dirPath("/tmp/var/google"); |
| bool created = std::filesystem::create_directories(dirPath, ec); |
| ASSERT_TRUE(created || !ec) << "Failed to create directory: " << dirPath |
| << " Error: " << ec.message(); |
| |
| EXPECT_OK(biossettings_stub_->SetBiosSettings(&context, request, &response)); |
| |
| BiosSettings get_response; |
| ClientContext get_context; |
| EXPECT_OK( |
| biossettings_stub_->GetBiosSettings(&get_context, {}, &get_response)); |
| EXPECT_EQ(get_response.grace_egm_enabled(), request.grace_egm_enabled()); |
| EXPECT_EQ(get_response.grace_egm_hypervisor_reserved_memory_mb(), |
| request.grace_egm_hypervisor_reserved_memory_mb()); |
| |
| removeFile("/tmp/var/google/bios-settings.txtpb"); |
| } |
| |
| TEST_F(BiosSettingsTest, GetSettingsReturnsFileNotFound) { |
| Empty request; |
| OpaqueSettings response; |
| ClientContext context; |
| removeFile(kConfiguredFilepath); |
| grpc::Status status = |
| biossettings_stub_->GetSettings(&context, request, &response); |
| EXPECT_EQ(status.error_code(), grpc::StatusCode::NOT_FOUND); |
| } |
| |
| TEST_F(BiosSettingsTest, GetSettingsReturnsValidSettings) { |
| std::error_code ec; |
| // Create the directories recursively |
| std::filesystem::create_directories("/tmp/var/google/bios"); |
| |
| std::ofstream out(kConfiguredFilepath); |
| out << "test_content"; |
| out.close(); |
| |
| Empty request; |
| OpaqueSettings response; |
| ClientContext context; |
| |
| grpc::Status status = |
| biossettings_stub_->GetSettings(&context, request, &response); |
| EXPECT_OK(status); |
| EXPECT_EQ(response.content(), "test_content"); |
| removeFile(kConfiguredFilepath); |
| } |
| |
| TEST_F(BiosSettingsTest, ReportSettings) { |
| std::filesystem::remove_all("/tmp/var/google/bios"); |
| |
| OpaqueSettings request; |
| Empty response; |
| ClientContext context; |
| request.set_content("test_status"); |
| grpc::Status status = |
| biossettings_stub_->ReportSettings(&context, request, &response); |
| EXPECT_OK(status); |
| |
| std::ifstream ifs(kReportedFilepath); |
| std::string errorMessage; |
| ASSERT_TRUE(ifs.is_open()) << "Failed to open " << kReportedFilepath; |
| std::stringstream buffer; |
| buffer << ifs.rdbuf(); |
| std::string content = buffer.str(); |
| |
| EXPECT_EQ(content, "test_status"); |
| |
| std::filesystem::file_time_type last_write_time = |
| std::filesystem::last_write_time(kReportedFilepath); |
| |
| // Sleep for 1 second so the last write time is measurable. |
| std::this_thread::sleep_for(std::chrono::milliseconds(1000)); |
| |
| // Report the same settings again |
| ClientContext context2; |
| request.set_content("test_status"); |
| status = biossettings_stub_->ReportSettings(&context2, request, &response); |
| EXPECT_OK(status); |
| |
| EXPECT_EQ(last_write_time, |
| std::filesystem::last_write_time(kReportedFilepath)) |
| << "File should not be updated if the same settings are reported."; |
| |
| removeFile(kReportedFilepath); |
| } |
| |
| TEST_F(BiosSettingsTest, GetSettingsOnMultiHost) { |
| std::filesystem::create_directories("/tmp/var/google/bios"); |
| |
| // Port 10167: (insecure gRPC instance 0), CN 0 of multi-CN system |
| // Port 10168: (insecure gRPC instance 1), CN 1 of multi-CN system |
| // Port 10166: (insecure gRPC instance 2), single CN system, covered in the |
| // default case |
| std::unordered_map<int, int> instance_to_stub_map{{0, 10167}, {1, 10168}}; |
| for (const auto& [instance, port] : instance_to_stub_map) { |
| std::shared_ptr<Channel> channel = |
| grpc::CreateChannel("localhost:" + std::to_string(port), |
| grpc::InsecureChannelCredentials()); |
| std::unique_ptr<BiosSettingsService::Stub> cn_stub = |
| BiosSettingsService::NewStub(channel); |
| std::ofstream out(kConfiguredFilepath + "_" + std::to_string(instance)); |
| std::string cn_content = "settings from CN " + std::to_string(instance); |
| out << cn_content; |
| out.close(); |
| Empty request; |
| OpaqueSettings response; |
| ClientContext context; |
| grpc::Status status = cn_stub->GetSettings(&context, request, &response); |
| EXPECT_OK(status); |
| EXPECT_EQ(response.content(), cn_content); |
| } |
| std::filesystem::remove_all("/tmp/var/google/bios"); |
| } |
| |
| } // namespace |
| } // namespace blobs |