PEL: Create TemporaryFile class
Added support for creating temporary file
- Constructor creates the temporary file with data
- Destructor doesn't deletes file due to PEL function
related requirements.
- Provided remove function to delete the file.
Tested: Added test cases for TemporaryFile class and verified
test_openpower_pels_temporary_file OK 0.03s
Signed-off-by: Jayanth Othayoth <ojayanth@in.ibm.com>
Change-Id: I5295998d746ef1228512545f0a19faa1f94260d8
diff --git a/test/openpower-pels/meson.build b/test/openpower-pels/meson.build
index 0c7567e..ebfd608 100644
--- a/test/openpower-pels/meson.build
+++ b/test/openpower-pels/meson.build
@@ -53,6 +53,11 @@
'stream': {},
'user_data': {},
'user_header': {},
+ 'temporary_file': {
+ 'sources': [
+ '../../extensions/openpower-pels/temporary_file.cpp',
+ ],
+ },
}
# Build a common shared library for all openpower tests of all the widely
diff --git a/test/openpower-pels/temporary_file_test.cpp b/test/openpower-pels/temporary_file_test.cpp
new file mode 100644
index 0000000..4fb22cc
--- /dev/null
+++ b/test/openpower-pels/temporary_file_test.cpp
@@ -0,0 +1,353 @@
+/**
+ * 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 = std::move(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()));
+}