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