1 // Copyright 2021 Google Inc.
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 "log_handler.hpp"
16 #include "log_mock.hpp"
17 
18 #include <memory>
19 #include <string>
20 #include <string_view>
21 #include <vector>
22 
23 #include <gtest/gtest.h>
24 
25 using ::testing::_;
26 using ::testing::DoAll;
27 using ::testing::ElementsAreArray;
28 using ::testing::Ge;
29 using ::testing::IsEmpty;
30 using ::testing::Return;
31 
32 namespace ipmi_flash
33 {
34 
35 class LogReadBlobTest : public ::testing::Test
36 {
37   protected:
SetUp()38     void SetUp() override
39     {
40         h = std::make_unique<LogBlobHandler>(
41             createMockLogConfigs(blobNames, &im, &tm));
42     }
43     std::unique_ptr<blobs::GenericBlobInterface> h;
44     std::vector<std::string> blobNames{"blob0", "blob1", "blob2", "blob3"};
45     std::unordered_map<std::string, TriggerMock*> tm;
46     std::unordered_map<std::string, ImageHandlerMock*> im;
47     const std::uint16_t defaultSessionNumber{200};
48     std::vector<uint8_t> vector1{0xDE, 0xAD, 0xBE, 0xEF,
49                                  0xBA, 0xDF, 0xEE, 0x0D};
50     std::vector<uint8_t> vector2{0xCE, 0xAD, 0xDE, 0xFF};
51 };
52 
TEST_F(LogReadBlobTest,VerifyValidRead)53 TEST_F(LogReadBlobTest, VerifyValidRead)
54 {
55     testing::InSequence seq;
56     EXPECT_CALL(*tm.at("blob0"), trigger())
57         .WillOnce(DoAll([&]() { tm.at("blob0")->cb(*tm.at("blob0")); },
58                         Return(true)));
59     EXPECT_CALL(*tm.at("blob0"), status())
60         .WillOnce(Return(ActionStatus::success));
61     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in)).WillOnce(Return(true));
62     EXPECT_CALL(*im.at("blob0"), read(0, Ge(vector1.size())))
63         .WillOnce(Return(vector1));
64     EXPECT_CALL(*im.at("blob0"), close()).Times(1);
65     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
66 
67     std::basic_string_view<uint8_t> vectorS(vector1.data(), vector1.size());
68     EXPECT_THAT(h->read(defaultSessionNumber, 0, 7),
69                 ElementsAreArray(vectorS.substr(0, 7)));
70     EXPECT_THAT(h->read(defaultSessionNumber, 2, 10),
71                 ElementsAreArray(vectorS.substr(2, 6)));
72     EXPECT_THAT(h->read(defaultSessionNumber, 10, 0), IsEmpty());
73 }
74 
TEST_F(LogReadBlobTest,VerifyMultipleSession)75 TEST_F(LogReadBlobTest, VerifyMultipleSession)
76 {
77     testing::InSequence seq;
78     EXPECT_CALL(*tm.at("blob0"), trigger()).WillOnce(Return(true));
79     EXPECT_TRUE(h->open(0, blobs::read, "blob0"));
80     EXPECT_TRUE(h->open(1, blobs::read, "blob0"));
81 
82     EXPECT_CALL(*tm.at("blob0"), status())
83         .WillOnce(Return(ActionStatus::success));
84     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in)).WillOnce(Return(true));
85     EXPECT_CALL(*im.at("blob0"), read(0, Ge(vector1.size())))
86         .WillOnce(Return(vector1));
87     EXPECT_CALL(*im.at("blob0"), close()).Times(1);
88     tm.at("blob0")->cb(*tm.at("blob0"));
89 
90     EXPECT_CALL(*tm.at("blob0"), trigger()).WillOnce(Return(true));
91     EXPECT_TRUE(h->open(2, blobs::read, "blob0"));
92 
93     EXPECT_CALL(*tm.at("blob0"), status())
94         .WillOnce(Return(ActionStatus::success));
95     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in)).WillOnce(Return(true));
96     EXPECT_CALL(*im.at("blob0"), read(0, Ge(vector2.size())))
97         .WillOnce(Return(vector2));
98     EXPECT_CALL(*im.at("blob0"), close()).Times(1);
99     tm.at("blob0")->cb(*tm.at("blob0"));
100 
101     EXPECT_THAT(h->read(0, 0, 10), ElementsAreArray(vector1));
102     EXPECT_THAT(h->read(1, 0, 10), ElementsAreArray(vector1));
103     EXPECT_THAT(h->read(2, 0, 10), ElementsAreArray(vector2));
104 }
105 
TEST_F(LogReadBlobTest,VerifyReadEarlyFails)106 TEST_F(LogReadBlobTest, VerifyReadEarlyFails)
107 {
108     EXPECT_CALL(*tm.at("blob0"), trigger()).WillOnce(Return(true));
109 
110     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
111     EXPECT_THROW(h->read(defaultSessionNumber, 0, 10), std::runtime_error);
112 }
113 
TEST_F(LogReadBlobTest,VerifyTriggerFailureReadFails)114 TEST_F(LogReadBlobTest, VerifyTriggerFailureReadFails)
115 {
116     EXPECT_CALL(*tm.at("blob0"), trigger())
117         .WillOnce(DoAll([&]() { tm.at("blob0")->cb(*tm.at("blob0")); },
118                         Return(true)));
119     EXPECT_CALL(*tm.at("blob0"), status())
120         .WillOnce(Return(ActionStatus::failed));
121     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
122     EXPECT_THROW(h->read(defaultSessionNumber, 0, 10), std::runtime_error);
123 }
124 
TEST_F(LogReadBlobTest,VerifyReadFailsOnFileOpenFailure)125 TEST_F(LogReadBlobTest, VerifyReadFailsOnFileOpenFailure)
126 {
127     EXPECT_CALL(*tm.at("blob0"), trigger())
128         .WillOnce(DoAll([&]() { tm.at("blob0")->cb(*tm.at("blob0")); },
129                         Return(true)));
130     EXPECT_CALL(*tm.at("blob0"), status())
131         .WillOnce(Return(ActionStatus::success));
132     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in)).WillOnce(Return(false));
133 
134     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
135     EXPECT_THROW(h->read(defaultSessionNumber, 0, 10), std::runtime_error);
136 }
137 
TEST_F(LogReadBlobTest,VerifyReadFailsOnFileReadFailure)138 TEST_F(LogReadBlobTest, VerifyReadFailsOnFileReadFailure)
139 {
140     EXPECT_CALL(*tm.at("blob0"), trigger())
141         .WillOnce(DoAll([&]() { tm.at("blob0")->cb(*tm.at("blob0")); },
142                         Return(true)));
143     EXPECT_CALL(*tm.at("blob0"), status())
144         .WillOnce(Return(ActionStatus::success));
145     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in)).WillOnce(Return(true));
146     EXPECT_CALL(*im.at("blob0"), read(_, _)).WillOnce(Return(std::nullopt));
147     EXPECT_CALL(*im.at("blob0"), close()).Times(1);
148 
149     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
150     EXPECT_THROW(h->read(defaultSessionNumber, 0, 10), std::runtime_error);
151 }
152 
153 } // namespace ipmi_flash
154