xref: /openbmc/phosphor-logging/test/openpower-pels/temporary_file_test.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2021 IBM Corporation
3 
4 #include "extensions/openpower-pels/temporary_file.hpp"
5 
6 #include <filesystem>
7 #include <fstream>
8 #include <string>
9 #include <utility>
10 
11 #include <gtest/gtest.h>
12 
13 using namespace openpower::pels::util;
14 namespace fs = std::filesystem;
15 
16 /**
17  * Modify the specified file so that fs::remove() can successfully delete it.
18  *
19  * Undo the modifications from an earlier call to makeFileUnRemovable().
20  *
21  * @param path path to the file
22  */
makeFileRemovable(const fs::path & path)23 inline void makeFileRemovable(const fs::path& path)
24 {
25     // makeFileUnRemovable() creates a directory at the file path.  Remove the
26     // directory and all of its contents.
27     fs::remove_all(path);
28 
29     // Rename the file back to the original path to restore its contents
30     fs::path savePath{path.native() + ".save"};
31     fs::rename(savePath, path);
32 }
33 
34 /**
35  * Modify the specified file so that fs::remove() fails with an exception.
36  *
37  * The file will be renamed and can be restored by calling makeFileRemovable().
38  *
39  * @param path path to the file
40  */
makeFileUnRemovable(const fs::path & path)41 inline void makeFileUnRemovable(const fs::path& path)
42 {
43     // Rename the file to save its contents
44     fs::path savePath{path.native() + ".save"};
45     fs::rename(path, savePath);
46 
47     // Create a directory at the original file path
48     fs::create_directory(path);
49 
50     // Create a file within the directory.  fs::remove() will throw an exception
51     // if the path is a non-empty directory.
52     std::ofstream childFile{path / "childFile"};
53 }
54 
55 class TemporaryFileTests : public ::testing::Test
56 {
57   protected:
SetUp()58     void SetUp() override
59     {
60         // Create temporary file with some data
61         std::string buf{"FFDCDATA"};
62         uint32_t size = buf.size();
63         tmpFile = new TemporaryFile(buf.c_str(), size);
64 
65         // Create temporary file with no data
66         std::string noData{""};
67         tmpFileNoData = new TemporaryFile(noData.c_str(), 0);
68     }
69 
TearDown()70     void TearDown() override
71     {
72         std::filesystem::remove_all(tmpFile->getPath());
73         delete tmpFile;
74 
75         std::filesystem::remove_all(tmpFileNoData->getPath());
76         delete tmpFileNoData;
77     }
78 
79     // temporary file with Data
80     TemporaryFile* tmpFile;
81 
82     // temporary file with no data
83     TemporaryFile* tmpFileNoData;
84 };
85 
TEST_F(TemporaryFileTests,DefaultConstructor)86 TEST_F(TemporaryFileTests, DefaultConstructor)
87 {
88     fs::path path = tmpFile->getPath();
89     EXPECT_FALSE(path.empty());
90     EXPECT_TRUE(fs::exists(path));
91     EXPECT_TRUE(fs::is_regular_file(path));
92 
93     fs::path parentDir = path.parent_path();
94     EXPECT_EQ(parentDir, "/tmp");
95 
96     std::string fileName = path.filename();
97     std::string namePrefix = "phosphor-logging-";
98     EXPECT_EQ(fileName.compare(0, namePrefix.size(), namePrefix), 0);
99 }
100 
TEST_F(TemporaryFileTests,DefaultConstructorNoData)101 TEST_F(TemporaryFileTests, DefaultConstructorNoData)
102 {
103     fs::path path = tmpFileNoData->getPath();
104     EXPECT_FALSE(path.empty());
105     EXPECT_TRUE(fs::exists(path));
106     EXPECT_TRUE(fs::is_regular_file(path));
107 
108     fs::path parentDir = path.parent_path();
109     EXPECT_EQ(parentDir, "/tmp");
110 
111     std::string fileName = path.filename();
112     std::string namePrefix = "phosphor-logging-";
113     EXPECT_EQ(fileName.compare(0, namePrefix.size(), namePrefix), 0);
114 }
115 
TEST_F(TemporaryFileTests,MoveConstructor)116 TEST_F(TemporaryFileTests, MoveConstructor)
117 {
118     // verify temporary file exists
119     EXPECT_FALSE(tmpFile->getPath().empty());
120     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
121 
122     // Save path to temporary file
123     fs::path path = tmpFile->getPath();
124 
125     // Create second TemporaryFile object by moving first object
126     TemporaryFile file{std::move(*tmpFile)};
127 
128     // Verify first object now has an empty path
129     EXPECT_TRUE(tmpFile->getPath().empty());
130 
131     // Verify second object now owns same temporary file and file exists
132     EXPECT_EQ(file.getPath(), path);
133     EXPECT_TRUE(fs::exists(file.getPath()));
134 
135     // Delete file
136     std::filesystem::remove_all(file.getPath());
137 }
138 
TEST_F(TemporaryFileTests,MoveAssignmentOperatorTest1)139 TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest1)
140 {
141     // Test where works: TemporaryFile object is moved
142     // verify temporary file exists
143     EXPECT_FALSE(tmpFile->getPath().empty());
144     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
145 
146     // Save path to first temporary file
147     fs::path path1 = tmpFile->getPath();
148 
149     // Verify second temporary file exists
150     EXPECT_FALSE(tmpFileNoData->getPath().empty());
151     EXPECT_TRUE(fs::exists(tmpFileNoData->getPath()));
152 
153     // Save path to second temporary file
154     fs::path path2 = tmpFileNoData->getPath();
155 
156     // Verify temporary files are different
157     EXPECT_NE(path1, path2);
158 
159     // Move first object into the second
160     *tmpFileNoData = std::move(*tmpFile);
161 
162     // Verify first object now has an empty path
163     EXPECT_TRUE(tmpFile->getPath().empty());
164 
165     // Verify second object now owns first temporary file and file exists
166     EXPECT_EQ(tmpFileNoData->getPath(), path1);
167     EXPECT_TRUE(fs::exists(path1));
168 
169     // Verify second temporary file was deleted
170     EXPECT_FALSE(fs::exists(path2));
171 }
172 
TEST_F(TemporaryFileTests,MoveAssignmentOperatorTest2)173 TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest2)
174 {
175     // Test where does nothing: TemporaryFile object is moved into itself
176     // Verify temporary file exists
177     EXPECT_FALSE(tmpFile->getPath().empty());
178     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
179 
180     // Save path to temporary file
181     fs::path path = tmpFile->getPath();
182 
183     // Try to move object into itself; should do nothing
184     *tmpFile = static_cast<TemporaryFile&&>(*tmpFile);
185 
186     // Verify object still owns same temporary file and file exists
187     EXPECT_EQ(tmpFile->getPath(), path);
188     EXPECT_TRUE(fs::exists(path));
189 }
190 
TEST_F(TemporaryFileTests,MoveAssignmentOperatorTest3)191 TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest3)
192 {
193     // Test where fails: Cannot delete temporary file
194     // Verify temporary file exists
195     EXPECT_FALSE(tmpFile->getPath().empty());
196     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
197 
198     // Save path to first temporary file
199     fs::path path1 = tmpFile->getPath();
200 
201     // Verify temporary file exists
202     EXPECT_FALSE(tmpFileNoData->getPath().empty());
203     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
204 
205     // Save path to second temporary file
206     fs::path path2 = tmpFileNoData->getPath();
207 
208     // Verify temporary files are different
209     EXPECT_NE(path1, path2);
210 
211     // Make second temporary file unremoveable
212     makeFileUnRemovable(path2);
213 
214     try
215     {
216         // Try to move first object into the second; should throw exception
217         *tmpFileNoData = std::move(*tmpFile);
218         ADD_FAILURE() << "Should not have reached this line.";
219     }
220     catch (const std::exception& e)
221     {
222         // This is expected.  Exception message will vary.
223     }
224 
225     // Verify first object has not changed and first temporary file exists
226     EXPECT_EQ(tmpFile->getPath(), path1);
227     EXPECT_TRUE(fs::exists(path1));
228 
229     // Verify second object has not changed and second temporary file exists
230     EXPECT_EQ(tmpFileNoData->getPath(), path2);
231     EXPECT_TRUE(fs::exists(path2));
232 
233     // Make second temporary file removeable so destructor can delete it
234     makeFileRemovable(path2);
235 }
236 
TEST_F(TemporaryFileTests,Destructor)237 TEST_F(TemporaryFileTests, Destructor)
238 {
239     // Test where works: Temporary file is not deleted
240     {
241         fs::path path{};
242         {
243             TemporaryFile file("", 0);
244             path = file.getPath();
245             EXPECT_TRUE(fs::exists(path));
246         }
247         EXPECT_TRUE(fs::exists(path));
248         fs::remove(path);
249     }
250 
251     // Test where works: Temporary file was already deleted
252     {
253         fs::path path{};
254         {
255             TemporaryFile file("", 0);
256             path = file.getPath();
257             EXPECT_TRUE(fs::exists(path));
258             file.remove();
259             EXPECT_FALSE(fs::exists(path));
260         }
261         EXPECT_FALSE(fs::exists(path));
262     }
263 
264     // Test where fails: Cannot delete temporary file: No exception thrown
265     {
266         fs::path path{};
267         try
268         {
269             TemporaryFile file("", 0);
270             path = file.getPath();
271             EXPECT_TRUE(fs::exists(path));
272             makeFileUnRemovable(path);
273         }
274         catch (...)
275         {
276             ADD_FAILURE() << "Should not have caught exception.";
277         }
278 
279         // Temporary file should still exist
280         EXPECT_TRUE(fs::exists(path));
281 
282         // Make file removable and delete it
283         makeFileRemovable(path);
284         fs::remove(path);
285     }
286 }
287 
TEST_F(TemporaryFileTests,RemoveTest1)288 TEST_F(TemporaryFileTests, RemoveTest1)
289 {
290     // Test where works
291     // Vverify temporary file exists
292     EXPECT_FALSE(tmpFile->getPath().empty());
293     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
294 
295     // Save path to temporary file
296     fs::path path = tmpFile->getPath();
297 
298     // Delete temporary file
299     tmpFile->remove();
300 
301     // Verify path is cleared and file does not exist
302     EXPECT_TRUE(tmpFile->getPath().empty());
303     EXPECT_FALSE(fs::exists(path));
304 
305     // Delete temporary file again; should do nothing
306     tmpFile->remove();
307     EXPECT_TRUE(tmpFile->getPath().empty());
308     EXPECT_FALSE(fs::exists(path));
309 }
310 
TEST_F(TemporaryFileTests,RemoveTest2)311 TEST_F(TemporaryFileTests, RemoveTest2)
312 {
313     // Test where fails
314     // Create TemporaryFile object and verify temporary file exists
315     EXPECT_FALSE(tmpFile->getPath().empty());
316     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
317 
318     // Make file unremovable
319     makeFileUnRemovable(tmpFile->getPath());
320 
321     try
322     {
323         // Try to delete temporary file; should fail with exception
324         tmpFile->remove();
325         ADD_FAILURE() << "Should not have reached this line.";
326     }
327     catch (const std::exception& e)
328     {
329         // This is expected.  Exception message will vary.
330     }
331 
332     // Make file removable again so it will be deleted by the destructor
333     makeFileRemovable(tmpFile->getPath());
334 }
335 
TEST_F(TemporaryFileTests,GetPath)336 TEST_F(TemporaryFileTests, GetPath)
337 {
338     EXPECT_FALSE(tmpFile->getPath().empty());
339     EXPECT_EQ(tmpFile->getPath().parent_path(), "/tmp");
340     EXPECT_TRUE(fs::exists(tmpFile->getPath()));
341 }
342