xref: /aosp_15_r20/external/federated-compute/fcp/tensorflow/file_descriptor_filesystem_test.cc (revision 14675a029014e728ec732f129a32e299b2da0601)
1 /*
2  * Copyright 2023 Google LLC
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 
17 #include "fcp/tensorflow/file_descriptor_filesystem.h"
18 
19 #include <fcntl.h>
20 
21 #include <memory>
22 #include <vector>
23 
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/string_view.h"
26 #include "android-base/file.h"
27 #include "gmock/gmock.h"
28 #include "gtest/gtest.h"
29 #include "tensorflow/core/lib/core/status_test_util.h"
30 
31 namespace tensorflow {
32 namespace fcp {
33 namespace {
34 
35 using ::android::base::ReadFileToString;
36 using ::testing::TempDir;
37 
38 static constexpr char kBadFdPath[] = "fd:///10000";
39 static constexpr char kFileContent[] = "abcdefgh";
40 static constexpr int kFileContentLen = 8;
41 
42 class FileDescriptorFileSystemTest : public ::testing::Test {
43  protected:
TearDown()44   void TearDown() override {
45     if (fd_ != -1) {
46       ASSERT_NE(-1, close(fd_));
47     }
48   }
49 
50   // Writes contents to a temp file and sets fd_path_ to point to it. The opened
51   // file descriptor is closed automatically in TearDown(). To be called at most
52   // once per test.
CreateAndOpenFdForTest(std::string contents)53   void CreateAndOpenFdForTest(std::string contents) {
54     ASSERT_EQ(-1, fd_);  // prevent accidental double-open
55     file_name_ = TempDir() + "/fdtest";
56     android::base::WriteStringToFile(contents, file_name_);
57 
58     fd_ = open(file_name_.c_str(), O_RDONLY);
59     ASSERT_NE(-1, fd_);
60 
61     fd_path_ = absl::StrCat("fd:///", fd_);
62   }
63 
CreateTempFdForTest()64   void CreateTempFdForTest() {
65     ASSERT_EQ(-1, fd_);  // prevent accidental double-open
66 
67     file_name_ = TempDir() + "/fdtest";
68     android::base::WriteStringToFile("", file_name_);
69 
70     fd_ = open(file_name_.c_str(), O_WRONLY);
71     ASSERT_NE(-1, fd_);
72 
73     fd_path_ = absl::StrCat("fd:///", fd_);
74   }
75 
76   FileDescriptorFileSystem fd_fs_;
77   string fd_path_;
78   string file_name_;
79 
80  private:
81   int fd_ = -1;
82 };
83 
TEST_F(FileDescriptorFileSystemTest,WritableFile)84 TEST_F(FileDescriptorFileSystemTest, WritableFile) {
85   CreateTempFdForTest();
86 
87   std::unique_ptr<WritableFile> file;
88   TF_ASSERT_OK(fd_fs_.NewWritableFile(fd_path_, &file));
89   TF_ASSERT_OK(file->Append(kFileContent));
90   TF_ASSERT_OK(file->Close());
91 
92   std::string actual_content;
93   ASSERT_TRUE(ReadFileToString(file_name_, &actual_content));
94   EXPECT_EQ(kFileContent, actual_content);
95 }
96 
TEST_F(FileDescriptorFileSystemTest,WritableFileFailsOnInvalidFd)97 TEST_F(FileDescriptorFileSystemTest, WritableFileFailsOnInvalidFd) {
98   std::unique_ptr<WritableFile> file;
99   EXPECT_FALSE(fd_fs_.NewWritableFile(kBadFdPath, &file).ok());
100 }
101 
TEST_F(FileDescriptorFileSystemTest,MalformedPathReturnsInvalidArgument)102 TEST_F(FileDescriptorFileSystemTest, MalformedPathReturnsInvalidArgument) {
103   FileStatistics stats;
104   EXPECT_EQ(fd_fs_.Stat("fd://0", &stats).code(), error::INVALID_ARGUMENT);
105   EXPECT_EQ(fd_fs_.Stat("fd://authority/0", &stats).code(),
106             error::INVALID_ARGUMENT);
107   EXPECT_EQ(fd_fs_.Stat("fd:///not-a-number", &stats).code(),
108             error::INVALID_ARGUMENT);
109 }
110 
TEST_F(FileDescriptorFileSystemTest,NewRandomAccessFile)111 TEST_F(FileDescriptorFileSystemTest, NewRandomAccessFile) {
112   CreateAndOpenFdForTest(kFileContent);
113 
114   std::unique_ptr<RandomAccessFile> file;
115   TF_ASSERT_OK(fd_fs_.NewRandomAccessFile(fd_path_, &file));
116   StringPiece content;
117   char scratch[kFileContentLen];
118   TF_ASSERT_OK(file->Read(0, kFileContentLen, &content, scratch));
119 
120   EXPECT_EQ(kFileContent, content);
121 }
122 
TEST_F(FileDescriptorFileSystemTest,NewRandomAccessFileFailsOnRequestMoreBytes)123 TEST_F(FileDescriptorFileSystemTest,
124        NewRandomAccessFileFailsOnRequestMoreBytes) {
125   CreateAndOpenFdForTest(kFileContent);
126 
127   std::unique_ptr<RandomAccessFile> file;
128   TF_ASSERT_OK(fd_fs_.NewRandomAccessFile(fd_path_, &file));
129   StringPiece content;
130   char scratch[kFileContentLen];
131   auto status = file->Read(0, kFileContentLen + 2, &content, scratch);
132   EXPECT_EQ(status.code(), error::OUT_OF_RANGE);
133   EXPECT_EQ(status.error_message(),
134             "Read fewer bytes than requested. Total read bytes 8");
135 }
136 
TEST_F(FileDescriptorFileSystemTest,NewRandomAccessFileFailsOnInvalidFd)137 TEST_F(FileDescriptorFileSystemTest, NewRandomAccessFileFailsOnInvalidFd) {
138   std::unique_ptr<RandomAccessFile> file;
139   EXPECT_FALSE(fd_fs_.NewRandomAccessFile(kBadFdPath, &file).ok());
140 }
141 
TEST_F(FileDescriptorFileSystemTest,NewRandomAccessFileFailsOnDirectoryFd)142 TEST_F(FileDescriptorFileSystemTest, NewRandomAccessFileFailsOnDirectoryFd) {
143   int dir_fd = open(TempDir().c_str(), O_RDONLY | O_DIRECTORY);
144   ASSERT_NE(-1, dir_fd);
145   string dir_fd_path = absl::StrCat("fd:///", dir_fd);
146 
147   std::unique_ptr<RandomAccessFile> file;
148   EXPECT_FALSE(fd_fs_.NewRandomAccessFile(dir_fd_path, &file).ok());
149 
150   close(dir_fd);
151 }
152 
TEST_F(FileDescriptorFileSystemTest,GetMatchingPaths)153 TEST_F(FileDescriptorFileSystemTest, GetMatchingPaths) {
154   CreateAndOpenFdForTest(kFileContent);
155 
156   std::vector<string> paths;
157   TF_EXPECT_OK(fd_fs_.GetMatchingPaths(fd_path_, &paths));
158 
159   ASSERT_EQ(1, paths.size());
160   EXPECT_EQ(fd_path_, paths.at(0));
161 }
162 
TEST_F(FileDescriptorFileSystemTest,GetMatchingPathsReturnsEmptyOnBadFd)163 TEST_F(FileDescriptorFileSystemTest, GetMatchingPathsReturnsEmptyOnBadFd) {
164   std::vector<string> paths;
165   TF_EXPECT_OK(fd_fs_.GetMatchingPaths(kBadFdPath, &paths));
166   EXPECT_TRUE(paths.empty());
167 }
168 
TEST_F(FileDescriptorFileSystemTest,Stat)169 TEST_F(FileDescriptorFileSystemTest, Stat) {
170   CreateAndOpenFdForTest(kFileContent);
171 
172   FileStatistics stats;
173   TF_EXPECT_OK(fd_fs_.Stat(fd_path_, &stats));
174 
175   EXPECT_EQ(kFileContentLen, stats.length);
176   EXPECT_GT(stats.mtime_nsec, 0);
177   EXPECT_FALSE(stats.is_directory);
178 }
179 
TEST_F(FileDescriptorFileSystemTest,StatFailsOnBadFd)180 TEST_F(FileDescriptorFileSystemTest, StatFailsOnBadFd) {
181   FileStatistics stats;
182   EXPECT_FALSE(fd_fs_.Stat(kBadFdPath, &stats).ok());
183 }
184 
TEST_F(FileDescriptorFileSystemTest,GetFileSize)185 TEST_F(FileDescriptorFileSystemTest, GetFileSize) {
186   CreateAndOpenFdForTest(kFileContent);
187 
188   uint64 size;
189   TF_EXPECT_OK(fd_fs_.GetFileSize(fd_path_, &size));
190 
191   EXPECT_EQ(kFileContentLen, size);
192 }
193 
TEST_F(FileDescriptorFileSystemTest,GetFileSizeFailsOnBadFd)194 TEST_F(FileDescriptorFileSystemTest, GetFileSizeFailsOnBadFd) {
195   uint64 size;
196   EXPECT_FALSE(fd_fs_.GetFileSize(kBadFdPath, &size).ok());
197 }
198 
TEST_F(FileDescriptorFileSystemTest,NewReadOnlyMemoryRegionFromFileReturnsUnimplemented)199 TEST_F(FileDescriptorFileSystemTest,
200        NewReadOnlyMemoryRegionFromFileReturnsUnimplemented) {
201   std::unique_ptr<ReadOnlyMemoryRegion> region;
202   EXPECT_EQ(fd_fs_.NewReadOnlyMemoryRegionFromFile(kBadFdPath, &region).code(),
203             error::UNIMPLEMENTED);
204 }
205 
TEST_F(FileDescriptorFileSystemTest,FileExistsReturnsUnimplemented)206 TEST_F(FileDescriptorFileSystemTest, FileExistsReturnsUnimplemented) {
207   EXPECT_EQ(fd_fs_.FileExists(kBadFdPath).code(), error::UNIMPLEMENTED);
208 }
209 
TEST_F(FileDescriptorFileSystemTest,GetChildrenReturnsUnimplemented)210 TEST_F(FileDescriptorFileSystemTest, GetChildrenReturnsUnimplemented) {
211   std::vector<string> paths;
212   EXPECT_EQ(fd_fs_.GetChildren(kBadFdPath, &paths).code(),
213             error::UNIMPLEMENTED);
214 }
215 
216 }  // anonymous namespace
217 }  // namespace fcp
218 }  // namespace tensorflow
219