1*9462e066SShawn McCarney /** 2*9462e066SShawn McCarney * Copyright © 2020 IBM Corporation 3*9462e066SShawn McCarney * 4*9462e066SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License"); 5*9462e066SShawn McCarney * you may not use this file except in compliance with the License. 6*9462e066SShawn McCarney * You may obtain a copy of the License at 7*9462e066SShawn McCarney * 8*9462e066SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0 9*9462e066SShawn McCarney * 10*9462e066SShawn McCarney * Unless required by applicable law or agreed to in writing, software 11*9462e066SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS, 12*9462e066SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*9462e066SShawn McCarney * See the License for the specific language governing permissions and 14*9462e066SShawn McCarney * limitations under the License. 15*9462e066SShawn McCarney */ 16*9462e066SShawn McCarney #include "file_descriptor.hpp" 17*9462e066SShawn McCarney 18*9462e066SShawn McCarney #include <errno.h> // for errno 19*9462e066SShawn McCarney #include <fcntl.h> // for open() and fcntl() 20*9462e066SShawn McCarney #include <sys/stat.h> // for open() 21*9462e066SShawn McCarney #include <sys/types.h> // for open() 22*9462e066SShawn McCarney #include <unistd.h> // for fcntl() 23*9462e066SShawn McCarney 24*9462e066SShawn McCarney #include <utility> 25*9462e066SShawn McCarney 26*9462e066SShawn McCarney #include <gtest/gtest.h> 27*9462e066SShawn McCarney 28*9462e066SShawn McCarney using namespace phosphor::power::util; 29*9462e066SShawn McCarney 30*9462e066SShawn McCarney /** 31*9462e066SShawn McCarney * Returns whether the specified file descriptor is valid/open. 32*9462e066SShawn McCarney * 33*9462e066SShawn McCarney * @param[in] fd - File descriptor 34*9462e066SShawn McCarney * @return true if descriptor is valid/open, false otherwise 35*9462e066SShawn McCarney */ 36*9462e066SShawn McCarney bool isValid(int fd) 37*9462e066SShawn McCarney { 38*9462e066SShawn McCarney return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF); 39*9462e066SShawn McCarney } 40*9462e066SShawn McCarney 41*9462e066SShawn McCarney /** 42*9462e066SShawn McCarney * Creates an open file descriptor. 43*9462e066SShawn McCarney * 44*9462e066SShawn McCarney * Verifies the file descriptor is valid. 45*9462e066SShawn McCarney * 46*9462e066SShawn McCarney * @return file descriptor 47*9462e066SShawn McCarney */ 48*9462e066SShawn McCarney int createOpenFileDescriptor() 49*9462e066SShawn McCarney { 50*9462e066SShawn McCarney int fd = open("/etc/hosts", O_RDONLY); 51*9462e066SShawn McCarney EXPECT_NE(fd, -1); 52*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 53*9462e066SShawn McCarney return fd; 54*9462e066SShawn McCarney } 55*9462e066SShawn McCarney 56*9462e066SShawn McCarney TEST(FileDescriptorTests, DefaultConstructor) 57*9462e066SShawn McCarney { 58*9462e066SShawn McCarney FileDescriptor descriptor; 59*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 60*9462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 61*9462e066SShawn McCarney } 62*9462e066SShawn McCarney 63*9462e066SShawn McCarney TEST(FileDescriptorTests, IntConstructor) 64*9462e066SShawn McCarney { 65*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 66*9462e066SShawn McCarney FileDescriptor descriptor{fd}; 67*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 68*9462e066SShawn McCarney EXPECT_TRUE(descriptor.operator bool()); 69*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 70*9462e066SShawn McCarney } 71*9462e066SShawn McCarney 72*9462e066SShawn McCarney TEST(FileDescriptorTests, MoveConstructor) 73*9462e066SShawn McCarney { 74*9462e066SShawn McCarney // Create first FileDescriptor object with open file descriptor 75*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 76*9462e066SShawn McCarney FileDescriptor descriptor1{fd}; 77*9462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd); 78*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 79*9462e066SShawn McCarney 80*9462e066SShawn McCarney // Create second FileDescriptor object, moving in the contents of the first 81*9462e066SShawn McCarney FileDescriptor descriptor2{std::move(descriptor1)}; 82*9462e066SShawn McCarney 83*9462e066SShawn McCarney // Verify descriptor has been moved out of first object 84*9462e066SShawn McCarney EXPECT_EQ(descriptor1(), -1); 85*9462e066SShawn McCarney 86*9462e066SShawn McCarney // Verify descriptor has been moved into second object 87*9462e066SShawn McCarney EXPECT_EQ(descriptor2(), fd); 88*9462e066SShawn McCarney 89*9462e066SShawn McCarney // Verify descriptor is still valid/open 90*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 91*9462e066SShawn McCarney } 92*9462e066SShawn McCarney 93*9462e066SShawn McCarney TEST(FileDescriptorTests, MoveAssignmentOperator) 94*9462e066SShawn McCarney { 95*9462e066SShawn McCarney // Test where move is valid 96*9462e066SShawn McCarney { 97*9462e066SShawn McCarney // Create first FileDescriptor object with open file descriptor 98*9462e066SShawn McCarney int fd1 = createOpenFileDescriptor(); 99*9462e066SShawn McCarney FileDescriptor descriptor1{fd1}; 100*9462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd1); 101*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 102*9462e066SShawn McCarney 103*9462e066SShawn McCarney // Create second FileDescriptor object with open file descriptor 104*9462e066SShawn McCarney int fd2 = createOpenFileDescriptor(); 105*9462e066SShawn McCarney FileDescriptor descriptor2{fd2}; 106*9462e066SShawn McCarney EXPECT_EQ(descriptor2(), fd2); 107*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 108*9462e066SShawn McCarney 109*9462e066SShawn McCarney // Move second FileDescriptor object into the first 110*9462e066SShawn McCarney descriptor1 = std::move(descriptor2); 111*9462e066SShawn McCarney 112*9462e066SShawn McCarney // Verify second file descriptor has been moved into first object 113*9462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd2); 114*9462e066SShawn McCarney 115*9462e066SShawn McCarney // Verify second file descriptor has been moved out of second object 116*9462e066SShawn McCarney EXPECT_EQ(descriptor2(), -1); 117*9462e066SShawn McCarney 118*9462e066SShawn McCarney // Verify first file descriptor has been closed and is no longer valid 119*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd1)); 120*9462e066SShawn McCarney 121*9462e066SShawn McCarney // Verify second file descriptor is still valid 122*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 123*9462e066SShawn McCarney } 124*9462e066SShawn McCarney 125*9462e066SShawn McCarney // Test where move is invalid: Attempt to move object into itself 126*9462e066SShawn McCarney { 127*9462e066SShawn McCarney // Create FileDescriptor object with open file descriptor 128*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 129*9462e066SShawn McCarney FileDescriptor descriptor{fd}; 130*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 131*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 132*9462e066SShawn McCarney 133*9462e066SShawn McCarney // Try to move object into itself 134*9462e066SShawn McCarney descriptor = std::move(descriptor); 135*9462e066SShawn McCarney 136*9462e066SShawn McCarney // Verify object still contains file descriptor 137*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 138*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 139*9462e066SShawn McCarney } 140*9462e066SShawn McCarney } 141*9462e066SShawn McCarney 142*9462e066SShawn McCarney TEST(FileDescriptorTests, Destructor) 143*9462e066SShawn McCarney { 144*9462e066SShawn McCarney // Test where file descriptor was never set 145*9462e066SShawn McCarney { 146*9462e066SShawn McCarney FileDescriptor descriptor; 147*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 148*9462e066SShawn McCarney } 149*9462e066SShawn McCarney 150*9462e066SShawn McCarney // Test where file descriptor was already closed 151*9462e066SShawn McCarney { 152*9462e066SShawn McCarney // Create FileDescriptor object with open file descriptor. Close the 153*9462e066SShawn McCarney // descriptor explicitly. 154*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 155*9462e066SShawn McCarney { 156*9462e066SShawn McCarney FileDescriptor descriptor{fd}; 157*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 158*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 159*9462e066SShawn McCarney 160*9462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 161*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 162*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 163*9462e066SShawn McCarney } 164*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 165*9462e066SShawn McCarney } 166*9462e066SShawn McCarney 167*9462e066SShawn McCarney // Test where file descriptor needs to be closed 168*9462e066SShawn McCarney { 169*9462e066SShawn McCarney // Create FileDescriptor object with open file descriptor. Destructor 170*9462e066SShawn McCarney // will close descriptor. 171*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 172*9462e066SShawn McCarney { 173*9462e066SShawn McCarney FileDescriptor descriptor{fd}; 174*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 175*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 176*9462e066SShawn McCarney } 177*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 178*9462e066SShawn McCarney } 179*9462e066SShawn McCarney } 180*9462e066SShawn McCarney 181*9462e066SShawn McCarney TEST(FileDescriptorTests, FunctionCallOperator) 182*9462e066SShawn McCarney { 183*9462e066SShawn McCarney // Test where FileDescriptor object does not contain a valid file descriptor 184*9462e066SShawn McCarney FileDescriptor descriptor{}; 185*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 186*9462e066SShawn McCarney 187*9462e066SShawn McCarney // Test where FileDescriptor object contains a valid file descriptor 188*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 189*9462e066SShawn McCarney descriptor.set(fd); 190*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 191*9462e066SShawn McCarney } 192*9462e066SShawn McCarney 193*9462e066SShawn McCarney TEST(FileDescriptorTests, OperatorBool) 194*9462e066SShawn McCarney { 195*9462e066SShawn McCarney // Test where FileDescriptor object does not contain a valid file descriptor 196*9462e066SShawn McCarney FileDescriptor descriptor{}; 197*9462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 198*9462e066SShawn McCarney if (descriptor) 199*9462e066SShawn McCarney { 200*9462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 201*9462e066SShawn McCarney } 202*9462e066SShawn McCarney 203*9462e066SShawn McCarney // Test where FileDescriptor object contains a valid file descriptor 204*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 205*9462e066SShawn McCarney descriptor.set(fd); 206*9462e066SShawn McCarney EXPECT_TRUE(descriptor.operator bool()); 207*9462e066SShawn McCarney if (!descriptor) 208*9462e066SShawn McCarney { 209*9462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 210*9462e066SShawn McCarney } 211*9462e066SShawn McCarney 212*9462e066SShawn McCarney // Test where file descriptor has been closed 213*9462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 214*9462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 215*9462e066SShawn McCarney if (descriptor) 216*9462e066SShawn McCarney { 217*9462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 218*9462e066SShawn McCarney } 219*9462e066SShawn McCarney } 220*9462e066SShawn McCarney 221*9462e066SShawn McCarney TEST(FileDescriptorTests, Close) 222*9462e066SShawn McCarney { 223*9462e066SShawn McCarney // Test where object contains an open file descriptor 224*9462e066SShawn McCarney int fd = createOpenFileDescriptor(); 225*9462e066SShawn McCarney FileDescriptor descriptor{fd}; 226*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 227*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 228*9462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 229*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 230*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 231*9462e066SShawn McCarney 232*9462e066SShawn McCarney // Test where object does not contain an open file descriptor 233*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 234*9462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 235*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 236*9462e066SShawn McCarney 237*9462e066SShawn McCarney // Test where close() fails due to invalid file descriptor 238*9462e066SShawn McCarney descriptor.set(999999); 239*9462e066SShawn McCarney EXPECT_EQ(descriptor.close(), -1); 240*9462e066SShawn McCarney EXPECT_EQ(errno, EBADF); 241*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 242*9462e066SShawn McCarney } 243*9462e066SShawn McCarney 244*9462e066SShawn McCarney TEST(FileDescriptorTests, Set) 245*9462e066SShawn McCarney { 246*9462e066SShawn McCarney // Test where object does not contain an open file descriptor 247*9462e066SShawn McCarney FileDescriptor descriptor{}; 248*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 249*9462e066SShawn McCarney int fd1 = createOpenFileDescriptor(); 250*9462e066SShawn McCarney descriptor.set(fd1); 251*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd1); 252*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 253*9462e066SShawn McCarney 254*9462e066SShawn McCarney // Test where object contains an open file descriptor. Should close 255*9462e066SShawn McCarney // previous descriptor. 256*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd1); 257*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 258*9462e066SShawn McCarney int fd2 = createOpenFileDescriptor(); 259*9462e066SShawn McCarney descriptor.set(fd2); 260*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd2); 261*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd1)); 262*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 263*9462e066SShawn McCarney 264*9462e066SShawn McCarney // Test where -1 is specified. Should close previous descriptor. 265*9462e066SShawn McCarney EXPECT_EQ(descriptor(), fd2); 266*9462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 267*9462e066SShawn McCarney descriptor.set(-1); 268*9462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 269*9462e066SShawn McCarney EXPECT_FALSE(isValid(fd2)); 270*9462e066SShawn McCarney } 271