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 */
isValid(int fd)40 bool isValid(int fd)
41 {
42 return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF);
43 }
44
TEST(FFDCFileTests,Constructor)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
TEST(FFDCFileTests,GetFileDescriptor)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
TEST(FFDCFileTests,GetFormat)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
TEST(FFDCFileTests,GetPath)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
TEST(FFDCFileTests,GetSubType)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
TEST(FFDCFileTests,GetVersion)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
TEST(FFDCFileTests,Remove)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