1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "bios_setting.hpp"
16 #include "commands.hpp"
17 #include "helper.hpp"
18
19 #include <stdplus/gtest/tmp.hpp>
20
21 #include <fstream>
22 #include <ios>
23 #include <iostream>
24 #include <string>
25 #include <vector>
26
27 #include <gtest/gtest.h>
28
29 namespace google
30 {
31 namespace ipmi
32 {
33
34 using testing::_;
35 using ::testing::ElementsAre;
36
37 class BiosSettingTest : public stdplus::gtest::TestWithTmp
38 {
39 public:
40 std::string filename = std::format("{}/oem_bios_setting", CaseTmpDir());
41
writeTmpFile(std::vector<uint8_t> payload)42 void writeTmpFile(std::vector<uint8_t> payload)
43 {
44 std::ofstream ofs;
45 ofs.open(filename, std::ios::trunc | std::ios::binary);
46 ofs.write(reinterpret_cast<char*>(payload.data()), payload.size());
47 ofs.close();
48 }
49 };
50
TEST_F(BiosSettingTest,NoOrEmptyFileRead)51 TEST_F(BiosSettingTest, NoOrEmptyFileRead)
52 {
53 std::vector<uint8_t> request = {};
54
55 HandlerMock hMock;
56 EXPECT_EQ(::ipmi::responseRetBytesUnavailable(),
57 readBiosSetting(request, &hMock));
58
59 // Create an empty file
60 writeTmpFile({});
61 EXPECT_EQ(::ipmi::responseRetBytesUnavailable(),
62 readBiosSetting(request, &hMock, filename));
63 std::remove(filename.c_str());
64 }
65
TEST_F(BiosSettingTest,SuccessfulRead)66 TEST_F(BiosSettingTest, SuccessfulRead)
67 {
68 std::vector<uint8_t> request = {};
69 // Ensure 0x0A which is a new line character '\n', is read properly
70 std::vector<uint8_t> payload = {0x0A, 0xDE, 0xAD, 0xBE, 0xEF, 0x0A};
71 std::vector<uint8_t> expectedReply = {6, 0x0A, 0xDE, 0xAD,
72 0xBE, 0xEF, 0x0A};
73
74 writeTmpFile(payload);
75
76 HandlerMock hMock;
77 auto reply = readBiosSetting(request, &hMock, filename);
78 auto result = ValidateReply(reply);
79 auto& data = result.second;
80
81 EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
82 EXPECT_EQ(expectedReply.size() - 1, data.front());
83 EXPECT_EQ(expectedReply, data);
84 std::remove(filename.c_str());
85 }
86
TEST_F(BiosSettingTest,InvalidRequestWrite)87 TEST_F(BiosSettingTest, InvalidRequestWrite)
88 {
89 // Empty request
90 std::vector<uint8_t> request = {};
91
92 HandlerMock hMock;
93 EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
94 writeBiosSetting(request, &hMock));
95
96 // Request with payload size 1 but no payload
97 request = {0x01};
98 EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
99 writeBiosSetting(request, &hMock));
100
101 // Request with payload size 1 but actual payload size of 2 bytes
102 request = {0x01, 0x02, 0x03};
103 EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
104 writeBiosSetting(request, &hMock));
105
106 // Request with payload size 2 but actual payload of 1 byte
107 request = {0x02, 0x02};
108 EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
109 writeBiosSetting(request, &hMock));
110 }
111
TEST_F(BiosSettingTest,SuccessfulWrite)112 TEST_F(BiosSettingTest, SuccessfulWrite)
113 {
114 std::vector<uint8_t> request = {0x02, 0xDE, 0xAD};
115
116 // Write a dummy file to get around permission issues with CI
117 // (Not needed in local CI)
118 writeTmpFile({});
119 HandlerMock hMock;
120 auto reply = writeBiosSetting(request, &hMock, filename);
121 auto result = ValidateReply(reply);
122 auto& data = result.second;
123
124 EXPECT_EQ(SysOEMCommands::SysWriteBiosSetting, result.first);
125 EXPECT_EQ(std::vector<uint8_t>{2}, data);
126
127 // Validate the payload is correct
128 reply = readBiosSetting(request, &hMock, filename);
129 result = ValidateReply(reply);
130 data = result.second;
131
132 EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
133 EXPECT_EQ(request.size() - 1, data.front());
134 EXPECT_EQ(request, data);
135
136 // Verify that we can write a shorter string and it'll replace the original
137 // content of the file
138 request = {0x01, 0x0A};
139
140 reply = writeBiosSetting(request, &hMock, filename);
141 result = ValidateReply(reply);
142 data = result.second;
143
144 EXPECT_EQ(SysOEMCommands::SysWriteBiosSetting, result.first);
145 EXPECT_EQ(std::vector<uint8_t>{1}, data);
146
147 // Validate the payload is correct
148 reply = readBiosSetting(request, &hMock, filename);
149 result = ValidateReply(reply);
150 data = result.second;
151
152 EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
153 EXPECT_EQ(request.size() - 1, data.front());
154 EXPECT_EQ(request, data);
155 // Cleanup the settings file
156 std::remove(filename.c_str());
157 }
158
159 } // namespace ipmi
160 } // namespace google
161