blob: d2c9c78ab183c677cc293e4a4bcbe901776420a5 [file] [log] [blame]
// Copyright (c) 2013 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 "posix_translation/pepper_file.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "common/process_emulator.h"
#include "gtest/gtest.h"
#include "posix_translation/dir.h"
#include "posix_translation/file_system_handler.h"
#include "posix_translation/test_util/file_system_background_test_common.h"
#include "posix_translation/virtual_file_system.h"
#include "ppapi/utility/completion_callback_factory.h"
#include "ppapi_mocks/background_test.h"
#include "ppapi_mocks/background_thread.h"
#include "ppapi_mocks/ppapi_test.h"
#include "ppapi_mocks/ppb_file_io.h"
#include "ppapi_mocks/ppb_file_io_private.h"
#include "ppapi_mocks/ppb_file_ref.h"
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::SetArgPointee;
using ::testing::StrEq;
using ::testing::WithArgs;
namespace posix_translation {
class PepperFileTest : public FileSystemBackgroundTestCommon<PepperFileTest> {
public:
DECLARE_BACKGROUND_TEST(TestAccess);
DECLARE_BACKGROUND_TEST(TestAccessDirectory);
DECLARE_BACKGROUND_TEST(TestAccessFail);
DECLARE_BACKGROUND_TEST(TestFstat);
DECLARE_BACKGROUND_TEST(TestFtruncateReadonly);
DECLARE_BACKGROUND_TEST(TestMkdir);
DECLARE_BACKGROUND_TEST(TestMkdirFail);
DECLARE_BACKGROUND_TEST(TestMkdirNoPermission);
DECLARE_BACKGROUND_TEST(TestOpenAppend);
DECLARE_BACKGROUND_TEST(TestOpenCreat);
DECLARE_BACKGROUND_TEST(TestOpenCreatExclusive);
DECLARE_BACKGROUND_TEST(TestOpenCreatTruncate);
DECLARE_BACKGROUND_TEST(TestOpenCreatWriteOnly);
DECLARE_BACKGROUND_TEST(TestOpenDirectory);
DECLARE_BACKGROUND_TEST(TestOpenDirectoryWithWriteAccess);
DECLARE_BACKGROUND_TEST(TestOpenClose);
DECLARE_BACKGROUND_TEST(TestOpenExclusiveFail);
DECLARE_BACKGROUND_TEST(TestOpenNoentFail);
DECLARE_BACKGROUND_TEST(TestOpenPermFail);
DECLARE_BACKGROUND_TEST(TestOpenRead);
DECLARE_BACKGROUND_TEST(TestOpenWithOpenDirectoryFlag);
DECLARE_BACKGROUND_TEST(TestPacketCalls);
DECLARE_BACKGROUND_TEST(TestRename);
DECLARE_BACKGROUND_TEST(TestRenameInode);
DECLARE_BACKGROUND_TEST(TestRenameInode2);
DECLARE_BACKGROUND_TEST(TestRenameDirectoryCached);
DECLARE_BACKGROUND_TEST(TestRenameEnoentFail);
DECLARE_BACKGROUND_TEST(TestRenameEisdirFail);
DECLARE_BACKGROUND_TEST(TestRequestHandleFail);
DECLARE_BACKGROUND_TEST(TestStat);
DECLARE_BACKGROUND_TEST(TestStatCache);
DECLARE_BACKGROUND_TEST(TestStatCacheDisabled);
DECLARE_BACKGROUND_TEST(TestStatCacheInvalidation);
DECLARE_BACKGROUND_TEST(TestStatCacheWithTrailingSlash);
DECLARE_BACKGROUND_TEST(TestStatDirectory);
DECLARE_BACKGROUND_TEST(TestStatWithENOENT);
DECLARE_BACKGROUND_TEST(TestTruncate);
DECLARE_BACKGROUND_TEST(TestTruncateFail);
DECLARE_BACKGROUND_TEST(TestUTime);
DECLARE_BACKGROUND_TEST(TestUTimeFail);
DECLARE_BACKGROUND_TEST(TestUnlink);
DECLARE_BACKGROUND_TEST(TestUnlinkFail);
protected:
static const PP_Resource kFileRefResource = 74;
static const PP_Resource kFileRefResource2 = 75;
static const PP_Resource kFileIOResource = 76;
PepperFileTest()
: default_executor_(&bg_, PP_OK),
ppb_file_io_(NULL),
ppb_file_io_private_(NULL),
ppb_file_ref_(NULL) {
}
virtual void SetUp() OVERRIDE;
void SetUpOpenExpectations(
const char* path,
int native_flags,
CompletionCallbackExecutor* open_callback_executor,
CompletionCallbackExecutor* request_handle__callback_executor,
CompletionCallbackExecutor* query_callback_executor,
const PP_FileInfo& file_info);
void SetUpStatExpectations(
CompletionCallbackExecutor* callback_executor,
const PP_FileInfo& file_info);
void SetUpFtruncateExpectations(
CompletionCallbackExecutor* callback_executor,
off64_t length);
void SetUpMkdirExpectations(const char* path,
CompletionCallbackExecutor* callback_executor);
void SetUpRenameExpectations(const char* oldpath,
const char* newpath,
CompletionCallbackExecutor* callback_executor);
void SetUpUnlinkExpectations(const char* path,
CompletionCallbackExecutor* callback_executor);
void SetUpUTimeExpectations(const char* path,
time_t time,
CompletionCallbackExecutor* callback_executor);
void SetUpNoFileRefExpectations(
CompletionCallbackExecutor* callback_executor,
const PP_FileInfo& file_info);
scoped_refptr<FileStream> OpenFile(int oflag);
scoped_refptr<FileStream> OpenFileWithExpectations(int flags);
bool IsDirectory(scoped_refptr<FileStream> file);
void CheckStatStructure(const struct stat& st,
mode_t mode,
nlink_t link,
off64_t size,
ino_t inode,
time_t ctime,
time_t atime,
time_t mtime);
void DisableCache();
static int ConvertNativeOpenFlagsToPepper(int native_flags) {
return PepperFileHandler::ConvertNativeOpenFlagsToPepper(native_flags);
}
static int ConvertPepperErrorToErrno(int pp_error) {
return PepperFileHandler::ConvertPepperErrorToErrno(pp_error);
}
static const char kPepperPath[];
static const char kAnotherPepperPath[];
static const char kPepperOldDir[];
static const char kPepperNewDir[];
static const char kPepperPathNewDir[];
static const time_t kTime;
CompletionCallbackExecutor default_executor_;
NiceMock<PPB_FileIO_Mock>* ppb_file_io_;
NiceMock<PPB_FileIO_Private_Mock>* ppb_file_io_private_;
NiceMock<PPB_FileRef_Mock>* ppb_file_ref_;
scoped_ptr<PepperFileHandler> handler_;
};
#define EXPECT_ERROR(result, expected_error) \
EXPECT_EQ(-1, result); \
EXPECT_EQ(expected_error, errno); \
errno = 0;
const char PepperFileTest::kPepperPath[] = "/old/pepperfs.file";
const char PepperFileTest::kAnotherPepperPath[] = "/old/another.pepperfs.file";
const char PepperFileTest::kPepperOldDir[] = "/old";
const char PepperFileTest::kPepperNewDir[] = "/new";
const char PepperFileTest::kPepperPathNewDir[] = "/new/pepperfs.file";
const time_t PepperFileTest::kTime = 1355707320;
void PepperFileTest::SetUp() {
FileSystemBackgroundTestCommon<PepperFileTest>::SetUp();
factory_.GetMock(&ppb_file_io_);
factory_.GetMock(&ppb_file_io_private_);
factory_.GetMock(&ppb_file_ref_);
SetUpPepperFileSystemConstructExpectations(kInstanceNumber);
handler_.reset(new PepperFileHandler);
handler_->OpenPepperFileSystem(instance_.get());
RunCompletionCallbacks();
}
void PepperFileTest::SetUpOpenExpectations(
const char* path,
int native_flags,
CompletionCallbackExecutor* open_callback_executor,
CompletionCallbackExecutor* request_handle_callback_executor,
CompletionCallbackExecutor* query_callback_executor,
const PP_FileInfo& file_info) {
const int pepper_flags = ConvertNativeOpenFlagsToPepper(native_flags);
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(path))).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_io_, Create(kInstanceNumber)).
WillOnce(Return(kFileIOResource));
// Note that kFileIOResource is not released until close() is called.
EXPECT_CALL(*ppb_file_io_, Open(kFileIOResource,
kFileRefResource,
pepper_flags,
_)).
WillOnce(WithArgs<3>(
Invoke(open_callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread)));
if (open_callback_executor->final_result() == PP_OK) {
int handle = -1;
if (request_handle_callback_executor->final_result() == PP_OK)
handle = dup(0);
EXPECT_CALL(*ppb_file_io_private_,
RequestOSFileHandle(kFileIOResource, _, _)).
WillOnce(DoAll(
SetArgPointee<1>(handle),
WithArgs<2>(Invoke(
request_handle_callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread)))).
RetiresOnSaturation();
}
}
void PepperFileTest::SetUpStatExpectations(
CompletionCallbackExecutor* callback_executor,
const PP_FileInfo& file_info) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, _)).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_, Query(kFileRefResource,
_,
_)).
WillOnce(DoAll(
SetArgPointee<1>(file_info),
WithArgs<2>(Invoke(
callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread)))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpFtruncateExpectations(
CompletionCallbackExecutor* callback_executor,
off64_t length) {
EXPECT_CALL(*ppb_file_io_, SetLength(kFileIOResource,
length,
_)).
WillOnce(WithArgs<2>(Invoke(
callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpMkdirExpectations(
const char* path, CompletionCallbackExecutor* callback_executor) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(path))).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_,
MakeDirectory(kFileRefResource,
PP_MAKEDIRECTORYFLAG_EXCLUSIVE,
_)).
WillOnce(WithArgs<2>(
Invoke(callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpRenameExpectations(
const char* oldpath,
const char* newpath,
CompletionCallbackExecutor* callback_executor) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(oldpath))).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(newpath))).
WillOnce(Return(kFileRefResource2));
EXPECT_CALL(*ppb_file_ref_,
Rename(kFileRefResource, kFileRefResource2, _)).
WillOnce(WithArgs<2>(
Invoke(callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpUnlinkExpectations(
const char* path, CompletionCallbackExecutor* callback_executor) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(path))).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_, Delete(kFileRefResource, _)).
WillOnce(WithArgs<1>(
Invoke(callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpUTimeExpectations(
const char* path,
time_t time,
CompletionCallbackExecutor* callback_executor) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, StrEq(path))).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_, Touch(kFileRefResource, time, time, _)).
WillOnce(WithArgs<3>(
Invoke(callback_executor,
&CompletionCallbackExecutor::ExecuteOnMainThread))).
RetiresOnSaturation();
}
void PepperFileTest::SetUpNoFileRefExpectations(
CompletionCallbackExecutor* callback_executor,
const PP_FileInfo& file_info) {
EXPECT_CALL(*ppb_file_ref_, Create(kFileSystemResource, _)).
WillOnce(Return(kFileRefResource));
EXPECT_CALL(*ppb_file_ref_, Query(kFileRefResource,
_,
_)).
WillOnce(Return(PP_ERROR_FAILED)).
RetiresOnSaturation();
}
scoped_refptr<FileStream> PepperFileTest::OpenFile(int oflag) {
int fd = file_system_->fd_to_stream_->GetFirstUnusedDescriptor();
return handler_->open(fd, kPepperPath, oflag, 0);
}
scoped_refptr<FileStream> PepperFileTest::OpenFileWithExpectations(
int open_flags) {
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, open_flags,
&default_executor_, &default_executor_,
&default_executor_, file_info);
return OpenFile(open_flags);
}
bool PepperFileTest::IsDirectory(scoped_refptr<FileStream> file) {
if (!file) {
ADD_FAILURE() << "No file stream";
return false;
}
return strcmp(file->GetStreamType(), "pepper") != 0;
}
void PepperFileTest::CheckStatStructure(const struct stat& st,
mode_t mode,
nlink_t link,
off64_t size,
ino_t inode,
time_t ctime,
time_t atime,
time_t mtime) {
EXPECT_EQ(static_cast<dev_t>(0), st.st_dev);
EXPECT_EQ(inode, st.st_ino);
// PepperFile does not set permission bits, relying VirtualFileSystem.
EXPECT_EQ(mode, st.st_mode);
EXPECT_EQ(link, st.st_nlink);
// UID and GID must not be set in FileSystemHandler.
EXPECT_EQ(arc::kRootUid, st.st_uid);
EXPECT_EQ(arc::kRootGid, st.st_gid);
EXPECT_EQ(static_cast<dev_t>(0), st.st_rdev);
// Sanity check of the sizes.
EXPECT_EQ(sizeof(size), sizeof(st.st_size));
EXPECT_EQ(size, st.st_size);
EXPECT_EQ(static_cast<blksize_t>(4096), st.st_blksize);
EXPECT_EQ(static_cast<blkcnt_t>(0), st.st_blocks);
// We casts st_[cam]time for bionic. In bionic, their type is
// unsigned long and time_t is long.
EXPECT_EQ(ctime, static_cast<time_t>(st.st_ctime));
EXPECT_EQ(atime, static_cast<time_t>(st.st_atime));
EXPECT_EQ(mtime, static_cast<time_t>(st.st_mtime));
}
void PepperFileTest::DisableCache() {
handler_->DisableCacheForTesting();
}
TEST_F(PepperFileTest, ConstructPendingDestruct) {
// Just tests that the initialization that runs in SetUp() itself
// succeeds.
}
TEST_F(PepperFileTest, TestConvertNativeOpenFlagsToPepper) {
EXPECT_EQ(PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_WRONLY));
EXPECT_EQ(PP_FILEOPENFLAG_READ,
ConvertNativeOpenFlagsToPepper(O_RDONLY));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR));
// Unknown flag should be treated as O_RDONLY.
EXPECT_EQ(PP_FILEOPENFLAG_READ,
ConvertNativeOpenFlagsToPepper(O_ACCMODE));
// _WRITE and _APPEND flags are exclusive in Pepper.
EXPECT_EQ(PP_FILEOPENFLAG_APPEND,
ConvertNativeOpenFlagsToPepper(O_WRONLY | O_APPEND));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_APPEND,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_APPEND));
// O_RDONLY | O_APPEND is an error. O_APPEND should be ignored.
EXPECT_EQ(PP_FILEOPENFLAG_READ,
ConvertNativeOpenFlagsToPepper(O_RDONLY | O_APPEND));
// Test misc flags.
EXPECT_EQ(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE,
ConvertNativeOpenFlagsToPepper(O_WRONLY | O_CREAT));
EXPECT_EQ(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
PP_FILEOPENFLAG_EXCLUSIVE,
ConvertNativeOpenFlagsToPepper(O_WRONLY | O_CREAT | O_EXCL));
EXPECT_EQ(PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_TRUNCATE,
ConvertNativeOpenFlagsToPepper(O_WRONLY | O_TRUNC));
// Test unsupported flags.
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_NOCTTY));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_NONBLOCK));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_SYNC));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_ASYNC));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_NOFOLLOW));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_CLOEXEC));
EXPECT_EQ(PP_FILEOPENFLAG_READ | PP_FILEOPENFLAG_WRITE,
ConvertNativeOpenFlagsToPepper(O_RDWR | O_NOATIME));
}
TEST_F(PepperFileTest, TestConvertPepperErrorToErrno) {
EXPECT_EQ(ENOENT, ConvertPepperErrorToErrno(PP_ERROR_FILENOTFOUND));
EXPECT_EQ(EEXIST, ConvertPepperErrorToErrno(PP_ERROR_FILEEXISTS));
EXPECT_EQ(EPERM, ConvertPepperErrorToErrno(PP_ERROR_NOACCESS));
EXPECT_EQ(ENOMEM, ConvertPepperErrorToErrno(PP_ERROR_NOMEMORY));
EXPECT_EQ(ENOSPC, ConvertPepperErrorToErrno(PP_ERROR_NOQUOTA));
EXPECT_EQ(ENOSPC, ConvertPepperErrorToErrno(PP_ERROR_NOSPACE));
EXPECT_EQ(EISDIR, ConvertPepperErrorToErrno(PP_ERROR_NOTAFILE));
// We use ENOENT for all other error code.
EXPECT_EQ(ENOENT, ConvertPepperErrorToErrno(PP_ERROR_FAILED));
EXPECT_EQ(ENOENT, ConvertPepperErrorToErrno(PP_ERROR_USERCANCEL));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenRead) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDONLY));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenCreat) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDWR | O_CREAT));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenCreatExclusive) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(
OpenFileWithExpectations(O_RDWR | O_CREAT | O_EXCL));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenCreatTruncate) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(
OpenFileWithExpectations(O_RDWR | O_CREAT | O_TRUNC));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenCreatWriteOnly) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(
OpenFileWithExpectations(O_WRONLY | O_CREAT));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenAppend) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(
OpenFileWithExpectations(O_RDWR | O_APPEND));
EXPECT_TRUE(file.get());
EXPECT_FALSE(IsDirectory(file));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenWithOpenDirectoryFlag) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
const int flags = O_RDONLY | O_DIRECTORY;
SetUpOpenExpectations(kPepperPath, flags,
&default_executor_, &default_executor_,
&default_executor_, file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_FALSE(file.get());
EXPECT_EQ(ENOTDIR, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenDirectory) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_NOTAFILE);
PP_FileInfo file_info = {};
int flags = O_RDONLY;
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_TRUE(file.get());
EXPECT_TRUE(IsDirectory(file));
flags = O_RDONLY | O_DIRECTORY;
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file2(OpenFile(flags));
EXPECT_TRUE(file2.get());
EXPECT_TRUE(IsDirectory(file2));
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenDirectoryWithWriteAccess) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_NOTAFILE);
PP_FileInfo file_info = {};
int flags = O_RDWR;
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_FALSE(file.get());
EXPECT_EQ(EISDIR, errno);
flags = O_WRONLY;
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file2(OpenFile(flags));
EXPECT_FALSE(file2.get());
EXPECT_EQ(EISDIR, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenNoentFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND);
int flags = O_RDONLY;
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_FALSE(file.get());
EXPECT_EQ(ENOENT, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenPermFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_NOACCESS);
int flags = O_RDWR | O_CREAT;
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file2(OpenFile(flags));
EXPECT_FALSE(file2.get());
EXPECT_EQ(EPERM, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenExclusiveFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILEEXISTS);
int flags = O_WRONLY | O_CREAT | O_EXCL;
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, flags,
&executor, &default_executor_, &default_executor_,
file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_FALSE(file.get());
EXPECT_EQ(EEXIST, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestRequestHandleFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor request_handle_executor(&bg_, PP_ERROR_NOACCESS);
int flags = O_WRONLY | O_CREAT;
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, flags,
&default_executor_, &request_handle_executor,
&default_executor_, file_info);
scoped_refptr<FileStream> file(OpenFile(flags));
EXPECT_FALSE(file.get());
EXPECT_EQ(EPERM, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestOpenClose) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDWR | O_CREAT));
EXPECT_TRUE(file.get());
}
TEST_BACKGROUND_F(PepperFileTest, TestFstat) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDONLY));
EXPECT_TRUE(file.get());
struct stat st;
memset(&st, 1, sizeof(st));
// Call fstat just to make sure it does not crash.
EXPECT_EQ(0, file->fstat(&st));
}
TEST_BACKGROUND_F(PepperFileTest, TestRenameDirectoryCached) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
SetUpNoFileRefExpectations(&default_executor_, file_info);
struct stat st;
EXPECT_EQ(-1, handler_->stat(kPepperPathNewDir, &st));
EXPECT_EQ(-1, handler_->stat(kPepperPathNewDir, &st)); // cache hit
SetUpRenameExpectations(kPepperOldDir, kPepperNewDir, &default_executor_);
EXPECT_EQ(0, handler_->rename(kPepperOldDir, kPepperNewDir));
// Expect to be called since cache should be invalidated by previous rename.
SetUpStatExpectations(&default_executor_, file_info);
EXPECT_EQ(0, handler_->stat(kPepperPathNewDir, &st));
}
TEST_BACKGROUND_F(PepperFileTest, TestStat) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
const off64_t kSize = 0xdeadbeef;
file_info.size = kSize;
file_info.type = PP_FILETYPE_REGULAR;
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
SCOPED_TRACE("TestStat");
CheckStatStructure(st, S_IFREG, 1, kSize, GetInode(kPepperPath), 0, 0, 0);
}
TEST_BACKGROUND_F(PepperFileTest, TestStatDirectory) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
file_info.type = PP_FILETYPE_DIRECTORY;
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
SCOPED_TRACE("TestStatDirectory");
CheckStatStructure(st, S_IFDIR, 32, 4096, GetInode(kPepperPath), 0, 0, 0);
}
TEST_BACKGROUND_F(PepperFileTest, TestMkdir) {
base::AutoLock lock(file_system_->mutex());
const mode_t mode = 0777;
SetUpMkdirExpectations(kPepperPath, &default_executor_);
EXPECT_EQ(0, handler_->mkdir(kPepperPath, mode));
}
TEST_BACKGROUND_F(PepperFileTest, TestMkdirFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FAILED);
const mode_t mode = 0777;
SetUpMkdirExpectations(kPepperPath, &executor);
EXPECT_EQ(-1, handler_->mkdir(kPepperPath, mode));
EXPECT_EQ(ENOENT, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestMkdirNoPermission) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_NOACCESS);
const mode_t mode = 0777;
SetUpMkdirExpectations(kPepperPath, &executor);
EXPECT_EQ(-1, handler_->mkdir(kPepperPath, mode));
EXPECT_EQ(EPERM, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestRename) {
base::AutoLock lock(file_system_->mutex());
SetUpRenameExpectations(kPepperPath, kAnotherPepperPath, &default_executor_);
EXPECT_EQ(0, handler_->rename(kPepperPath, kAnotherPepperPath));
}
TEST_BACKGROUND_F(PepperFileTest, TestRenameInode) {
base::AutoLock lock(file_system_->mutex());
static const ino_t zero_ino = 0;
PP_FileInfo file_info = {};
file_info.size = 0xdeadbeef;
file_info.type = PP_FILETYPE_REGULAR;
// Assign inode for |kPepperPath| by calling stat().
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
const ino_t orig_ino = st.st_ino;
EXPECT_NE(zero_ino, orig_ino);
// Call rename().
SetUpRenameExpectations(kPepperPath, kAnotherPepperPath, &default_executor_);
EXPECT_EQ(0, handler_->rename(kPepperPath, kAnotherPepperPath));
// Call stat() against |kAnotherPepperPath| to confirm st_ino is the same.
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kAnotherPepperPath, &st));
EXPECT_EQ(orig_ino, st.st_ino);
}
TEST_BACKGROUND_F(PepperFileTest, TestRenameInode2) {
base::AutoLock lock(file_system_->mutex());
static const ino_t zero_ino = 0;
PP_FileInfo file_info = {};
file_info.size = 0xdeadbeef;
file_info.type = PP_FILETYPE_REGULAR;
// Assign inode for |kAnotherPepperPath| by calling stat().
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kAnotherPepperPath, &st));
const ino_t orig_ino = st.st_ino;
EXPECT_NE(zero_ino, orig_ino);
// Call rename().
SetUpRenameExpectations(kPepperPath, kAnotherPepperPath, &default_executor_);
EXPECT_EQ(0, handler_->rename(kPepperPath, kAnotherPepperPath));
// Call stat() against |kAnotherPepperPath| again to confirm st_ino is NOT
// the same.
SetUpStatExpectations(&default_executor_, file_info);
memset(&st, 1, sizeof(st));
EXPECT_EQ(0, handler_->stat(kAnotherPepperPath, &st));
EXPECT_NE(orig_ino, st.st_ino);
}
TEST_BACKGROUND_F(PepperFileTest, TestRenameEnoentFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND);
SetUpRenameExpectations(kPepperPath, kAnotherPepperPath, &executor);
EXPECT_EQ(-1, handler_->rename(kPepperPath, kAnotherPepperPath));
EXPECT_EQ(ENOENT, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestRenameEisdirFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_NOTAFILE);
SetUpRenameExpectations(kPepperPath, kAnotherPepperPath, &executor);
EXPECT_EQ(-1, handler_->rename(kPepperPath, kAnotherPepperPath));
EXPECT_EQ(EISDIR, errno);
}
TEST_BACKGROUND_F(PepperFileTest, TestUnlink) {
base::AutoLock lock(file_system_->mutex());
ino_t inode = GetInode(kPepperPath);
SetUpUnlinkExpectations(kPepperPath, &default_executor_);
EXPECT_EQ(0, handler_->unlink(kPepperPath));
EXPECT_NE(inode, GetInode(kPepperPath));
}
TEST_BACKGROUND_F(PepperFileTest, TestUnlinkFail) {
base::AutoLock lock(file_system_->mutex());
{
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND);
SetUpUnlinkExpectations(kPepperPath, &executor);
EXPECT_ERROR(handler_->unlink(kPepperPath), ENOENT);
}
{
// If you try to delete a non-empty directory, the API returns with
// PP_ERROR_FAILED.
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FAILED);
SetUpUnlinkExpectations(kPepperPath, &executor);
EXPECT_ERROR(handler_->unlink(kPepperPath), EISDIR);
}
}
TEST_BACKGROUND_F(PepperFileTest, TestUTime) {
base::AutoLock lock(file_system_->mutex());
SetUpUTimeExpectations(kPepperPath, kTime, &default_executor_);
{
struct timeval times[2];
times[0].tv_sec = kTime;
times[0].tv_usec = 0;
times[1].tv_sec = kTime;
times[1].tv_usec = 0;
EXPECT_EQ(0, handler_->utimes(kPepperPath, times));
}
}
TEST_BACKGROUND_F(PepperFileTest, TestUTimeFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND);
SetUpUTimeExpectations(kPepperPath, kTime, &executor);
{
struct timeval times[2];
times[0].tv_sec = kTime;
times[0].tv_usec = 0;
times[1].tv_sec = kTime;
times[1].tv_usec = 0;
EXPECT_ERROR(handler_->utimes(kPepperPath, times), ENOENT);
}
}
TEST_BACKGROUND_F(PepperFileTest, TestStatCache) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
SetUpStatExpectations(&default_executor_, file_info);
// StatExpectations expect the underlying calls that stat call to be
// called exactly once.
struct stat st;
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
}
TEST_BACKGROUND_F(PepperFileTest, TestStatCacheDisabled) {
base::AutoLock lock(file_system_->mutex());
DisableCache();
PP_FileInfo file_info = {};
struct stat st;
// Confirm Pepper's stat() is called twice when the cache is disabled.
SetUpStatExpectations(&default_executor_, file_info);
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
SetUpStatExpectations(&default_executor_, file_info);
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
}
TEST_BACKGROUND_F(PepperFileTest, TestStatCacheWithTrailingSlash) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
EXPECT_EQ(0, handler_->stat("/dir", &st));
// Check if pepper_file.cc automatically remove the trailing / when
// accessing the cache.
EXPECT_EQ(0, handler_->stat("/dir/", &st));
}
TEST_BACKGROUND_F(PepperFileTest, TestStatCacheInvalidation) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
SetUpStatExpectations(&default_executor_, file_info);
struct stat st;
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
// Now call utimes to invalidate the cache.
SetUpUTimeExpectations(kPepperPath, kTime, &default_executor_);
{
struct timeval times[2];
times[0].tv_sec = kTime;
times[0].tv_usec = 0;
times[1].tv_sec = kTime;
times[1].tv_usec = 0;
EXPECT_EQ(0, handler_->utimes(kPepperPath, times));
}
SetUpStatExpectations(&default_executor_, file_info);
// StatExpectations expect the underlying calls that stat call to be
// called exactly once.
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
EXPECT_EQ(0, handler_->stat(kPepperPath, &st));
}
TEST_BACKGROUND_F(PepperFileTest, TestStatWithENOENT) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND); // ENOENT
PP_FileInfo file_info = {};
SetUpStatExpectations(&executor, file_info);
struct stat st;
EXPECT_EQ(-1, handler_->stat(kPepperPath, &st));
EXPECT_EQ(ENOENT, errno);
// The following stat, open, rename, truncate, unlink, and utimes
// calls should not call into Pepper since the initial stat call above
// returned ENOENT.
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(-1, handler_->stat(kPepperPath, &st));
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(NULL, handler_->open(-1, kPepperPath, O_RDONLY, 0).get());
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(NULL, handler_->open(-1, kPepperPath, O_WRONLY, 0).get());
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(NULL, handler_->open(-1, kPepperPath, O_RDWR, 0).get());
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(-1, handler_->rename(kPepperPath, "/abc"));
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(-1, handler_->truncate(kPepperPath, 0));
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ(-1, handler_->unlink(kPepperPath));
EXPECT_EQ(ENOENT, errno);
{
struct timeval times[2];
times[0].tv_sec = kTime;
times[0].tv_usec = 0;
times[1].tv_sec = kTime;
times[1].tv_usec = 0;
EXPECT_EQ(-1, handler_->utimes(kPepperPath, times));
EXPECT_EQ(ENOENT, errno);
}
// However, open() with O_CREAT should ignore the cache.
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_WRONLY | O_CREAT));
EXPECT_TRUE(file.get());
}
TEST_BACKGROUND_F(PepperFileTest, TestTruncate) {
base::AutoLock lock(file_system_->mutex());
PP_FileInfo file_info = {};
// Truncate is just an open, ftruncate, and close.
SetUpOpenExpectations(kPepperPath, O_WRONLY,
&default_executor_, &default_executor_,
&default_executor_, file_info);
off64_t length = 0;
SetUpFtruncateExpectations(&default_executor_, length);
EXPECT_EQ(0, handler_->truncate(kPepperPath, length));
// Do the same with non-zero |length|.
SetUpOpenExpectations(kPepperPath, O_WRONLY,
&default_executor_, &default_executor_,
&default_executor_, file_info);
length = 12345;
SetUpFtruncateExpectations(&default_executor_, length);
EXPECT_EQ(0, handler_->truncate(kPepperPath, length));
}
TEST_BACKGROUND_F(PepperFileTest, TestTruncateFail) {
base::AutoLock lock(file_system_->mutex());
CompletionCallbackExecutor executor(&bg_, PP_ERROR_FILENOTFOUND);
PP_FileInfo file_info = {};
SetUpOpenExpectations(kPepperPath, O_WRONLY,
&executor, &default_executor_, &default_executor_,
file_info);
EXPECT_ERROR(handler_->truncate(kPepperPath, 0), ENOENT);
CompletionCallbackExecutor executor2(&bg_, PP_ERROR_NOTAFILE);
SetUpOpenExpectations(kPepperPath, O_WRONLY,
&executor2, &default_executor_, &default_executor_,
file_info);
EXPECT_ERROR(handler_->truncate(kPepperPath, 0), EISDIR);
}
TEST_BACKGROUND_F(PepperFileTest, TestFtruncateReadonly) {
base::AutoLock lock(file_system_->mutex());
// Can not call truncate() against a read-only fd.
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDONLY));
EXPECT_TRUE(file.get());
EXPECT_ERROR(file->ftruncate(0), EBADF);
}
TEST_BACKGROUND_F(PepperFileTest, TestPacketCalls) {
base::AutoLock lock(file_system_->mutex());
scoped_refptr<FileStream> file(OpenFileWithExpectations(O_RDWR | O_CREAT));
char buf[1];
EXPECT_ERROR(file->recv(buf, 1, 0), ENOTSOCK);
EXPECT_ERROR(file->recvfrom(buf, 1, 0, NULL, NULL), ENOTSOCK);
EXPECT_ERROR(file->send(buf, 1, 0), ENOTSOCK);
EXPECT_ERROR(file->sendto(buf, 1, 0, NULL, 0), ENOTSOCK);
}
} // namespace posix_translation