193a4c0abSBrandon Kim // Copyright 2024 Google LLC
293a4c0abSBrandon Kim //
393a4c0abSBrandon Kim // Licensed under the Apache License, Version 2.0 (the "License");
493a4c0abSBrandon Kim // you may not use this file except in compliance with the License.
593a4c0abSBrandon Kim // You may obtain a copy of the License at
693a4c0abSBrandon Kim //
793a4c0abSBrandon Kim //      http://www.apache.org/licenses/LICENSE-2.0
893a4c0abSBrandon Kim //
993a4c0abSBrandon Kim // Unless required by applicable law or agreed to in writing, software
1093a4c0abSBrandon Kim // distributed under the License is distributed on an "AS IS" BASIS,
1193a4c0abSBrandon Kim // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1293a4c0abSBrandon Kim // See the License for the specific language governing permissions and
1393a4c0abSBrandon Kim // limitations under the License.
1493a4c0abSBrandon Kim 
1593a4c0abSBrandon Kim #include "bios_setting.hpp"
1693a4c0abSBrandon Kim #include "commands.hpp"
1793a4c0abSBrandon Kim #include "helper.hpp"
1893a4c0abSBrandon Kim 
1993a4c0abSBrandon Kim #include <stdplus/gtest/tmp.hpp>
2093a4c0abSBrandon Kim 
2193a4c0abSBrandon Kim #include <fstream>
2293a4c0abSBrandon Kim #include <ios>
2393a4c0abSBrandon Kim #include <iostream>
2493a4c0abSBrandon Kim #include <string>
2593a4c0abSBrandon Kim #include <vector>
2693a4c0abSBrandon Kim 
2793a4c0abSBrandon Kim #include <gtest/gtest.h>
2893a4c0abSBrandon Kim 
2993a4c0abSBrandon Kim namespace google
3093a4c0abSBrandon Kim {
3193a4c0abSBrandon Kim namespace ipmi
3293a4c0abSBrandon Kim {
3393a4c0abSBrandon Kim 
3493a4c0abSBrandon Kim using testing::_;
3593a4c0abSBrandon Kim using ::testing::ElementsAre;
3693a4c0abSBrandon Kim 
3793a4c0abSBrandon Kim class BiosSettingTest : public stdplus::gtest::TestWithTmp
3893a4c0abSBrandon Kim {
3993a4c0abSBrandon Kim   public:
4093a4c0abSBrandon Kim     std::string filename = std::format("{}/oem_bios_setting", CaseTmpDir());
4193a4c0abSBrandon Kim 
writeTmpFile(std::vector<uint8_t> payload)4293a4c0abSBrandon Kim     void writeTmpFile(std::vector<uint8_t> payload)
4393a4c0abSBrandon Kim     {
4493a4c0abSBrandon Kim         std::ofstream ofs;
4593a4c0abSBrandon Kim         ofs.open(filename, std::ios::trunc | std::ios::binary);
4693a4c0abSBrandon Kim         ofs.write(reinterpret_cast<char*>(payload.data()), payload.size());
4793a4c0abSBrandon Kim         ofs.close();
4893a4c0abSBrandon Kim     }
4993a4c0abSBrandon Kim };
5093a4c0abSBrandon Kim 
TEST_F(BiosSettingTest,NoOrEmptyFileRead)5193a4c0abSBrandon Kim TEST_F(BiosSettingTest, NoOrEmptyFileRead)
5293a4c0abSBrandon Kim {
5393a4c0abSBrandon Kim     std::vector<uint8_t> request = {};
5493a4c0abSBrandon Kim 
5593a4c0abSBrandon Kim     HandlerMock hMock;
5693a4c0abSBrandon Kim     EXPECT_EQ(::ipmi::responseRetBytesUnavailable(),
5793a4c0abSBrandon Kim               readBiosSetting(request, &hMock));
5893a4c0abSBrandon Kim 
5993a4c0abSBrandon Kim     // Create an empty file
6093a4c0abSBrandon Kim     writeTmpFile({});
6193a4c0abSBrandon Kim     EXPECT_EQ(::ipmi::responseRetBytesUnavailable(),
6293a4c0abSBrandon Kim               readBiosSetting(request, &hMock, filename));
6393a4c0abSBrandon Kim     std::remove(filename.c_str());
6493a4c0abSBrandon Kim }
6593a4c0abSBrandon Kim 
TEST_F(BiosSettingTest,SuccessfulRead)6693a4c0abSBrandon Kim TEST_F(BiosSettingTest, SuccessfulRead)
6793a4c0abSBrandon Kim {
6893a4c0abSBrandon Kim     std::vector<uint8_t> request = {};
6993a4c0abSBrandon Kim     // Ensure 0x0A which is a new line character '\n', is read properly
7093a4c0abSBrandon Kim     std::vector<uint8_t> payload = {0x0A, 0xDE, 0xAD, 0xBE, 0xEF, 0x0A};
7193a4c0abSBrandon Kim     std::vector<uint8_t> expectedReply = {6,    0x0A, 0xDE, 0xAD,
7293a4c0abSBrandon Kim                                           0xBE, 0xEF, 0x0A};
7393a4c0abSBrandon Kim 
7493a4c0abSBrandon Kim     writeTmpFile(payload);
7593a4c0abSBrandon Kim 
7693a4c0abSBrandon Kim     HandlerMock hMock;
7793a4c0abSBrandon Kim     auto reply = readBiosSetting(request, &hMock, filename);
7893a4c0abSBrandon Kim     auto result = ValidateReply(reply);
7993a4c0abSBrandon Kim     auto& data = result.second;
8093a4c0abSBrandon Kim 
8193a4c0abSBrandon Kim     EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
8293a4c0abSBrandon Kim     EXPECT_EQ(expectedReply.size() - 1, data.front());
8393a4c0abSBrandon Kim     EXPECT_EQ(expectedReply, data);
8493a4c0abSBrandon Kim     std::remove(filename.c_str());
8593a4c0abSBrandon Kim }
8693a4c0abSBrandon Kim 
TEST_F(BiosSettingTest,InvalidRequestWrite)87*e8929699SBrandon Kim TEST_F(BiosSettingTest, InvalidRequestWrite)
88*e8929699SBrandon Kim {
89*e8929699SBrandon Kim     // Empty request
90*e8929699SBrandon Kim     std::vector<uint8_t> request = {};
91*e8929699SBrandon Kim 
92*e8929699SBrandon Kim     HandlerMock hMock;
93*e8929699SBrandon Kim     EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
94*e8929699SBrandon Kim               writeBiosSetting(request, &hMock));
95*e8929699SBrandon Kim 
96*e8929699SBrandon Kim     // Request with payload size 1 but no payload
97*e8929699SBrandon Kim     request = {0x01};
98*e8929699SBrandon Kim     EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
99*e8929699SBrandon Kim               writeBiosSetting(request, &hMock));
100*e8929699SBrandon Kim 
101*e8929699SBrandon Kim     // Request with payload size 1 but actual payload size of 2 bytes
102*e8929699SBrandon Kim     request = {0x01, 0x02, 0x03};
103*e8929699SBrandon Kim     EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
104*e8929699SBrandon Kim               writeBiosSetting(request, &hMock));
105*e8929699SBrandon Kim 
106*e8929699SBrandon Kim     // Request with payload size 2 but actual payload of 1 byte
107*e8929699SBrandon Kim     request = {0x02, 0x02};
108*e8929699SBrandon Kim     EXPECT_EQ(::ipmi::responseReqDataLenInvalid(),
109*e8929699SBrandon Kim               writeBiosSetting(request, &hMock));
110*e8929699SBrandon Kim }
111*e8929699SBrandon Kim 
TEST_F(BiosSettingTest,SuccessfulWrite)112*e8929699SBrandon Kim TEST_F(BiosSettingTest, SuccessfulWrite)
113*e8929699SBrandon Kim {
114*e8929699SBrandon Kim     std::vector<uint8_t> request = {0x02, 0xDE, 0xAD};
115*e8929699SBrandon Kim 
116*e8929699SBrandon Kim     // Write a dummy file to get around permission issues with CI
117*e8929699SBrandon Kim     // (Not needed in local CI)
118*e8929699SBrandon Kim     writeTmpFile({});
119*e8929699SBrandon Kim     HandlerMock hMock;
120*e8929699SBrandon Kim     auto reply = writeBiosSetting(request, &hMock, filename);
121*e8929699SBrandon Kim     auto result = ValidateReply(reply);
122*e8929699SBrandon Kim     auto& data = result.second;
123*e8929699SBrandon Kim 
124*e8929699SBrandon Kim     EXPECT_EQ(SysOEMCommands::SysWriteBiosSetting, result.first);
125*e8929699SBrandon Kim     EXPECT_EQ(std::vector<uint8_t>{2}, data);
126*e8929699SBrandon Kim 
127*e8929699SBrandon Kim     // Validate the payload is correct
128*e8929699SBrandon Kim     reply = readBiosSetting(request, &hMock, filename);
129*e8929699SBrandon Kim     result = ValidateReply(reply);
130*e8929699SBrandon Kim     data = result.second;
131*e8929699SBrandon Kim 
132*e8929699SBrandon Kim     EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
133*e8929699SBrandon Kim     EXPECT_EQ(request.size() - 1, data.front());
134*e8929699SBrandon Kim     EXPECT_EQ(request, data);
135*e8929699SBrandon Kim 
136*e8929699SBrandon Kim     // Verify that we can write a shorter string and it'll replace the original
137*e8929699SBrandon Kim     // content of the file
138*e8929699SBrandon Kim     request = {0x01, 0x0A};
139*e8929699SBrandon Kim 
140*e8929699SBrandon Kim     reply = writeBiosSetting(request, &hMock, filename);
141*e8929699SBrandon Kim     result = ValidateReply(reply);
142*e8929699SBrandon Kim     data = result.second;
143*e8929699SBrandon Kim 
144*e8929699SBrandon Kim     EXPECT_EQ(SysOEMCommands::SysWriteBiosSetting, result.first);
145*e8929699SBrandon Kim     EXPECT_EQ(std::vector<uint8_t>{1}, data);
146*e8929699SBrandon Kim 
147*e8929699SBrandon Kim     // Validate the payload is correct
148*e8929699SBrandon Kim     reply = readBiosSetting(request, &hMock, filename);
149*e8929699SBrandon Kim     result = ValidateReply(reply);
150*e8929699SBrandon Kim     data = result.second;
151*e8929699SBrandon Kim 
152*e8929699SBrandon Kim     EXPECT_EQ(SysOEMCommands::SysReadBiosSetting, result.first);
153*e8929699SBrandon Kim     EXPECT_EQ(request.size() - 1, data.front());
154*e8929699SBrandon Kim     EXPECT_EQ(request, data);
155*e8929699SBrandon Kim     // Cleanup the settings file
156*e8929699SBrandon Kim     std::remove(filename.c_str());
157*e8929699SBrandon Kim }
158*e8929699SBrandon Kim 
15993a4c0abSBrandon Kim } // namespace ipmi
16093a4c0abSBrandon Kim } // namespace google
161