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