// Copyright (c) 2012 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include #include "base/string_util.h" #include #include "update_engine/filesystem_iterator.h" #include "update_engine/test_utils.h" #include "update_engine/utils.h" using std::set; using std::string; using std::vector; namespace chromeos_update_engine { class FilesystemIteratorTest : public ::testing::Test { protected: virtual void SetUp() { ASSERT_TRUE(utils::MakeTempDirectory("FilesystemIteratorTest-XXXXXX", &test_dir_)); LOG(INFO) << "SetUp() mkdir " << test_dir_; } virtual void TearDown() { LOG(INFO) << "TearDown() rmdir " << test_dir_; EXPECT_EQ(0, System(StringPrintf("rm -rf %s", TestDir()))); } const char* TestDir() { return test_dir_.c_str(); } private: string test_dir_; }; TEST_F(FilesystemIteratorTest, RunAsRootSuccessTest) { ASSERT_EQ(0, getuid()); // Create uniquely named main/sub images. string main_image; ASSERT_TRUE(utils::MakeTempFile("FilesystemIteratorTest.image1-XXXXXX", &main_image, NULL)); ScopedPathUnlinker main_image_unlinker(main_image); string sub_image; ASSERT_TRUE(utils::MakeTempFile("FilesystemIteratorTest.image2-XXXXXX", &sub_image, NULL)); ScopedPathUnlinker sub_image_unlinker(sub_image); // Create uniqely named main/sub mount points. string main_image_mount_point; ASSERT_TRUE(utils::MakeTempDirectory( "FilesystemIteratorTest.mount-XXXXXX", &main_image_mount_point)); ScopedPathUnlinker main_image_mount_point_unlinker(main_image_mount_point); const string sub_image_mount_point = main_image_mount_point + "/some_dir/mnt"; vector expected_paths_vector; CreateExtImageAtPath(main_image, &expected_paths_vector); CreateExtImageAtPath(sub_image, NULL); ASSERT_EQ(0, System(string("mount -o loop ") + main_image + " " + main_image_mount_point)); ASSERT_EQ(0, System(string("mount -o loop ") + sub_image + " " + sub_image_mount_point)); for (vector::iterator it = expected_paths_vector.begin(); it != expected_paths_vector.end(); ++it) *it = main_image_mount_point + *it; set expected_paths(expected_paths_vector.begin(), expected_paths_vector.end()); VerifyAllPaths(main_image_mount_point, expected_paths); EXPECT_TRUE(utils::UnmountFilesystem(sub_image_mount_point)); EXPECT_TRUE(utils::UnmountFilesystem(main_image_mount_point)); } TEST_F(FilesystemIteratorTest, NegativeTest) { { FilesystemIterator iter("/non/existent/path", set()); EXPECT_TRUE(iter.IsEnd()); EXPECT_TRUE(iter.IsErr()); } { FilesystemIterator iter(TestDir(), set()); EXPECT_FALSE(iter.IsEnd()); EXPECT_FALSE(iter.IsErr()); // Here I'm deleting the exact directory that iterator is point at, // then incrementing (which normally would descend into that directory). EXPECT_EQ(0, rmdir(TestDir())); iter.Increment(); EXPECT_TRUE(iter.IsEnd()); EXPECT_FALSE(iter.IsErr()); } } TEST_F(FilesystemIteratorTest, DeleteWhileTraverseTest) { const string dir_name = TestDir(); ASSERT_EQ(0, chmod(dir_name.c_str(), 0755)); const string sub_dir_name(dir_name + "/a"); ASSERT_EQ(0, mkdir(sub_dir_name.c_str(), 0755)); const string sub_sub_dir_name(sub_dir_name + "/b"); ASSERT_EQ(0, mkdir(sub_sub_dir_name.c_str(), 0755)); ASSERT_EQ(0, mkdir((dir_name + "/b").c_str(), 0755)); ASSERT_EQ(0, mkdir((dir_name + "/c").c_str(), 0755)); string expected_paths_arr[] = { "", "/a", "/b", "/c" }; set expected_paths(expected_paths_arr, expected_paths_arr + arraysize(expected_paths_arr)); FilesystemIterator iter(dir_name, set()); while (!iter.IsEnd()) { string path = iter.GetPartialPath(); EXPECT_TRUE(expected_paths.find(path) != expected_paths.end()); if (expected_paths.find(path) != expected_paths.end()) { expected_paths.erase(path); } if (path == "/a") { EXPECT_EQ(0, rmdir(sub_sub_dir_name.c_str())); EXPECT_EQ(0, rmdir(sub_dir_name.c_str())); } iter.Increment(); } EXPECT_FALSE(iter.IsErr()); EXPECT_TRUE(expected_paths.empty()); } } // namespace chromeos_update_engine