• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
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 "src/traced/probes/filesystem/file_scanner.h"
18 
19 #include <sys/stat.h>
20 #include <memory>
21 #include <string>
22 
23 #include "perfetto/base/logging.h"
24 #include "protos/perfetto/trace/filesystem/inode_file_map.pbzero.h"
25 #include "src/base/test/test_task_runner.h"
26 #include "src/base/test/utils.h"
27 #include "test/gtest_and_gmock.h"
28 
29 namespace perfetto {
30 namespace {
31 
32 using ::testing::Eq;
33 using ::testing::Contains;
34 using ::testing::UnorderedElementsAre;
35 
36 class TestDelegate : public FileScanner::Delegate {
37  public:
TestDelegate(std::function<bool (BlockDeviceID,Inode,const std::string &,InodeFileMap_Entry_Type)> callback,std::function<void ()> done_callback)38   TestDelegate(std::function<bool(BlockDeviceID,
39                                   Inode,
40                                   const std::string&,
41                                   InodeFileMap_Entry_Type)> callback,
42                std::function<void()> done_callback)
43       : callback_(std::move(callback)),
44         done_callback_(std::move(done_callback)) {}
OnInodeFound(BlockDeviceID block_device_id,Inode inode,const std::string & path,InodeFileMap_Entry_Type type)45   bool OnInodeFound(BlockDeviceID block_device_id,
46                     Inode inode,
47                     const std::string& path,
48                     InodeFileMap_Entry_Type type) override {
49     return callback_(block_device_id, inode, path, type);
50   }
51 
OnInodeScanDone()52   void OnInodeScanDone() { return done_callback_(); }
53 
54  private:
55   std::function<
56       bool(BlockDeviceID, Inode, const std::string&, InodeFileMap_Entry_Type)>
57       callback_;
58   std::function<void()> done_callback_;
59 };
60 
61 struct FileEntry {
FileEntryperfetto::__anon87225d370111::FileEntry62   FileEntry(BlockDeviceID block_device_id,
63             Inode inode,
64             std::string path,
65             InodeFileMap_Entry_Type type)
66       : block_device_id_(block_device_id),
67         inode_(inode),
68         path_(std::move(path)),
69         type_(type) {}
70 
operator ==perfetto::__anon87225d370111::FileEntry71   bool operator==(const FileEntry& other) const {
72     return block_device_id_ == other.block_device_id_ &&
73            inode_ == other.inode_ && path_ == other.path_ &&
74            type_ == other.type_;
75   }
76 
77   BlockDeviceID block_device_id_;
78   Inode inode_;
79   std::string path_;
80   InodeFileMap_Entry_Type type_;
81 };
82 
CheckStat(const std::string & path)83 struct stat CheckStat(const std::string& path) {
84   struct stat buf;
85   PERFETTO_CHECK(lstat(path.c_str(), &buf) != -1);
86   return buf;
87 }
88 
StatFileEntry(const std::string & path,InodeFileMap_Entry_Type type)89 FileEntry StatFileEntry(const std::string& path, InodeFileMap_Entry_Type type) {
90   struct stat buf = CheckStat(path);
91   return FileEntry(buf.st_dev, buf.st_ino, path, type);
92 }
93 
TEST(FileScannerTest,TestSynchronousStop)94 TEST(FileScannerTest, TestSynchronousStop) {
95   uint64_t seen = 0;
96   bool done = false;
97   TestDelegate delegate(
98       [&seen](BlockDeviceID, Inode, const std::string&,
99               InodeFileMap_Entry_Type) {
100         ++seen;
101         return false;
102       },
103       [&done] { done = true; });
104 
105   FileScanner fs(
106       {base::GetTestDataPath("src/traced/probes/filesystem/testdata")},
107       &delegate);
108   fs.Scan();
109 
110   EXPECT_EQ(seen, 1u);
111   EXPECT_TRUE(done);
112 }
113 
TEST(FileScannerTest,TestAsynchronousStop)114 TEST(FileScannerTest, TestAsynchronousStop) {
115   uint64_t seen = 0;
116   base::TestTaskRunner task_runner;
117   TestDelegate delegate(
118       [&seen](BlockDeviceID, Inode, const std::string&,
119               InodeFileMap_Entry_Type) {
120         ++seen;
121         return false;
122       },
123       task_runner.CreateCheckpoint("done"));
124 
125   FileScanner fs(
126       {base::GetTestDataPath("src/traced/probes/filesystem/testdata")},
127       &delegate, 1, 1);
128   fs.Scan(&task_runner);
129 
130   task_runner.RunUntilCheckpoint("done");
131 
132   EXPECT_EQ(seen, 1u);
133 }
134 
TEST(FileScannerTest,TestSynchronousFindFiles)135 TEST(FileScannerTest, TestSynchronousFindFiles) {
136   std::vector<FileEntry> file_entries;
137   TestDelegate delegate(
138       [&file_entries](BlockDeviceID block_device_id, Inode inode,
139                       const std::string& path, InodeFileMap_Entry_Type type) {
140         file_entries.emplace_back(block_device_id, inode, path, type);
141         return true;
142       },
143       [] {});
144 
145   FileScanner fs(
146       {base::GetTestDataPath("src/traced/probes/filesystem/testdata")},
147       &delegate);
148   fs.Scan();
149 
150   EXPECT_THAT(
151       file_entries,
152       UnorderedElementsAre(
153           Eq(StatFileEntry(
154               base::GetTestDataPath(
155                   "src/traced/probes/filesystem/testdata/dir1/file1"),
156               protos::pbzero::InodeFileMap_Entry_Type_FILE)),
157           Eq(StatFileEntry(base::GetTestDataPath(
158                                "src/traced/probes/filesystem/testdata/file2"),
159                            protos::pbzero::InodeFileMap_Entry_Type_FILE)),
160           Eq(StatFileEntry(
161               base::GetTestDataPath(
162                   "src/traced/probes/filesystem/testdata/dir1"),
163               protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY))));
164 }
165 
TEST(FileScannerTest,TestAsynchronousFindFiles)166 TEST(FileScannerTest, TestAsynchronousFindFiles) {
167   base::TestTaskRunner task_runner;
168   std::vector<FileEntry> file_entries;
169   TestDelegate delegate(
170       [&file_entries](BlockDeviceID block_device_id, Inode inode,
171                       const std::string& path, InodeFileMap_Entry_Type type) {
172         file_entries.emplace_back(block_device_id, inode, path, type);
173         return true;
174       },
175       task_runner.CreateCheckpoint("done"));
176 
177   FileScanner fs(
178       {base::GetTestDataPath("src/traced/probes/filesystem/testdata")},
179       &delegate, 1, 1);
180   fs.Scan(&task_runner);
181 
182   task_runner.RunUntilCheckpoint("done");
183 
184   EXPECT_THAT(
185       file_entries,
186       UnorderedElementsAre(
187           Eq(StatFileEntry(
188               base::GetTestDataPath(
189                   "src/traced/probes/filesystem/testdata/dir1/file1"),
190               protos::pbzero::InodeFileMap_Entry_Type_FILE)),
191           Eq(StatFileEntry(base::GetTestDataPath(
192                                "src/traced/probes/filesystem/testdata/file2"),
193                            protos::pbzero::InodeFileMap_Entry_Type_FILE)),
194           Eq(StatFileEntry(
195               base::GetTestDataPath(
196                   "src/traced/probes/filesystem/testdata/dir1"),
197               protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY))));
198 }
199 
200 }  // namespace
201 }  // namespace perfetto
202