/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/traced/probes/filesystem/file_scanner.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include #include #include #include "perfetto/base/logging.h" #include "src/base/test/test_task_runner.h" namespace perfetto { namespace { using ::testing::Eq; using ::testing::Contains; using ::testing::UnorderedElementsAre; class TestDelegate : public FileScanner::Delegate { public: TestDelegate( std::function callback, std::function done_callback) : callback_(std::move(callback)), done_callback_(std::move(done_callback)) {} bool OnInodeFound(BlockDeviceID block_device_id, Inode inode, const std::string& path, protos::pbzero::InodeFileMap_Entry_Type type) override { return callback_(block_device_id, inode, path, type); } void OnInodeScanDone() { return done_callback_(); } private: std::function callback_; std::function done_callback_; }; struct FileEntry { FileEntry(BlockDeviceID block_device_id, Inode inode, std::string path, protos::pbzero::InodeFileMap_Entry_Type type) : block_device_id_(block_device_id), inode_(inode), path_(std::move(path)), type_(type) {} bool operator==(const FileEntry& other) const { return block_device_id_ == other.block_device_id_ && inode_ == other.inode_ && path_ == other.path_ && type_ == other.type_; } BlockDeviceID block_device_id_; Inode inode_; std::string path_; protos::pbzero::InodeFileMap_Entry_Type type_; }; struct stat CheckStat(const std::string& path) { struct stat buf; PERFETTO_CHECK(lstat(path.c_str(), &buf) != -1); return buf; } FileEntry StatFileEntry(const std::string& path, protos::pbzero::InodeFileMap_Entry_Type type) { struct stat buf = CheckStat(path); return FileEntry(buf.st_dev, buf.st_ino, path, type); } TEST(FileScannerTest, TestSynchronousStop) { uint64_t seen = 0; bool done = false; TestDelegate delegate( [&seen](BlockDeviceID, Inode, const std::string&, protos::pbzero::InodeFileMap_Entry_Type) { ++seen; return false; }, [&done] { done = true; }); FileScanner fs({"src/traced/probes/filesystem/testdata"}, &delegate); fs.Scan(); EXPECT_EQ(seen, 1u); EXPECT_TRUE(done); } TEST(FileScannerTest, TestAsynchronousStop) { uint64_t seen = 0; base::TestTaskRunner task_runner; TestDelegate delegate( [&seen](BlockDeviceID, Inode, const std::string&, protos::pbzero::InodeFileMap_Entry_Type) { ++seen; return false; }, task_runner.CreateCheckpoint("done")); FileScanner fs({"src/traced/probes/filesystem/testdata"}, &delegate, 1, 1); fs.Scan(&task_runner); task_runner.RunUntilCheckpoint("done"); EXPECT_EQ(seen, 1u); } TEST(FileScannerTest, TestSynchronousFindFiles) { std::vector file_entries; TestDelegate delegate( [&file_entries](BlockDeviceID block_device_id, Inode inode, const std::string& path, protos::pbzero::InodeFileMap_Entry_Type type) { file_entries.emplace_back(block_device_id, inode, path, type); return true; }, [] {}); FileScanner fs({"src/traced/probes/filesystem/testdata"}, &delegate); fs.Scan(); EXPECT_THAT( file_entries, UnorderedElementsAre( Eq(StatFileEntry("src/traced/probes/filesystem/testdata/dir1/file1", protos::pbzero::InodeFileMap_Entry_Type_FILE)), Eq(StatFileEntry("src/traced/probes/filesystem/testdata/file2", protos::pbzero::InodeFileMap_Entry_Type_FILE)), Eq(StatFileEntry( "src/traced/probes/filesystem/testdata/dir1", protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY)))); } TEST(FileScannerTest, TestAsynchronousFindFiles) { base::TestTaskRunner task_runner; std::vector file_entries; TestDelegate delegate( [&file_entries](BlockDeviceID block_device_id, Inode inode, const std::string& path, protos::pbzero::InodeFileMap_Entry_Type type) { file_entries.emplace_back(block_device_id, inode, path, type); return true; }, task_runner.CreateCheckpoint("done")); FileScanner fs({"src/traced/probes/filesystem/testdata"}, &delegate, 1, 1); fs.Scan(&task_runner); task_runner.RunUntilCheckpoint("done"); EXPECT_THAT( file_entries, UnorderedElementsAre( Eq(StatFileEntry("src/traced/probes/filesystem/testdata/dir1/file1", protos::pbzero::InodeFileMap_Entry_Type_FILE)), Eq(StatFileEntry("src/traced/probes/filesystem/testdata/file2", protos::pbzero::InodeFileMap_Entry_Type_FILE)), Eq(StatFileEntry( "src/traced/probes/filesystem/testdata/dir1", protos::pbzero::InodeFileMap_Entry_Type_DIRECTORY)))); } } // namespace } // namespace perfetto