1 #include "flags.hpp"
2 #include "image_mock.hpp"
3 #include "triggerable_mock.hpp"
4 #include "util.hpp"
5 #include "version_handler.hpp"
6 
7 #include <array>
8 #include <string>
9 #include <vector>
10 
11 #include <gtest/gtest.h>
12 using ::testing::_;
13 using ::testing::IsEmpty;
14 using ::testing::Return;
15 namespace ipmi_flash
16 {
17 
18 class VersionReadBlobTest : public ::testing::Test
19 {
20   protected:
21     void SetUp() override
22     {
23         VersionInfoMap vim;
24         for (const auto& blobName : blobNames)
25         {
26             auto t = CreateTriggerMock();
27             auto i = CreateImageMock();
28             tm[blobName] = reinterpret_cast<TriggerMock*>(t.get());
29             im[blobName] = reinterpret_cast<ImageHandlerMock*>(i.get());
30             vim.try_emplace(
31                 blobName,
32                 VersionInfoPack(
33                     blobName, std::make_unique<VersionActionPack>(std::move(t)),
34                     std::move(i)));
35         }
36         h = VersionBlobHandler::create(std::move(vim));
37         ASSERT_NE(h, nullptr);
38         for (const auto& [key, val] : tm)
39         {
40             ON_CALL(*val, trigger()).WillByDefault(Return(true));
41         }
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 };
51 
52 TEST_F(VersionReadBlobTest, VerifyValidRead)
53 {
54     EXPECT_CALL(*tm.at("blob0"), status())
55         .Times(2)
56         .WillRepeatedly(Return(ActionStatus::success));
57     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
58     /* file path gets bound to file_handler on creation so path parameter
59      * doesn't actually matter
60      */
61     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in))
62         .Times(2)
63         .WillRepeatedly(Return(true));
64     EXPECT_CALL(*im.at("blob0"), read(0, 10)).WillOnce(Return(vector1));
65     EXPECT_CALL(*im.at("blob0"), read(2, 10)).WillOnce(Return(vector1));
66     EXPECT_CALL(*im.at("blob0"), close()).Times(2);
67 
68     EXPECT_EQ(h->read(defaultSessionNumber, 0, 10), vector1);
69     EXPECT_EQ(h->read(defaultSessionNumber, 2, 10), vector1);
70 }
71 
72 TEST_F(VersionReadBlobTest, VerifyUnopenedReadFails)
73 {
74     EXPECT_CALL(*tm.at("blob0"), status()).Times(0);
75     EXPECT_CALL(*im.at("blob0"), open(_, _)).Times(0);
76     EXPECT_CALL(*im.at("blob0"), read(_, _)).Times(0);
77 
78     EXPECT_THAT(h->read(defaultSessionNumber, 0, 10), IsEmpty());
79 }
80 
81 TEST_F(VersionReadBlobTest, VerifyTriggerFailureReadFails)
82 {
83     EXPECT_CALL(*tm.at("blob0"), status())
84         .Times(1)
85         .WillOnce(Return(ActionStatus::failed));
86     EXPECT_CALL(*im.at("blob0"), open(_, _)).Times(0);
87     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
88     EXPECT_THAT(h->read(defaultSessionNumber, 0, 10), IsEmpty());
89 }
90 
91 TEST_F(VersionReadBlobTest, VerifyReadFailsOnFileReadFailure)
92 {
93     EXPECT_CALL(*tm.at("blob0"), status())
94         .Times(1)
95         .WillOnce(Return(ActionStatus::success));
96     /* file path gets bound to file_handler on creation so path parameter
97      * doesn't actually matter
98      */
99     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in))
100         .Times(1)
101         .WillOnce(Return(true));
102     EXPECT_CALL(*im.at("blob0"), read(_, _))
103         .Times(1)
104         .WillOnce(Return(std::nullopt));
105     EXPECT_CALL(*im.at("blob0"), close()).Times(1);
106 
107     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
108     EXPECT_THAT(h->read(defaultSessionNumber, 0, 10), IsEmpty());
109 }
110 
111 TEST_F(VersionReadBlobTest, VerifyReadFailsOnFileOpenFailure)
112 {
113     /* first call to trigger status fails, second succeeds */
114     EXPECT_CALL(*tm.at("blob0"), status())
115         .Times(1)
116         .WillOnce(Return(ActionStatus::success));
117     /* file path gets bound to file_handler on creation so path parameter
118      * doesn't actually matter
119      */
120     EXPECT_CALL(*im.at("blob0"), open(_, std::ios::in))
121         .Times(1)
122         .WillOnce(Return(false));
123 
124     EXPECT_TRUE(h->open(defaultSessionNumber, blobs::read, "blob0"));
125     EXPECT_THAT(h->read(defaultSessionNumber, 0, 10), IsEmpty());
126 }
127 
128 } // namespace ipmi_flash
129