1 /** 2 * Copyright © 2020 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 "ffdc_file.hpp" 17 #include "test_utils.hpp" 18 19 #include <errno.h> // for errno 20 #include <fcntl.h> // for fcntl() 21 #include <string.h> // for memset(), size_t 22 #include <sys/types.h> // for lseek() 23 #include <unistd.h> // for read(), write(), lseek(), fcntl(), close() 24 25 #include <exception> 26 #include <filesystem> 27 28 #include <gtest/gtest.h> 29 30 using namespace phosphor::power::regulators; 31 using namespace phosphor::power::regulators::test_utils; 32 namespace fs = std::filesystem; 33 34 /** 35 * Returns whether the specified file descriptor is valid/open. 36 * 37 * @param[in] fd - File descriptor 38 * @return true if descriptor is valid/open, false otherwise 39 */ 40 bool isValid(int fd) 41 { 42 return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF); 43 } 44 45 TEST(FFDCFileTests, Constructor) 46 { 47 // Test where only the FFDCFormat parameter is specified 48 { 49 FFDCFile file{FFDCFormat::JSON}; 50 EXPECT_NE(file.getFileDescriptor(), -1); 51 EXPECT_TRUE(isValid(file.getFileDescriptor())); 52 EXPECT_EQ(file.getFormat(), FFDCFormat::JSON); 53 EXPECT_FALSE(file.getPath().empty()); 54 EXPECT_TRUE(fs::exists(file.getPath())); 55 EXPECT_EQ(file.getSubType(), 0); 56 EXPECT_EQ(file.getVersion(), 0); 57 } 58 59 // Test where all constructor parameters are specified 60 { 61 FFDCFile file{FFDCFormat::Custom, 2, 3}; 62 EXPECT_NE(file.getFileDescriptor(), -1); 63 EXPECT_TRUE(isValid(file.getFileDescriptor())); 64 EXPECT_EQ(file.getFormat(), FFDCFormat::Custom); 65 EXPECT_FALSE(file.getPath().empty()); 66 EXPECT_TRUE(fs::exists(file.getPath())); 67 EXPECT_EQ(file.getSubType(), 2); 68 EXPECT_EQ(file.getVersion(), 3); 69 } 70 71 // Note: The case where open() fails currently needs to be tested manually 72 } 73 74 TEST(FFDCFileTests, GetFileDescriptor) 75 { 76 FFDCFile file{FFDCFormat::JSON}; 77 int fd = file.getFileDescriptor(); 78 EXPECT_NE(fd, -1); 79 EXPECT_TRUE(isValid(fd)); 80 81 // Write some data to the file 82 char buffer[] = "This is some sample data"; 83 size_t count = sizeof(buffer); 84 EXPECT_EQ(write(fd, buffer, count), count); 85 86 // Seek back to the beginning of the file 87 EXPECT_EQ(lseek(fd, 0, SEEK_SET), 0); 88 89 // Clear buffer 90 memset(buffer, '\0', count); 91 EXPECT_STREQ(buffer, ""); 92 93 // Read and verify file contents 94 EXPECT_EQ(read(fd, buffer, count), count); 95 EXPECT_STREQ(buffer, "This is some sample data"); 96 } 97 98 TEST(FFDCFileTests, GetFormat) 99 { 100 // Test where 'Text' was specified 101 { 102 FFDCFile file{FFDCFormat::Text}; 103 EXPECT_EQ(file.getFormat(), FFDCFormat::Text); 104 } 105 106 // Test where 'Custom' was specified 107 { 108 FFDCFile file{FFDCFormat::Custom, 2, 3}; 109 EXPECT_EQ(file.getFormat(), FFDCFormat::Custom); 110 } 111 } 112 113 TEST(FFDCFileTests, GetPath) 114 { 115 FFDCFile file{FFDCFormat::JSON}; 116 EXPECT_FALSE(file.getPath().empty()); 117 EXPECT_TRUE(fs::exists(file.getPath())); 118 } 119 120 TEST(FFDCFileTests, GetSubType) 121 { 122 // Test where subType was not specified 123 { 124 FFDCFile file{FFDCFormat::JSON}; 125 EXPECT_EQ(file.getSubType(), 0); 126 } 127 128 // Test where subType was specified 129 { 130 FFDCFile file{FFDCFormat::Custom, 3, 2}; 131 EXPECT_EQ(file.getSubType(), 3); 132 } 133 } 134 135 TEST(FFDCFileTests, GetVersion) 136 { 137 // Test where version was not specified 138 { 139 FFDCFile file{FFDCFormat::JSON}; 140 EXPECT_EQ(file.getVersion(), 0); 141 } 142 143 // Test where version was specified 144 { 145 FFDCFile file{FFDCFormat::Custom, 2, 5}; 146 EXPECT_EQ(file.getVersion(), 5); 147 } 148 } 149 150 TEST(FFDCFileTests, Remove) 151 { 152 // Test where works 153 { 154 FFDCFile file{FFDCFormat::JSON}; 155 EXPECT_NE(file.getFileDescriptor(), -1); 156 EXPECT_TRUE(isValid(file.getFileDescriptor())); 157 EXPECT_FALSE(file.getPath().empty()); 158 EXPECT_TRUE(fs::exists(file.getPath())); 159 160 int fd = file.getFileDescriptor(); 161 fs::path path = file.getPath(); 162 163 file.remove(); 164 EXPECT_EQ(file.getFileDescriptor(), -1); 165 EXPECT_TRUE(file.getPath().empty()); 166 167 EXPECT_FALSE(isValid(fd)); 168 EXPECT_FALSE(fs::exists(path)); 169 } 170 171 // Test where file was already removed 172 { 173 FFDCFile file{FFDCFormat::JSON}; 174 EXPECT_NE(file.getFileDescriptor(), -1); 175 EXPECT_FALSE(file.getPath().empty()); 176 177 file.remove(); 178 EXPECT_EQ(file.getFileDescriptor(), -1); 179 EXPECT_TRUE(file.getPath().empty()); 180 181 file.remove(); 182 EXPECT_EQ(file.getFileDescriptor(), -1); 183 EXPECT_TRUE(file.getPath().empty()); 184 } 185 186 // Test where closing the file fails 187 { 188 FFDCFile file{FFDCFormat::JSON}; 189 int fd = file.getFileDescriptor(); 190 EXPECT_TRUE(isValid(fd)); 191 192 EXPECT_EQ(close(fd), 0); 193 EXPECT_FALSE(isValid(fd)); 194 195 try 196 { 197 file.remove(); 198 ADD_FAILURE() << "Should not have reached this line."; 199 } 200 catch (const std::exception& e) 201 { 202 EXPECT_NE(std::string{e.what()}.find("Unable to close FFDC file: "), 203 std::string::npos); 204 } 205 } 206 207 // Test where deleting the file fails 208 { 209 FFDCFile file{FFDCFormat::JSON}; 210 fs::path path = file.getPath(); 211 EXPECT_TRUE(fs::exists(path)); 212 213 makeFileUnRemovable(path); 214 try 215 { 216 file.remove(); 217 ADD_FAILURE() << "Should not have reached this line."; 218 } 219 catch (const std::exception& e) 220 { 221 // This is expected. Exception message will vary. 222 } 223 makeFileRemovable(path); 224 } 225 } 226