blob: 425700a840c0d27f324ba1affcefa355d15c4600 [file] [log] [blame]
/**
* 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()));
}