blob: 9ade2af2bb27e2ab43a75207fc02353e1e65651d [file] [log] [blame]
/**
* Copyright 2010 Google Inc.
*
* 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.
*/
// Author: jmarantz@google.com (Joshua Marantz)
#include <unistd.h>
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "net/instaweb/util/public/file_system_test.h"
#include "net/instaweb/util/public/google_message_handler.h"
#include <string>
#include "net/instaweb/util/public/gtest.h"
namespace net_instaweb {
FileSystemTest::FileSystemTest() { }
FileSystemTest::~FileSystemTest() { }
std::string FileSystemTest::WriteNewFile(const StringPiece& suffix,
const std::string& content) {
std::string filename = StrCat(test_tmpdir(), suffix);
// Make sure we don't read an old file.
DeleteRecursively(filename);
EXPECT_TRUE(file_system()->WriteFile(filename.c_str(), content, &handler_));
return filename;
}
// Check that a file has been read.
void FileSystemTest::CheckRead(const std::string& filename,
const std::string& expected_contents) {
std::string buffer;
ASSERT_TRUE(file_system()->ReadFile(filename.c_str(), &buffer, &handler_));
EXPECT_EQ(buffer, expected_contents);
}
// Make sure we can no longer read the file by the old name. Note
// that this will spew some error messages into the log file, and
// we can add a null_message_handler implementation to
// swallow them, if they become annoying.
void FileSystemTest::CheckDoesNotExist(const std::string& filename) {
std::string read_buffer;
EXPECT_FALSE(file_system()->ReadFile(filename.c_str(), &read_buffer,
&handler_));
EXPECT_TRUE(file_system()->Exists(filename.c_str(), &handler_).is_false());
}
// Write a named file, then read it.
void FileSystemTest::TestWriteRead() {
std::string filename = test_tmpdir() + "/write.txt";
std::string msg("Hello, world!");
DeleteRecursively(filename);
FileSystem::OutputFile* ofile = file_system()->OpenOutputFile(
filename.c_str(), &handler_);
ASSERT_TRUE(ofile != NULL);
EXPECT_TRUE(ofile->Write(msg, &handler_));
EXPECT_TRUE(file_system()->Close(ofile, &handler_));
CheckRead(filename, msg);
}
// Write a temp file, then read it.
void FileSystemTest::TestTemp() {
std::string prefix = test_tmpdir() + "/temp_prefix";
FileSystem::OutputFile* ofile = file_system()->OpenTempFile(
prefix.c_str(), &handler_);
ASSERT_TRUE(ofile != NULL);
std::string filename(ofile->filename());
std::string msg("Hello, world!");
EXPECT_TRUE(ofile->Write(msg, &handler_));
EXPECT_TRUE(file_system()->Close(ofile, &handler_));
CheckRead(filename, msg);
}
// Write a temp file, rename it, then read it.
void FileSystemTest::TestRename() {
std::string from_text = "Now is time time";
std::string to_file = test_tmpdir() + "/to.txt";
DeleteRecursively(to_file);
std::string from_file = WriteNewFile("/from.txt", from_text);
ASSERT_TRUE(file_system()->RenameFile(from_file.c_str(), to_file.c_str(),
&handler_));
CheckDoesNotExist(from_file);
CheckRead(to_file, from_text);
}
// Write a file and successfully delete it.
void FileSystemTest::TestRemove() {
std::string filename = WriteNewFile("/remove.txt", "Goodbye, world!");
ASSERT_TRUE(file_system()->RemoveFile(filename.c_str(), &handler_));
CheckDoesNotExist(filename);
}
// Write a file and check that it exists.
void FileSystemTest::TestExists() {
std::string filename = WriteNewFile("/exists.txt", "I'm here.");
ASSERT_TRUE(file_system()->Exists(filename.c_str(), &handler_).is_true());
}
// Create a file along with its directory which does not exist.
void FileSystemTest::TestCreateFileInDir() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
std::string filename = dir_name + "/file-in-dir.txt";
FileSystem::OutputFile* file =
file_system()->OpenOutputFile(filename.c_str(), &handler_);
ASSERT_TRUE(file);
file_system()->Close(file, &handler_);
}
// Make a directory and check that files may be placed in it.
void FileSystemTest::TestMakeDir() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
std::string filename = dir_name + "/file-in-dir.txt";
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
// ... but we can open a file after we've created the directory.
FileSystem::OutputFile* file =
file_system()->OpenOutputFile(filename.c_str(), &handler_);
ASSERT_TRUE(file);
file_system()->Close(file, &handler_);
}
// Make a directory and check that it is a directory.
void FileSystemTest::TestIsDir() {
std::string dir_name = test_tmpdir() + "/this_is_a_dir";
DeleteRecursively(dir_name);
// Make sure we don't think the directory is there when it isn't ...
ASSERT_TRUE(file_system()->IsDir(dir_name.c_str(), &handler_).is_false());
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
// ... and that we do think it's there when it is.
ASSERT_TRUE(file_system()->IsDir(dir_name.c_str(), &handler_).is_true());
// Make sure that we don't think a regular file is a directory.
std::string filename = dir_name + "/this_is_a_file.txt";
std::string content = "I'm not a directory.";
ASSERT_TRUE(file_system()->WriteFile(filename.c_str(), content, &handler_));
ASSERT_TRUE(file_system()->IsDir(filename.c_str(), &handler_).is_false());
}
// Recursively make directories and check that it worked.
void FileSystemTest::TestRecursivelyMakeDir() {
std::string base = test_tmpdir() + "/base";
std::string long_path = base + "/dir/of/a/really/deep/hierarchy";
DeleteRecursively(base);
// Make sure we don't think the directory is there when it isn't ...
ASSERT_TRUE(file_system()->IsDir(long_path.c_str(), &handler_).is_false());
ASSERT_TRUE(file_system()->RecursivelyMakeDir(long_path, &handler_));
// ... and that we do think it's there when it is.
ASSERT_TRUE(file_system()->IsDir(long_path.c_str(), &handler_).is_true());
}
// Check that we cannot create a directory we do not have permissions for.
// Note: depends upon root dir not being writable.
void FileSystemTest::TestRecursivelyMakeDir_NoPermission() {
std::string base = "/bogus-dir";
std::string path = base + "/no/permission/to/make/this/dir";
// Make sure the bogus bottom level directory is not there.
ASSERT_TRUE(file_system()->Exists(base.c_str(), &handler_).is_false());
// We do not have permission to create it.
ASSERT_FALSE(file_system()->RecursivelyMakeDir(path, &handler_));
}
// Check that we cannot create a directory below a file.
void FileSystemTest::TestRecursivelyMakeDir_FileInPath() {
std::string base = test_tmpdir() + "/file-in-path";
std::string filename = base + "/this-is-a-file";
std::string bad_path = filename + "/some/more/path";
DeleteRecursively(base);
std::string content = "Your path must end here. You shall not pass!";
ASSERT_TRUE(file_system()->MakeDir(base.c_str(), &handler_));
ASSERT_TRUE(file_system()->WriteFile(filename.c_str(), content, &handler_));
ASSERT_FALSE(file_system()->RecursivelyMakeDir(bad_path, &handler_));
}
void FileSystemTest::TestListContents() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
std::string filename1 = dir_name + "/file-in-dir.txt";
std::string filename2 = dir_name + "/another-file-in-dir.txt";
std::string content = "Lorem ipsum dolor sit amet";
StringVector mylist;
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
ASSERT_TRUE(file_system()->WriteFile(filename1.c_str(),
content, &handler_));
ASSERT_TRUE(file_system()->WriteFile(filename2.c_str(),
content, &handler_));
EXPECT_TRUE(file_system()->ListContents(dir_name, &mylist, &handler_));
EXPECT_EQ(size_t(2), mylist.size());
// Make sure our filenames are in there
EXPECT_FALSE(filename1.compare(mylist.at(0))
&& filename1.compare(mylist.at(1)));
EXPECT_FALSE(filename2.compare(mylist.at(0))
&& filename2.compare(mylist.at(1)));
}
void FileSystemTest::TestAtime() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
std::string filename1 = "file-in-dir.txt";
std::string filename2 = "another-file-in-dir.txt";
std::string full_path1 = dir_name + "/" + filename1;
std::string full_path2 = dir_name + "/" + filename2;
std::string content = "Lorem ipsum dolor sit amet";
// We need to sleep a bit between accessing files so that the
// difference shows up in in atimes which are measured in seconds.
unsigned int sleep_micros = 1500000;
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
ASSERT_TRUE(file_system()->WriteFile(full_path1.c_str(),
content, &handler_));
ASSERT_TRUE(file_system()->WriteFile(full_path2.c_str(),
content, &handler_));
int64 atime1, atime2;
CheckRead(full_path1, content);
usleep(sleep_micros);
CheckRead(full_path2, content);
ASSERT_TRUE(file_system()->Atime(full_path1, &atime1, &handler_));
ASSERT_TRUE(file_system()->Atime(full_path2, &atime2, &handler_));
EXPECT_LT(atime1, atime2);
CheckRead(full_path2, content);
usleep(sleep_micros);
CheckRead(full_path1, content);
ASSERT_TRUE(file_system()->Atime(full_path1, &atime1, &handler_));
ASSERT_TRUE(file_system()->Atime(full_path2, &atime2, &handler_));
EXPECT_LT(atime2, atime1);
}
void FileSystemTest::TestSize() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
std::string dir_name2 = dir_name + "/make_dir2";
std::string filename1 = "file-in-dir.txt";
std::string filename2 = "another-file-in-dir.txt";
std::string full_path1 = dir_name2 + "/" + filename1;
std::string full_path2 = dir_name2 + "/" + filename2;
std::string content1 = "12345";
std::string content2 = "1234567890";
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
ASSERT_TRUE(file_system()->MakeDir(dir_name2.c_str(), &handler_));
ASSERT_TRUE(file_system()->WriteFile(full_path1.c_str(),
content1, &handler_));
ASSERT_TRUE(file_system()->WriteFile(full_path2.c_str(),
content2, &handler_));
int64 size;
EXPECT_TRUE(file_system()->Size(full_path1, &size, &handler_));
EXPECT_EQ(content1.size(), size_t(size));
EXPECT_TRUE(file_system()->Size(full_path2, &size, &handler_));
EXPECT_EQ(content2.size(), size_t(size));
size = 0;
EXPECT_TRUE(file_system()->RecursiveDirSize(dir_name2, &size, &handler_));
EXPECT_EQ(content1.size() + content2.size(), size_t(size));
size = 0;
EXPECT_TRUE(file_system()->RecursiveDirSize(dir_name, &size, &handler_));
EXPECT_EQ(content1.size() + content2.size(), size_t(size));
}
void FileSystemTest::TestLock() {
std::string dir_name = test_tmpdir() + "/make_dir";
DeleteRecursively(dir_name);
ASSERT_TRUE(file_system()->MakeDir(dir_name.c_str(), &handler_));
std::string lock_name = dir_name + "/lock";
// Acquire the lock
EXPECT_TRUE(file_system()->TryLock(lock_name, &handler_).is_true());
// Can't re-acquire the lock
EXPECT_TRUE(file_system()->TryLock(lock_name, &handler_).is_false());
// Release the lock
EXPECT_TRUE(file_system()->Unlock(lock_name, &handler_));
// Do it all again to make sure the release worked.
EXPECT_TRUE(file_system()->TryLock(lock_name, &handler_).is_true());
EXPECT_TRUE(file_system()->TryLock(lock_name, &handler_).is_false());
EXPECT_TRUE(file_system()->Unlock(lock_name, &handler_));
}
} // namespace net_instaweb