1 #include "helpers.hpp"
2 #include "persistent_json_storage.hpp"
3 
4 #include <fstream>
5 
6 #include "gmock/gmock.h"
7 #include "gtest/gtest.h"
8 
9 using namespace testing;
10 
11 class TestPersistentJsonStorage : public Test
12 {
13   public:
14     using FilePath = interfaces::JsonStorage::FilePath;
15     using DirectoryPath = interfaces::JsonStorage::DirectoryPath;
16 
SetUpTestSuite()17     static void SetUpTestSuite()
18     {
19         ASSERT_FALSE(std::filesystem::exists(directory));
20     }
21 
TearDown()22     void TearDown() override
23     {
24         if (std::filesystem::exists(directory))
25         {
26             std::filesystem::remove_all(directory);
27         }
28     }
29 
30     const FilePath fileName = FilePath("report/1/file.txt");
31 
32     static const DirectoryPath directory;
33     PersistentJsonStorage sut{directory};
34 };
35 
36 const interfaces::JsonStorage::DirectoryPath
37     TestPersistentJsonStorage::directory =
38         interfaces::JsonStorage::DirectoryPath(
39             std::filesystem::temp_directory_path() / "telemetry-tests");
40 
TEST_F(TestPersistentJsonStorage,storesJsonData)41 TEST_F(TestPersistentJsonStorage, storesJsonData)
42 {
43     nlohmann::json data = nlohmann::json::object();
44     data["name"] = "kevin";
45     data["lastname"] = "mc calister";
46 
47     sut.store(fileName, data);
48 
49     ASSERT_THAT(sut.load(fileName), Eq(data));
50 }
51 
TEST_F(TestPersistentJsonStorage,emptyListWhenNoReportsCreated)52 TEST_F(TestPersistentJsonStorage, emptyListWhenNoReportsCreated)
53 {
54     EXPECT_THAT(sut.list(), SizeIs(0u));
55 }
56 
TEST_F(TestPersistentJsonStorage,listSavedReports)57 TEST_F(TestPersistentJsonStorage, listSavedReports)
58 {
59     sut.store(FilePath("report/domain-1/name-1/conf-1.json"),
60               nlohmann::json("data-1a"));
61     sut.store(FilePath("report/domain-1/name-2/conf-1.json"),
62               nlohmann::json("data-2a"));
63     sut.store(FilePath("report/domain-1/name-2/conf-2.json"),
64               nlohmann::json("data-2b"));
65     sut.store(FilePath("report/domain-2/name-1/conf-1.json"),
66               nlohmann::json("data-3a"));
67 
68     EXPECT_THAT(
69         sut.list(),
70         UnorderedElementsAre(FilePath("report/domain-1/name-1/conf-1.json"),
71                              FilePath("report/domain-1/name-2/conf-1.json"),
72                              FilePath("report/domain-1/name-2/conf-2.json"),
73                              FilePath("report/domain-2/name-1/conf-1.json")));
74 }
75 
TEST_F(TestPersistentJsonStorage,listSavedReportsWithoutRemovedOnes)76 TEST_F(TestPersistentJsonStorage, listSavedReportsWithoutRemovedOnes)
77 {
78     sut.store(FilePath("report/domain-1/name-1/conf-1.json"),
79               nlohmann::json("data-1a"));
80     sut.store(FilePath("report/domain-1/name-2/conf-1.json"),
81               nlohmann::json("data-2a"));
82     sut.store(FilePath("report/domain-1/name-2/conf-2.json"),
83               nlohmann::json("data-2b"));
84     sut.store(FilePath("report/domain-2/name-1/conf-1.json"),
85               nlohmann::json("data-3a"));
86     sut.remove(FilePath("report/domain-1/name-1/conf-1.json"));
87     sut.remove(FilePath("report/domain-1/name-2/conf-2.json"));
88 
89     EXPECT_THAT(
90         sut.list(),
91         UnorderedElementsAre(FilePath("report/domain-1/name-2/conf-1.json"),
92                              FilePath("report/domain-2/name-1/conf-1.json")));
93 }
94 
TEST_F(TestPersistentJsonStorage,removesStoredJson)95 TEST_F(TestPersistentJsonStorage, removesStoredJson)
96 {
97     nlohmann::json data = nlohmann::json::object();
98     data["name"] = "kevin";
99     data["lastname"] = "mc calister";
100 
101     sut.store(fileName, data);
102 
103     ASSERT_THAT(sut.remove(fileName), Eq(true));
104     ASSERT_THAT(sut.load(fileName), Eq(std::nullopt));
105 }
106 
TEST_F(TestPersistentJsonStorage,returnsFalseWhenDeletingNonExistingFile)107 TEST_F(TestPersistentJsonStorage, returnsFalseWhenDeletingNonExistingFile)
108 {
109     ASSERT_THAT(sut.remove(fileName), Eq(false));
110 }
111 
TEST_F(TestPersistentJsonStorage,returnsNulloptWhenFileDoesntExist)112 TEST_F(TestPersistentJsonStorage, returnsNulloptWhenFileDoesntExist)
113 {
114     ASSERT_THAT(sut.load(fileName), Eq(std::nullopt));
115 }
116 
117 struct TestFileSymlink
118 {
119     static interfaces::JsonStorage::FilePath
setupSymlinksTestFileSymlink120         setupSymlinks(const std::filesystem::path& originalFile,
121                       const interfaces::JsonStorage::DirectoryPath& directory)
122     {
123         auto linkPath = std::filesystem::path(directory) /
124                         "report/symlink.json";
125         std::filesystem::create_directories(std::filesystem::path(directory) /
126                                             "report");
127         std::filesystem::create_symlink(originalFile, linkPath);
128         return interfaces::JsonStorage::FilePath(linkPath);
129     }
130 };
131 
132 struct TestDirectorySymlink
133 {
134     static interfaces::JsonStorage::FilePath
setupSymlinksTestDirectorySymlink135         setupSymlinks(const std::filesystem::path& originalFile,
136                       const interfaces::JsonStorage::DirectoryPath& directory)
137     {
138         auto linkPath = std::filesystem::path(directory) / "reportLink";
139         std::filesystem::create_directories(std::filesystem::path(directory) /
140                                             "report");
141         std::filesystem::create_directory_symlink(originalFile.parent_path(),
142                                                   linkPath);
143         return interfaces::JsonStorage::FilePath(linkPath /
144                                                  originalFile.filename());
145     }
146 };
147 
148 template <typename T>
149 class TestPersistentJsonStorageWithSymlink : public TestPersistentJsonStorage
150 {
151   public:
TestPersistentJsonStorageWithSymlink()152     TestPersistentJsonStorageWithSymlink()
153     {
154         std::ofstream file(dummyReportPath);
155         file << "{}";
156         file.close();
157 
158         linkPath = T::setupSymlinks(dummyReportPath, directory);
159     }
160 
SetUpTestSuite()161     static void SetUpTestSuite()
162     {
163         TestPersistentJsonStorage::SetUpTestSuite();
164         ASSERT_FALSE(std::filesystem::exists(dummyReportPath));
165     }
166 
TearDown()167     void TearDown() override
168     {
169         TestPersistentJsonStorage::TearDown();
170         if (std::filesystem::exists(dummyReportPath))
171         {
172             std::filesystem::remove(dummyReportPath);
173         }
174     }
175 
176     static const std::filesystem::path dummyReportPath;
177     interfaces::JsonStorage::FilePath linkPath;
178 };
179 
180 template <typename T>
181 const std::filesystem::path
182     TestPersistentJsonStorageWithSymlink<T>::dummyReportPath =
183         std::filesystem::temp_directory_path() / "report.json";
184 
185 using SymlinkTypes = Types<TestFileSymlink, TestDirectorySymlink>;
186 TYPED_TEST_SUITE(TestPersistentJsonStorageWithSymlink, SymlinkTypes);
187 
TYPED_TEST(TestPersistentJsonStorageWithSymlink,symlinksAreNotListed)188 TYPED_TEST(TestPersistentJsonStorageWithSymlink, symlinksAreNotListed)
189 {
190     ASSERT_THAT(TestPersistentJsonStorage::sut.list(), UnorderedElementsAre());
191 }
192 
TYPED_TEST(TestPersistentJsonStorageWithSymlink,throwsWhenStoreTargetIsSymlink)193 TYPED_TEST(TestPersistentJsonStorageWithSymlink, throwsWhenStoreTargetIsSymlink)
194 {
195     ASSERT_THROW(TestPersistentJsonStorage::sut.store(TestFixture::linkPath,
196                                                       nlohmann::json("data")),
197                  std::runtime_error);
198 
199     ASSERT_THAT(TestPersistentJsonStorage::sut.list(), UnorderedElementsAre());
200 }
201 
TYPED_TEST(TestPersistentJsonStorageWithSymlink,returnsNulloptWhenFileIsSymlink)202 TYPED_TEST(TestPersistentJsonStorageWithSymlink,
203            returnsNulloptWhenFileIsSymlink)
204 {
205     ASSERT_THAT(TestPersistentJsonStorage::sut.load(TestFixture::linkPath),
206                 Eq(std::nullopt));
207 }
208 
TYPED_TEST(TestPersistentJsonStorageWithSymlink,returnsFalseWhenTryingToDeleteSymlink)209 TYPED_TEST(TestPersistentJsonStorageWithSymlink,
210            returnsFalseWhenTryingToDeleteSymlink)
211 {
212     EXPECT_THAT(TestPersistentJsonStorage::sut.remove(TestFixture::linkPath),
213                 Eq(false));
214     EXPECT_TRUE(std::filesystem::exists(TestFixture::linkPath));
215     EXPECT_TRUE(std::filesystem::exists(TestFixture::dummyReportPath));
216 }
217