/** * Copyright © 2020 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 "ffdc_file.hpp" #include "test_utils.hpp" #include // for errno #include // for fcntl() #include // for memset(), size_t #include // for lseek() #include // for read(), write(), lseek(), fcntl(), close() #include #include #include using namespace phosphor::power::regulators; using namespace phosphor::power::regulators::test_utils; namespace fs = std::filesystem; /** * Returns whether the specified file descriptor is valid/open. * * @param[in] fd - File descriptor * @return true if descriptor is valid/open, false otherwise */ bool isValid(int fd) { return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF); } TEST(FFDCFileTests, Constructor) { // Test where only the FFDCFormat parameter is specified { FFDCFile file{FFDCFormat::JSON}; EXPECT_NE(file.getFileDescriptor(), -1); EXPECT_TRUE(isValid(file.getFileDescriptor())); EXPECT_EQ(file.getFormat(), FFDCFormat::JSON); EXPECT_FALSE(file.getPath().empty()); EXPECT_TRUE(fs::exists(file.getPath())); EXPECT_EQ(file.getSubType(), 0); EXPECT_EQ(file.getVersion(), 0); } // Test where all constructor parameters are specified { FFDCFile file{FFDCFormat::Custom, 2, 3}; EXPECT_NE(file.getFileDescriptor(), -1); EXPECT_TRUE(isValid(file.getFileDescriptor())); EXPECT_EQ(file.getFormat(), FFDCFormat::Custom); EXPECT_FALSE(file.getPath().empty()); EXPECT_TRUE(fs::exists(file.getPath())); EXPECT_EQ(file.getSubType(), 2); EXPECT_EQ(file.getVersion(), 3); } // Note: The case where open() fails currently needs to be tested manually } TEST(FFDCFileTests, GetFileDescriptor) { FFDCFile file{FFDCFormat::JSON}; int fd = file.getFileDescriptor(); EXPECT_NE(fd, -1); EXPECT_TRUE(isValid(fd)); // Write some data to the file char buffer[] = "This is some sample data"; size_t count = sizeof(buffer); EXPECT_EQ(write(fd, buffer, count), count); // Seek back to the beginning of the file EXPECT_EQ(lseek(fd, 0, SEEK_SET), 0); // Clear buffer memset(buffer, '\0', count); EXPECT_STREQ(buffer, ""); // Read and verify file contents EXPECT_EQ(read(fd, buffer, count), count); EXPECT_STREQ(buffer, "This is some sample data"); } TEST(FFDCFileTests, GetFormat) { // Test where 'Text' was specified { FFDCFile file{FFDCFormat::Text}; EXPECT_EQ(file.getFormat(), FFDCFormat::Text); } // Test where 'Custom' was specified { FFDCFile file{FFDCFormat::Custom, 2, 3}; EXPECT_EQ(file.getFormat(), FFDCFormat::Custom); } } TEST(FFDCFileTests, GetPath) { FFDCFile file{FFDCFormat::JSON}; EXPECT_FALSE(file.getPath().empty()); EXPECT_TRUE(fs::exists(file.getPath())); } TEST(FFDCFileTests, GetSubType) { // Test where subType was not specified { FFDCFile file{FFDCFormat::JSON}; EXPECT_EQ(file.getSubType(), 0); } // Test where subType was specified { FFDCFile file{FFDCFormat::Custom, 3, 2}; EXPECT_EQ(file.getSubType(), 3); } } TEST(FFDCFileTests, GetVersion) { // Test where version was not specified { FFDCFile file{FFDCFormat::JSON}; EXPECT_EQ(file.getVersion(), 0); } // Test where version was specified { FFDCFile file{FFDCFormat::Custom, 2, 5}; EXPECT_EQ(file.getVersion(), 5); } } TEST(FFDCFileTests, Remove) { // Test where works { FFDCFile file{FFDCFormat::JSON}; EXPECT_NE(file.getFileDescriptor(), -1); EXPECT_TRUE(isValid(file.getFileDescriptor())); EXPECT_FALSE(file.getPath().empty()); EXPECT_TRUE(fs::exists(file.getPath())); int fd = file.getFileDescriptor(); fs::path path = file.getPath(); file.remove(); EXPECT_EQ(file.getFileDescriptor(), -1); EXPECT_TRUE(file.getPath().empty()); EXPECT_FALSE(isValid(fd)); EXPECT_FALSE(fs::exists(path)); } // Test where file was already removed { FFDCFile file{FFDCFormat::JSON}; EXPECT_NE(file.getFileDescriptor(), -1); EXPECT_FALSE(file.getPath().empty()); file.remove(); EXPECT_EQ(file.getFileDescriptor(), -1); EXPECT_TRUE(file.getPath().empty()); file.remove(); EXPECT_EQ(file.getFileDescriptor(), -1); EXPECT_TRUE(file.getPath().empty()); } // Test where closing the file fails { FFDCFile file{FFDCFormat::JSON}; int fd = file.getFileDescriptor(); EXPECT_TRUE(isValid(fd)); EXPECT_EQ(close(fd), 0); EXPECT_FALSE(isValid(fd)); try { file.remove(); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::exception& e) { EXPECT_NE(std::string{e.what()}.find("Unable to close FFDC file: "), std::string::npos); } } // Test where deleting the file fails { FFDCFile file{FFDCFormat::JSON}; fs::path path = file.getPath(); EXPECT_TRUE(fs::exists(path)); makeFileUnRemovable(path); try { file.remove(); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::exception& e) { // This is expected. Exception message will vary. } makeFileRemovable(path); } }