| /** |
| * Copyright © 2021 IBM Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "extensions/openpower-pels/temporary_file.hpp" |
| |
| #include <filesystem> |
| #include <fstream> |
| #include <string> |
| #include <utility> |
| |
| #include <gtest/gtest.h> |
| |
| using namespace openpower::pels::util; |
| namespace fs = std::filesystem; |
| |
| /** |
| * Modify the specified file so that fs::remove() can successfully delete it. |
| * |
| * Undo the modifications from an earlier call to makeFileUnRemovable(). |
| * |
| * @param path path to the file |
| */ |
| inline void makeFileRemovable(const fs::path& path) |
| { |
| // makeFileUnRemovable() creates a directory at the file path. Remove the |
| // directory and all of its contents. |
| fs::remove_all(path); |
| |
| // Rename the file back to the original path to restore its contents |
| fs::path savePath{path.native() + ".save"}; |
| fs::rename(savePath, path); |
| } |
| |
| /** |
| * Modify the specified file so that fs::remove() fails with an exception. |
| * |
| * The file will be renamed and can be restored by calling makeFileRemovable(). |
| * |
| * @param path path to the file |
| */ |
| inline void makeFileUnRemovable(const fs::path& path) |
| { |
| // Rename the file to save its contents |
| fs::path savePath{path.native() + ".save"}; |
| fs::rename(path, savePath); |
| |
| // Create a directory at the original file path |
| fs::create_directory(path); |
| |
| // Create a file within the directory. fs::remove() will throw an exception |
| // if the path is a non-empty directory. |
| std::ofstream childFile{path / "childFile"}; |
| } |
| |
| class TemporaryFileTests : public ::testing::Test |
| { |
| protected: |
| void SetUp() override |
| { |
| // Create temporary file with some data |
| std::string buf{"FFDCDATA"}; |
| uint32_t size = buf.size(); |
| tmpFile = new TemporaryFile(buf.c_str(), size); |
| |
| // Create temporary file with no data |
| std::string noData{""}; |
| tmpFileNoData = new TemporaryFile(noData.c_str(), 0); |
| } |
| |
| void TearDown() override |
| { |
| std::filesystem::remove_all(tmpFile->getPath()); |
| delete tmpFile; |
| |
| std::filesystem::remove_all(tmpFileNoData->getPath()); |
| delete tmpFileNoData; |
| } |
| |
| // temporary file with Data |
| TemporaryFile* tmpFile; |
| |
| // temporary file with no data |
| TemporaryFile* tmpFileNoData; |
| }; |
| |
| TEST_F(TemporaryFileTests, DefaultConstructor) |
| { |
| fs::path path = tmpFile->getPath(); |
| EXPECT_FALSE(path.empty()); |
| EXPECT_TRUE(fs::exists(path)); |
| EXPECT_TRUE(fs::is_regular_file(path)); |
| |
| fs::path parentDir = path.parent_path(); |
| EXPECT_EQ(parentDir, "/tmp"); |
| |
| std::string fileName = path.filename(); |
| std::string namePrefix = "phosphor-logging-"; |
| EXPECT_EQ(fileName.compare(0, namePrefix.size(), namePrefix), 0); |
| } |
| |
| TEST_F(TemporaryFileTests, DefaultConstructorNoData) |
| { |
| fs::path path = tmpFileNoData->getPath(); |
| EXPECT_FALSE(path.empty()); |
| EXPECT_TRUE(fs::exists(path)); |
| EXPECT_TRUE(fs::is_regular_file(path)); |
| |
| fs::path parentDir = path.parent_path(); |
| EXPECT_EQ(parentDir, "/tmp"); |
| |
| std::string fileName = path.filename(); |
| std::string namePrefix = "phosphor-logging-"; |
| EXPECT_EQ(fileName.compare(0, namePrefix.size(), namePrefix), 0); |
| } |
| |
| TEST_F(TemporaryFileTests, MoveConstructor) |
| { |
| // verify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to temporary file |
| fs::path path = tmpFile->getPath(); |
| |
| // Create second TemporaryFile object by moving first object |
| TemporaryFile file{std::move(*tmpFile)}; |
| |
| // Verify first object now has an empty path |
| EXPECT_TRUE(tmpFile->getPath().empty()); |
| |
| // Verify second object now owns same temporary file and file exists |
| EXPECT_EQ(file.getPath(), path); |
| EXPECT_TRUE(fs::exists(file.getPath())); |
| |
| // Delete file |
| std::filesystem::remove_all(file.getPath()); |
| } |
| |
| TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest1) |
| { |
| // Test where works: TemporaryFile object is moved |
| // verify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to first temporary file |
| fs::path path1 = tmpFile->getPath(); |
| |
| // Verify second temporary file exists |
| EXPECT_FALSE(tmpFileNoData->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFileNoData->getPath())); |
| |
| // Save path to second temporary file |
| fs::path path2 = tmpFileNoData->getPath(); |
| |
| // Verify temporary files are different |
| EXPECT_NE(path1, path2); |
| |
| // Move first object into the second |
| *tmpFileNoData = std::move(*tmpFile); |
| |
| // Verify first object now has an empty path |
| EXPECT_TRUE(tmpFile->getPath().empty()); |
| |
| // Verify second object now owns first temporary file and file exists |
| EXPECT_EQ(tmpFileNoData->getPath(), path1); |
| EXPECT_TRUE(fs::exists(path1)); |
| |
| // Verify second temporary file was deleted |
| EXPECT_FALSE(fs::exists(path2)); |
| } |
| |
| TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest2) |
| { |
| // Test where does nothing: TemporaryFile object is moved into itself |
| // Verify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to temporary file |
| fs::path path = tmpFile->getPath(); |
| |
| // Try to move object into itself; should do nothing |
| *tmpFile = static_cast<TemporaryFile&&>(*tmpFile); |
| |
| // Verify object still owns same temporary file and file exists |
| EXPECT_EQ(tmpFile->getPath(), path); |
| EXPECT_TRUE(fs::exists(path)); |
| } |
| |
| TEST_F(TemporaryFileTests, MoveAssignmentOperatorTest3) |
| { |
| // Test where fails: Cannot delete temporary file |
| // Verify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to first temporary file |
| fs::path path1 = tmpFile->getPath(); |
| |
| // Verify temporary file exists |
| EXPECT_FALSE(tmpFileNoData->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to second temporary file |
| fs::path path2 = tmpFileNoData->getPath(); |
| |
| // Verify temporary files are different |
| EXPECT_NE(path1, path2); |
| |
| // Make second temporary file unremoveable |
| makeFileUnRemovable(path2); |
| |
| try |
| { |
| // Try to move first object into the second; should throw exception |
| *tmpFileNoData = std::move(*tmpFile); |
| ADD_FAILURE() << "Should not have reached this line."; |
| } |
| catch (const std::exception& e) |
| { |
| // This is expected. Exception message will vary. |
| } |
| |
| // Verify first object has not changed and first temporary file exists |
| EXPECT_EQ(tmpFile->getPath(), path1); |
| EXPECT_TRUE(fs::exists(path1)); |
| |
| // Verify second object has not changed and second temporary file exists |
| EXPECT_EQ(tmpFileNoData->getPath(), path2); |
| EXPECT_TRUE(fs::exists(path2)); |
| |
| // Make second temporary file removeable so destructor can delete it |
| makeFileRemovable(path2); |
| } |
| |
| TEST_F(TemporaryFileTests, Destructor) |
| { |
| // Test where works: Temporary file is not deleted |
| { |
| fs::path path{}; |
| { |
| TemporaryFile file("", 0); |
| path = file.getPath(); |
| EXPECT_TRUE(fs::exists(path)); |
| } |
| EXPECT_TRUE(fs::exists(path)); |
| fs::remove(path); |
| } |
| |
| // Test where works: Temporary file was already deleted |
| { |
| fs::path path{}; |
| { |
| TemporaryFile file("", 0); |
| path = file.getPath(); |
| EXPECT_TRUE(fs::exists(path)); |
| file.remove(); |
| EXPECT_FALSE(fs::exists(path)); |
| } |
| EXPECT_FALSE(fs::exists(path)); |
| } |
| |
| // Test where fails: Cannot delete temporary file: No exception thrown |
| { |
| fs::path path{}; |
| try |
| { |
| TemporaryFile file("", 0); |
| path = file.getPath(); |
| EXPECT_TRUE(fs::exists(path)); |
| makeFileUnRemovable(path); |
| } |
| catch (...) |
| { |
| ADD_FAILURE() << "Should not have caught exception."; |
| } |
| |
| // Temporary file should still exist |
| EXPECT_TRUE(fs::exists(path)); |
| |
| // Make file removable and delete it |
| makeFileRemovable(path); |
| fs::remove(path); |
| } |
| } |
| |
| TEST_F(TemporaryFileTests, RemoveTest1) |
| { |
| // Test where works |
| // Vverify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Save path to temporary file |
| fs::path path = tmpFile->getPath(); |
| |
| // Delete temporary file |
| tmpFile->remove(); |
| |
| // Verify path is cleared and file does not exist |
| EXPECT_TRUE(tmpFile->getPath().empty()); |
| EXPECT_FALSE(fs::exists(path)); |
| |
| // Delete temporary file again; should do nothing |
| tmpFile->remove(); |
| EXPECT_TRUE(tmpFile->getPath().empty()); |
| EXPECT_FALSE(fs::exists(path)); |
| } |
| |
| TEST_F(TemporaryFileTests, RemoveTest2) |
| { |
| // Test where fails |
| // Create TemporaryFile object and verify temporary file exists |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| |
| // Make file unremovable |
| makeFileUnRemovable(tmpFile->getPath()); |
| |
| try |
| { |
| // Try to delete temporary file; should fail with exception |
| tmpFile->remove(); |
| ADD_FAILURE() << "Should not have reached this line."; |
| } |
| catch (const std::exception& e) |
| { |
| // This is expected. Exception message will vary. |
| } |
| |
| // Make file removable again so it will be deleted by the destructor |
| makeFileRemovable(tmpFile->getPath()); |
| } |
| |
| TEST_F(TemporaryFileTests, GetPath) |
| { |
| EXPECT_FALSE(tmpFile->getPath().empty()); |
| EXPECT_EQ(tmpFile->getPath().parent_path(), "/tmp"); |
| EXPECT_TRUE(fs::exists(tmpFile->getPath())); |
| } |