19462e066SShawn McCarney /** 29462e066SShawn McCarney * Copyright © 2020 IBM Corporation 39462e066SShawn McCarney * 49462e066SShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License"); 59462e066SShawn McCarney * you may not use this file except in compliance with the License. 69462e066SShawn McCarney * You may obtain a copy of the License at 79462e066SShawn McCarney * 89462e066SShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0 99462e066SShawn McCarney * 109462e066SShawn McCarney * Unless required by applicable law or agreed to in writing, software 119462e066SShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS, 129462e066SShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139462e066SShawn McCarney * See the License for the specific language governing permissions and 149462e066SShawn McCarney * limitations under the License. 159462e066SShawn McCarney */ 169462e066SShawn McCarney #include "file_descriptor.hpp" 179462e066SShawn McCarney 189462e066SShawn McCarney #include <errno.h> // for errno 199462e066SShawn McCarney #include <fcntl.h> // for open() and fcntl() 209462e066SShawn McCarney #include <sys/stat.h> // for open() 219462e066SShawn McCarney #include <sys/types.h> // for open() 229462e066SShawn McCarney #include <unistd.h> // for fcntl() 239462e066SShawn McCarney 249462e066SShawn McCarney #include <utility> 259462e066SShawn McCarney 269462e066SShawn McCarney #include <gtest/gtest.h> 279462e066SShawn McCarney 289462e066SShawn McCarney using namespace phosphor::power::util; 299462e066SShawn McCarney 309462e066SShawn McCarney /** 319462e066SShawn McCarney * Returns whether the specified file descriptor is valid/open. 329462e066SShawn McCarney * 339462e066SShawn McCarney * @param[in] fd - File descriptor 349462e066SShawn McCarney * @return true if descriptor is valid/open, false otherwise 359462e066SShawn McCarney */ 369462e066SShawn McCarney bool isValid(int fd) 379462e066SShawn McCarney { 389462e066SShawn McCarney return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF); 399462e066SShawn McCarney } 409462e066SShawn McCarney 419462e066SShawn McCarney /** 429462e066SShawn McCarney * Creates an open file descriptor. 439462e066SShawn McCarney * 449462e066SShawn McCarney * Verifies the file descriptor is valid. 459462e066SShawn McCarney * 469462e066SShawn McCarney * @return file descriptor 479462e066SShawn McCarney */ 489462e066SShawn McCarney int createOpenFileDescriptor() 499462e066SShawn McCarney { 509462e066SShawn McCarney int fd = open("/etc/hosts", O_RDONLY); 519462e066SShawn McCarney EXPECT_NE(fd, -1); 529462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 539462e066SShawn McCarney return fd; 549462e066SShawn McCarney } 559462e066SShawn McCarney 569462e066SShawn McCarney TEST(FileDescriptorTests, DefaultConstructor) 579462e066SShawn McCarney { 589462e066SShawn McCarney FileDescriptor descriptor; 599462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 609462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 619462e066SShawn McCarney } 629462e066SShawn McCarney 639462e066SShawn McCarney TEST(FileDescriptorTests, IntConstructor) 649462e066SShawn McCarney { 659462e066SShawn McCarney int fd = createOpenFileDescriptor(); 669462e066SShawn McCarney FileDescriptor descriptor{fd}; 679462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 689462e066SShawn McCarney EXPECT_TRUE(descriptor.operator bool()); 699462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 709462e066SShawn McCarney } 719462e066SShawn McCarney 729462e066SShawn McCarney TEST(FileDescriptorTests, MoveConstructor) 739462e066SShawn McCarney { 749462e066SShawn McCarney // Create first FileDescriptor object with open file descriptor 759462e066SShawn McCarney int fd = createOpenFileDescriptor(); 769462e066SShawn McCarney FileDescriptor descriptor1{fd}; 779462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd); 789462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 799462e066SShawn McCarney 809462e066SShawn McCarney // Create second FileDescriptor object, moving in the contents of the first 819462e066SShawn McCarney FileDescriptor descriptor2{std::move(descriptor1)}; 829462e066SShawn McCarney 839462e066SShawn McCarney // Verify descriptor has been moved out of first object 849462e066SShawn McCarney EXPECT_EQ(descriptor1(), -1); 859462e066SShawn McCarney 869462e066SShawn McCarney // Verify descriptor has been moved into second object 879462e066SShawn McCarney EXPECT_EQ(descriptor2(), fd); 889462e066SShawn McCarney 899462e066SShawn McCarney // Verify descriptor is still valid/open 909462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 919462e066SShawn McCarney } 929462e066SShawn McCarney 939462e066SShawn McCarney TEST(FileDescriptorTests, MoveAssignmentOperator) 949462e066SShawn McCarney { 959462e066SShawn McCarney // Test where move is valid 969462e066SShawn McCarney { 979462e066SShawn McCarney // Create first FileDescriptor object with open file descriptor 989462e066SShawn McCarney int fd1 = createOpenFileDescriptor(); 999462e066SShawn McCarney FileDescriptor descriptor1{fd1}; 1009462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd1); 1019462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 1029462e066SShawn McCarney 1039462e066SShawn McCarney // Create second FileDescriptor object with open file descriptor 1049462e066SShawn McCarney int fd2 = createOpenFileDescriptor(); 1059462e066SShawn McCarney FileDescriptor descriptor2{fd2}; 1069462e066SShawn McCarney EXPECT_EQ(descriptor2(), fd2); 1079462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 1089462e066SShawn McCarney 1099462e066SShawn McCarney // Move second FileDescriptor object into the first 1109462e066SShawn McCarney descriptor1 = std::move(descriptor2); 1119462e066SShawn McCarney 1129462e066SShawn McCarney // Verify second file descriptor has been moved into first object 1139462e066SShawn McCarney EXPECT_EQ(descriptor1(), fd2); 1149462e066SShawn McCarney 1159462e066SShawn McCarney // Verify second file descriptor has been moved out of second object 1169462e066SShawn McCarney EXPECT_EQ(descriptor2(), -1); 1179462e066SShawn McCarney 1189462e066SShawn McCarney // Verify first file descriptor has been closed and is no longer valid 1199462e066SShawn McCarney EXPECT_FALSE(isValid(fd1)); 1209462e066SShawn McCarney 1219462e066SShawn McCarney // Verify second file descriptor is still valid 1229462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 1239462e066SShawn McCarney } 1249462e066SShawn McCarney 1259462e066SShawn McCarney // Test where move is invalid: Attempt to move object into itself 1269462e066SShawn McCarney { 1279462e066SShawn McCarney // Create FileDescriptor object with open file descriptor 1289462e066SShawn McCarney int fd = createOpenFileDescriptor(); 1299462e066SShawn McCarney FileDescriptor descriptor{fd}; 1309462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 1319462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 1329462e066SShawn McCarney 1339462e066SShawn McCarney // Try to move object into itself 134*81e554c8SPatrick Williams descriptor = static_cast<FileDescriptor&&>(descriptor); 1359462e066SShawn McCarney 1369462e066SShawn McCarney // Verify object still contains file descriptor 1379462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 1389462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 1399462e066SShawn McCarney } 1409462e066SShawn McCarney } 1419462e066SShawn McCarney 1429462e066SShawn McCarney TEST(FileDescriptorTests, Destructor) 1439462e066SShawn McCarney { 1449462e066SShawn McCarney // Test where file descriptor was never set 1459462e066SShawn McCarney { 1469462e066SShawn McCarney FileDescriptor descriptor; 1479462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 1489462e066SShawn McCarney } 1499462e066SShawn McCarney 1509462e066SShawn McCarney // Test where file descriptor was already closed 1519462e066SShawn McCarney { 1529462e066SShawn McCarney // Create FileDescriptor object with open file descriptor. Close the 1539462e066SShawn McCarney // descriptor explicitly. 1549462e066SShawn McCarney int fd = createOpenFileDescriptor(); 1559462e066SShawn McCarney { 1569462e066SShawn McCarney FileDescriptor descriptor{fd}; 1579462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 1589462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 1599462e066SShawn McCarney 1609462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 1619462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 1629462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 1639462e066SShawn McCarney } 1649462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 1659462e066SShawn McCarney } 1669462e066SShawn McCarney 1679462e066SShawn McCarney // Test where file descriptor needs to be closed 1689462e066SShawn McCarney { 1699462e066SShawn McCarney // Create FileDescriptor object with open file descriptor. Destructor 1709462e066SShawn McCarney // will close descriptor. 1719462e066SShawn McCarney int fd = createOpenFileDescriptor(); 1729462e066SShawn McCarney { 1739462e066SShawn McCarney FileDescriptor descriptor{fd}; 1749462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 1759462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 1769462e066SShawn McCarney } 1779462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 1789462e066SShawn McCarney } 1799462e066SShawn McCarney } 1809462e066SShawn McCarney 1819462e066SShawn McCarney TEST(FileDescriptorTests, FunctionCallOperator) 1829462e066SShawn McCarney { 1839462e066SShawn McCarney // Test where FileDescriptor object does not contain a valid file descriptor 1849462e066SShawn McCarney FileDescriptor descriptor{}; 1859462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 1869462e066SShawn McCarney 1879462e066SShawn McCarney // Test where FileDescriptor object contains a valid file descriptor 1889462e066SShawn McCarney int fd = createOpenFileDescriptor(); 1899462e066SShawn McCarney descriptor.set(fd); 1909462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 1919462e066SShawn McCarney } 1929462e066SShawn McCarney 1939462e066SShawn McCarney TEST(FileDescriptorTests, OperatorBool) 1949462e066SShawn McCarney { 1959462e066SShawn McCarney // Test where FileDescriptor object does not contain a valid file descriptor 1969462e066SShawn McCarney FileDescriptor descriptor{}; 1979462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 1989462e066SShawn McCarney if (descriptor) 1999462e066SShawn McCarney { 2009462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 2019462e066SShawn McCarney } 2029462e066SShawn McCarney 2039462e066SShawn McCarney // Test where FileDescriptor object contains a valid file descriptor 2049462e066SShawn McCarney int fd = createOpenFileDescriptor(); 2059462e066SShawn McCarney descriptor.set(fd); 2069462e066SShawn McCarney EXPECT_TRUE(descriptor.operator bool()); 2079462e066SShawn McCarney if (!descriptor) 2089462e066SShawn McCarney { 2099462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 2109462e066SShawn McCarney } 2119462e066SShawn McCarney 2129462e066SShawn McCarney // Test where file descriptor has been closed 2139462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 2149462e066SShawn McCarney EXPECT_FALSE(descriptor.operator bool()); 2159462e066SShawn McCarney if (descriptor) 2169462e066SShawn McCarney { 2179462e066SShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 2189462e066SShawn McCarney } 2199462e066SShawn McCarney } 2209462e066SShawn McCarney 2219462e066SShawn McCarney TEST(FileDescriptorTests, Close) 2229462e066SShawn McCarney { 2239462e066SShawn McCarney // Test where object contains an open file descriptor 2249462e066SShawn McCarney int fd = createOpenFileDescriptor(); 2259462e066SShawn McCarney FileDescriptor descriptor{fd}; 2269462e066SShawn McCarney EXPECT_EQ(descriptor(), fd); 2279462e066SShawn McCarney EXPECT_TRUE(isValid(fd)); 2289462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 2299462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2309462e066SShawn McCarney EXPECT_FALSE(isValid(fd)); 2319462e066SShawn McCarney 2329462e066SShawn McCarney // Test where object does not contain an open file descriptor 2339462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2349462e066SShawn McCarney EXPECT_EQ(descriptor.close(), 0); 2359462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2369462e066SShawn McCarney 2379462e066SShawn McCarney // Test where close() fails due to invalid file descriptor 2389462e066SShawn McCarney descriptor.set(999999); 2399462e066SShawn McCarney EXPECT_EQ(descriptor.close(), -1); 2409462e066SShawn McCarney EXPECT_EQ(errno, EBADF); 2419462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2429462e066SShawn McCarney } 2439462e066SShawn McCarney 2449462e066SShawn McCarney TEST(FileDescriptorTests, Set) 2459462e066SShawn McCarney { 2469462e066SShawn McCarney // Test where object does not contain an open file descriptor 2479462e066SShawn McCarney FileDescriptor descriptor{}; 2489462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2499462e066SShawn McCarney int fd1 = createOpenFileDescriptor(); 2509462e066SShawn McCarney descriptor.set(fd1); 2519462e066SShawn McCarney EXPECT_EQ(descriptor(), fd1); 2529462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 2539462e066SShawn McCarney 2549462e066SShawn McCarney // Test where object contains an open file descriptor. Should close 2559462e066SShawn McCarney // previous descriptor. 2569462e066SShawn McCarney EXPECT_EQ(descriptor(), fd1); 2579462e066SShawn McCarney EXPECT_TRUE(isValid(fd1)); 2589462e066SShawn McCarney int fd2 = createOpenFileDescriptor(); 2599462e066SShawn McCarney descriptor.set(fd2); 2609462e066SShawn McCarney EXPECT_EQ(descriptor(), fd2); 2619462e066SShawn McCarney EXPECT_FALSE(isValid(fd1)); 2629462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 2639462e066SShawn McCarney 2649462e066SShawn McCarney // Test where -1 is specified. Should close previous descriptor. 2659462e066SShawn McCarney EXPECT_EQ(descriptor(), fd2); 2669462e066SShawn McCarney EXPECT_TRUE(isValid(fd2)); 2679462e066SShawn McCarney descriptor.set(-1); 2689462e066SShawn McCarney EXPECT_EQ(descriptor(), -1); 2699462e066SShawn McCarney EXPECT_FALSE(isValid(fd2)); 2709462e066SShawn McCarney } 271