summaryrefslogtreecommitdiffstats
path: root/webkit/fileapi
diff options
context:
space:
mode:
authorkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-09 17:42:10 +0000
committerkinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-09 17:42:10 +0000
commitc4e6f9ca783c3959ae4730376723a6f0064ce783 (patch)
treea23d35c4131d5785fea0627285ce35066005cc2c /webkit/fileapi
parent36e2f42527f6b556045f44a0782dea1a04465763 (diff)
downloadchromium_src-c4e6f9ca783c3959ae4730376723a6f0064ce783.zip
chromium_src-c4e6f9ca783c3959ae4730376723a6f0064ce783.tar.gz
chromium_src-c4e6f9ca783c3959ae4730376723a6f0064ce783.tar.bz2
Add FileChangeObserver to track changes in local file system
BUG=146290,146317 TEST=LocalFileSystemOperationTest.*, ObfuscatedFileUtilTest.* Review URL: https://chromiumcodereview.appspot.com/10909060 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@155632 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
-rw-r--r--webkit/fileapi/file_observers.h19
-rw-r--r--webkit/fileapi/file_system_operation_context.h6
-rw-r--r--webkit/fileapi/local_file_system_operation.h8
-rw-r--r--webkit/fileapi/local_file_system_operation_unittest.cc106
-rw-r--r--webkit/fileapi/mock_file_change_observer.cc52
-rw-r--r--webkit/fileapi/mock_file_change_observer.h103
-rw-r--r--webkit/fileapi/obfuscated_file_util.cc45
-rw-r--r--webkit/fileapi/obfuscated_file_util_unittest.cc70
-rw-r--r--webkit/fileapi/task_runner_bound_observer_list.h2
9 files changed, 403 insertions, 8 deletions
diff --git a/webkit/fileapi/file_observers.h b/webkit/fileapi/file_observers.h
index 2022b81..8b64161 100644
--- a/webkit/fileapi/file_observers.h
+++ b/webkit/fileapi/file_observers.h
@@ -46,6 +46,25 @@ class FILEAPI_EXPORT FileAccessObserver {
virtual void OnAccess(const FileSystemURL& url) = 0;
};
+// An abstract interface to observe file changes.
+// Each method of this class is called once per file/directory is created,
+// removed or modified. For recursive operations each method is called for
+// each subdirectory/subfile. Currently ChangeObserver is only supported
+// by the local sandbox file system.
+class FILEAPI_EXPORT FileChangeObserver {
+ public:
+ virtual ~FileChangeObserver() {}
+
+ virtual void OnCreateFile(const FileSystemURL& url) = 0;
+ virtual void OnCreateFileFrom(const FileSystemURL& url,
+ const FileSystemURL& src) = 0;
+ virtual void OnRemoveFile(const FileSystemURL& url) = 0;
+ virtual void OnModifyFile(const FileSystemURL& url) = 0;
+
+ virtual void OnCreateDirectory(const FileSystemURL& url) = 0;
+ virtual void OnRemoveDirectory(const FileSystemURL& url) = 0;
+};
+
} // namespace fileapi
#endif // WEBKIT_FILEAPI_FILE_OBSERVERS_H_
diff --git a/webkit/fileapi/file_system_operation_context.h b/webkit/fileapi/file_system_operation_context.h
index f1dbda2..89b109c 100644
--- a/webkit/fileapi/file_system_operation_context.h
+++ b/webkit/fileapi/file_system_operation_context.h
@@ -65,6 +65,11 @@ class FILEAPI_EXPORT_PRIVATE FileSystemOperationContext {
return media_path_filter_;
}
+ void set_change_observers(const ChangeObserverList& list) {
+ change_observers_ = list;
+ }
+ ChangeObserverList* change_observers() { return &change_observers_; }
+
void set_access_observers(const AccessObserverList& list) {
access_observers_ = list;
}
@@ -83,6 +88,7 @@ class FILEAPI_EXPORT_PRIVATE FileSystemOperationContext {
MediaPathFilter* media_path_filter_;
AccessObserverList access_observers_;
+ ChangeObserverList change_observers_;
UpdateObserverList update_observers_;
#if defined(SUPPORT_MEDIA_FILESYSTEM)
diff --git a/webkit/fileapi/local_file_system_operation.h b/webkit/fileapi/local_file_system_operation.h
index b005b64..10dd19d 100644
--- a/webkit/fileapi/local_file_system_operation.h
+++ b/webkit/fileapi/local_file_system_operation.h
@@ -115,8 +115,8 @@ class FILEAPI_EXPORT LocalFileSystemOperation
friend class TestMountPointProvider;
friend class chromeos::CrosMountPointProvider;
- friend class FileSystemOperationTest;
- friend class FileSystemOperationWriteTest;
+ friend class LocalFileSystemOperationTest;
+ friend class LocalFileSystemOperationWriteTest;
friend class FileWriterDelegateTest;
friend class FileSystemQuotaTest;
friend class LocalFileSystemTestOriginHelper;
@@ -129,6 +129,10 @@ class FILEAPI_EXPORT LocalFileSystemOperation
return operation_context_->file_system_context();
}
+ FileSystemOperationContext* operation_context() const {
+ return operation_context_.get();
+ }
+
// The unit tests that need to specify and control the lifetime of the
// file_util on their own should call this before performing the actual
// operation. If it is given it will not be overwritten by the class.
diff --git a/webkit/fileapi/local_file_system_operation_unittest.cc b/webkit/fileapi/local_file_system_operation_unittest.cc
index d786406..d2aa935 100644
--- a/webkit/fileapi/local_file_system_operation_unittest.cc
+++ b/webkit/fileapi/local_file_system_operation_unittest.cc
@@ -21,6 +21,7 @@
#include "webkit/fileapi/file_system_util.h"
#include "webkit/fileapi/file_util_helper.h"
#include "webkit/fileapi/local_file_system_test_helper.h"
+#include "webkit/fileapi/mock_file_change_observer.h"
#include "webkit/quota/quota_manager.h"
using quota::QuotaClient;
@@ -169,6 +170,7 @@ class LocalFileSystemOperationTest
: status_(kFileOperationStatusNotSet),
next_unique_path_suffix_(0) {
EXPECT_TRUE(base_.CreateUniqueTempDir());
+ change_observers_ = MockFileChangeObserver::CreateList(&change_observer_);
}
LocalFileSystemOperation* operation();
@@ -198,6 +200,14 @@ class LocalFileSystemOperationTest
return test_helper_.file_util();
}
+ const ChangeObserverList& change_observers() const {
+ return change_observers_;
+ }
+
+ MockFileChangeObserver* change_observer() {
+ return &change_observer_;
+ }
+
FileSystemOperationContext* NewContext() {
FileSystemOperationContext* context = test_helper_.NewOperationContext();
// Grant enough quota for all test cases.
@@ -385,6 +395,9 @@ class LocalFileSystemOperationTest
scoped_refptr<QuotaManager> quota_manager_;
scoped_refptr<QuotaManagerProxy> quota_manager_proxy_;
+ MockFileChangeObserver change_observer_;
+ ChangeObserverList change_observers_;
+
int next_unique_path_suffix_;
DISALLOW_COPY_AND_ASSIGN(LocalFileSystemOperationTest);
@@ -410,15 +423,19 @@ void LocalFileSystemOperationTest::TearDown() {
}
LocalFileSystemOperation* LocalFileSystemOperationTest::operation() {
- return test_helper_.NewOperation();
+ LocalFileSystemOperation* operation = test_helper_.NewOperation();
+ operation->operation_context()->set_change_observers(change_observers());
+ return operation;
}
TEST_F(LocalFileSystemOperationTest, TestMoveFailureSrcDoesntExist) {
FileSystemURL src(URLForPath(FilePath(FILE_PATH_LITERAL("a"))));
FileSystemURL dest(URLForPath(FilePath(FILE_PATH_LITERAL("b"))));
+ change_observer()->ResetCount();
operation()->Move(src, dest, RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveFailureContainsPath) {
@@ -428,6 +445,7 @@ TEST_F(LocalFileSystemOperationTest, TestMoveFailureContainsPath) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveFailureSrcDirExistsDestFile) {
@@ -440,6 +458,7 @@ TEST_F(LocalFileSystemOperationTest, TestMoveFailureSrcDirExistsDestFile) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest,
@@ -453,6 +472,7 @@ TEST_F(LocalFileSystemOperationTest,
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveFailureSrcFileExistsDestDir) {
@@ -465,6 +485,7 @@ TEST_F(LocalFileSystemOperationTest, TestMoveFailureSrcFileExistsDestDir) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveFailureDestParentDoesntExist) {
@@ -477,6 +498,7 @@ TEST_F(LocalFileSystemOperationTest, TestMoveFailureDestParentDoesntExist) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcFileAndOverwrite) {
@@ -491,6 +513,10 @@ TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcFileAndOverwrite) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(dest_file_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Move is considered 'write' access (for both side), and won't be counted
// as read access.
EXPECT_EQ(0, quota_manager_proxy()->storage_accessed_count());
@@ -507,6 +533,10 @@ TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcFileAndNew) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(dest_file_path));
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcDirAndOverwrite) {
@@ -519,6 +549,10 @@ TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcDirAndOverwrite) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_FALSE(DirectoryExists(src_dir_path));
+ EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Make sure we've overwritten but not moved the source under the |dest_dir|.
EXPECT_TRUE(DirectoryExists(dest_dir_path));
EXPECT_FALSE(DirectoryExists(
@@ -537,6 +571,10 @@ TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcDirAndNew) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_FALSE(DirectoryExists(src_dir_path));
EXPECT_TRUE(DirectoryExists(dest_child_dir_path));
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcDirRecursive) {
@@ -556,6 +594,12 @@ TEST_F(LocalFileSystemOperationTest, TestMoveSuccessSrcDirRecursive) {
EXPECT_TRUE(FileExists(dest_dir_path.Append(
VirtualPath::BaseName(child_dir_path)).Append(
VirtualPath::BaseName(grandchild_file_path))));
+
+ EXPECT_EQ(3, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcDoesntExist) {
@@ -564,6 +608,7 @@ TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcDoesntExist) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureContainsPath) {
@@ -573,6 +618,7 @@ TEST_F(LocalFileSystemOperationTest, TestCopyFailureContainsPath) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcDirExistsDestFile) {
@@ -585,6 +631,7 @@ TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcDirExistsDestFile) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest,
@@ -598,6 +645,7 @@ TEST_F(LocalFileSystemOperationTest,
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcFileExistsDestDir) {
@@ -610,6 +658,7 @@ TEST_F(LocalFileSystemOperationTest, TestCopyFailureSrcFileExistsDestDir) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureDestParentDoesntExist) {
@@ -625,6 +674,7 @@ TEST_F(LocalFileSystemOperationTest, TestCopyFailureDestParentDoesntExist) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopyFailureByQuota) {
@@ -670,6 +720,9 @@ TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcFileAndOverwrite) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(dest_file_path));
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcFileAndNew) {
@@ -684,6 +737,9 @@ TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcFileAndNew) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(dest_file_path));
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirAndOverwrite) {
@@ -700,6 +756,10 @@ TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirAndOverwrite) {
EXPECT_FALSE(DirectoryExists(
dest_dir_path.Append(VirtualPath::BaseName(src_dir_path))));
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirAndNew) {
@@ -714,6 +774,9 @@ TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirAndNew) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(DirectoryExists(dest_child_dir_path));
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirRecursive) {
@@ -734,6 +797,11 @@ TEST_F(LocalFileSystemOperationTest, TestCopySuccessSrcDirRecursive) {
VirtualPath::BaseName(child_dir_path)).Append(
VirtualPath::BaseName(grandchild_file_path))));
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_from_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateFileFailure) {
@@ -744,6 +812,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateFileFailure) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessFileExists) {
@@ -755,6 +824,9 @@ TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessFileExists) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(file_path));
+
+ // The file was already there; did nothing.
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessExclusive) {
@@ -766,6 +838,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessExclusive) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(FileExists(file_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
}
TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessFileDoesntExist) {
@@ -776,6 +849,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateFileSuccessFileDoesntExist) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
}
TEST_F(LocalFileSystemOperationTest,
@@ -789,6 +863,7 @@ TEST_F(LocalFileSystemOperationTest,
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateDirFailureDirExists) {
@@ -798,6 +873,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateDirFailureDirExists) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateDirFailureFileExists) {
@@ -808,6 +884,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateDirFailureFileExists) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestCreateDirSuccess) {
@@ -817,6 +894,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateDirSuccess) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
// Dir doesn't exist.
FilePath nonexisting_dir_path(FilePath(
@@ -826,6 +904,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateDirSuccess) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(DirectoryExists(nonexisting_dir_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
}
TEST_F(LocalFileSystemOperationTest, TestCreateDirSuccessExclusive) {
@@ -838,6 +917,8 @@ TEST_F(LocalFileSystemOperationTest, TestCreateDirSuccessExclusive) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_TRUE(DirectoryExists(nonexisting_dir_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestExistsAndMetadataFailure) {
@@ -858,6 +939,7 @@ TEST_F(LocalFileSystemOperationTest, TestExistsAndMetadataFailure) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestExistsAndMetadataSuccess) {
@@ -891,6 +973,7 @@ TEST_F(LocalFileSystemOperationTest, TestExistsAndMetadataSuccess) {
++read_access;
EXPECT_EQ(read_access, quota_manager_proxy()->storage_accessed_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestTypeMismatchErrors) {
@@ -924,6 +1007,7 @@ TEST_F(LocalFileSystemOperationTest, TestReadDirFailure) {
MessageLoop::current()->RunAllPending();
// TODO(kkanetkar) crbug.com/54309 to change the error code.
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestReadDirSuccess) {
@@ -952,6 +1036,7 @@ TEST_F(LocalFileSystemOperationTest, TestReadDirSuccess) {
}
}
EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestRemoveFailure) {
@@ -981,6 +1066,7 @@ TEST_F(LocalFileSystemOperationTest, TestRemoveFailure) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY,
status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestRemoveSuccess) {
@@ -993,6 +1079,9 @@ TEST_F(LocalFileSystemOperationTest, TestRemoveSuccess) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_FALSE(DirectoryExists(empty_dir_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Removing a non-empty directory with recursive flag == true should be ok.
// parent_dir
// | |
@@ -1011,6 +1100,10 @@ TEST_F(LocalFileSystemOperationTest, TestRemoveSuccess) {
// Remove is not a 'read' access.
EXPECT_EQ(0, quota_manager_proxy()->storage_accessed_count());
+
+ EXPECT_EQ(2, change_observer()->get_and_reset_remove_directory_count());
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(LocalFileSystemOperationTest, TestTruncate) {
@@ -1036,6 +1129,9 @@ TEST_F(LocalFileSystemOperationTest, TestTruncate) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Check that its length is now 17 and that it's all zeroes after the test
// data.
base::PlatformFileInfo info;
@@ -1057,6 +1153,9 @@ TEST_F(LocalFileSystemOperationTest, TestTruncate) {
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Check that its length is now 3 and that it contains only bits of test data.
EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info));
EXPECT_EQ(length, info.size);
@@ -1081,6 +1180,8 @@ TEST_F(LocalFileSystemOperationTest, TestTruncateFailureByQuota) {
operation()->Truncate(URLForPath(file_path), 10, RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info));
EXPECT_EQ(10, info.size);
@@ -1088,6 +1189,7 @@ TEST_F(LocalFileSystemOperationTest, TestTruncateFailureByQuota) {
operation()->Truncate(URLForPath(file_path), 11, RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info));
EXPECT_EQ(10, info.size);
@@ -1116,6 +1218,7 @@ TEST_F(LocalFileSystemOperationTest, TestTouchFile) {
RecordStatusCallback());
MessageLoop::current()->RunAllPending();
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
+ EXPECT_TRUE(change_observer()->HasNoChange());
EXPECT_TRUE(file_util::GetFileInfo(platform_path, &info));
// We compare as time_t here to lower our resolution, to avoid false
@@ -1146,6 +1249,7 @@ TEST_F(LocalFileSystemOperationTest, TestCreateSnapshotFile) {
EXPECT_EQ(base::PLATFORM_FILE_OK, status());
EXPECT_FALSE(info().is_directory);
EXPECT_EQ(PlatformPath(file_path), path());
+ EXPECT_TRUE(change_observer()->HasNoChange());
// The FileSystemOpration implementation does not create a
// shareable file reference.
diff --git a/webkit/fileapi/mock_file_change_observer.cc b/webkit/fileapi/mock_file_change_observer.cc
new file mode 100644
index 0000000..c358185
--- /dev/null
+++ b/webkit/fileapi/mock_file_change_observer.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium 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 "webkit/fileapi/mock_file_change_observer.h"
+
+namespace fileapi {
+
+MockFileChangeObserver::MockFileChangeObserver()
+ : create_file_count_(0),
+ create_file_from_count_(0),
+ remove_file_count_(0),
+ modify_file_count_(0),
+ create_directory_count_(0),
+ remove_directory_count_(0) {}
+
+MockFileChangeObserver::~MockFileChangeObserver() {}
+
+// static
+ChangeObserverList MockFileChangeObserver::CreateList(
+ MockFileChangeObserver* observer) {
+ ChangeObserverList::Source source;
+ source.AddObserver(observer, base::MessageLoopProxy::current());
+ return ChangeObserverList(source);
+}
+
+void MockFileChangeObserver::OnCreateFile(const FileSystemURL& url) {
+ create_file_count_++;
+}
+
+void MockFileChangeObserver::OnCreateFileFrom(const FileSystemURL& url,
+ const FileSystemURL& src) {
+ create_file_from_count_++;
+}
+
+void MockFileChangeObserver::OnRemoveFile(const FileSystemURL& url) {
+ remove_file_count_++;
+}
+
+void MockFileChangeObserver::OnModifyFile(const FileSystemURL& url) {
+ modify_file_count_++;
+}
+
+void MockFileChangeObserver::OnCreateDirectory(const FileSystemURL& url) {
+ create_directory_count_++;
+}
+
+void MockFileChangeObserver::OnRemoveDirectory(const FileSystemURL& url) {
+ remove_directory_count_++;
+}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/mock_file_change_observer.h b/webkit/fileapi/mock_file_change_observer.h
new file mode 100644
index 0000000..81cfad9
--- /dev/null
+++ b/webkit/fileapi/mock_file_change_observer.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
+#define WEBKIT_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "webkit/fileapi/file_observers.h"
+#include "webkit/fileapi/file_system_url.h"
+#include "webkit/fileapi/task_runner_bound_observer_list.h"
+
+namespace fileapi {
+
+// Mock file change observer.
+class MockFileChangeObserver : public FileChangeObserver {
+ public:
+ MockFileChangeObserver();
+ virtual ~MockFileChangeObserver();
+
+ // Creates a ChangeObserverList which only contains given |observer|.
+ static ChangeObserverList CreateList(MockFileChangeObserver* observer);
+
+ // FileChangeObserver overrides.
+ virtual void OnCreateFile(const FileSystemURL& url) OVERRIDE;
+ virtual void OnCreateFileFrom(const FileSystemURL& url,
+ const FileSystemURL& src) OVERRIDE;
+ virtual void OnRemoveFile(const FileSystemURL& url) OVERRIDE;
+ virtual void OnModifyFile(const FileSystemURL& url) OVERRIDE;
+ virtual void OnCreateDirectory(const FileSystemURL& url) OVERRIDE;
+ virtual void OnRemoveDirectory(const FileSystemURL& url) OVERRIDE;
+
+ void ResetCount() {
+ create_file_count_ = 0;
+ create_file_from_count_ = 0;
+ remove_file_count_ = 0;
+ modify_file_count_ = 0;
+ create_directory_count_ = 0;
+ remove_directory_count_ = 0;
+ }
+
+ bool HasNoChange() const {
+ return create_file_count_ == 0 &&
+ create_file_from_count_ == 0 &&
+ remove_file_count_ == 0 &&
+ modify_file_count_ == 0 &&
+ create_directory_count_ == 0 &&
+ remove_directory_count_ == 0;
+ }
+
+ int create_file_count() const { return create_file_count_; }
+ int create_file_from_count() const { return create_file_from_count_; }
+ int remove_file_count() const { return remove_file_count_; }
+ int modify_file_count() const { return modify_file_count_; }
+ int create_directory_count() const { return create_directory_count_; }
+ int remove_directory_count() const { return remove_directory_count_; }
+
+ int get_and_reset_create_file_count() {
+ int tmp = create_file_count_;
+ create_file_count_ = 0;
+ return tmp;
+ }
+ int get_and_reset_create_file_from_count() {
+ int tmp = create_file_from_count_;
+ create_file_from_count_ = 0;
+ return tmp;
+ }
+ int get_and_reset_remove_file_count() {
+ int tmp = remove_file_count_;
+ remove_file_count_ = 0;
+ return tmp;
+ }
+ int get_and_reset_modify_file_count() {
+ int tmp = modify_file_count_;
+ modify_file_count_ = 0;
+ return tmp;
+ }
+ int get_and_reset_create_directory_count() {
+ int tmp = create_directory_count_;
+ create_directory_count_ = 0;
+ return tmp;
+ }
+ int get_and_reset_remove_directory_count() {
+ int tmp = remove_directory_count_;
+ remove_directory_count_ = 0;
+ return tmp;
+ }
+
+ private:
+ int create_file_count_;
+ int create_file_from_count_;
+ int remove_file_count_;
+ int modify_file_count_;
+ int create_directory_count_;
+ int remove_directory_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockFileChangeObserver);
+};
+
+} // namespace fileapi
+
+#endif // WEBKIT_FILEAPI_MOCK_FILE_CHANGE_OBSERVER_H_
diff --git a/webkit/fileapi/obfuscated_file_util.cc b/webkit/fileapi/obfuscated_file_util.cc
index fddf937..1022954 100644
--- a/webkit/fileapi/obfuscated_file_util.cc
+++ b/webkit/fileapi/obfuscated_file_util.cc
@@ -293,6 +293,8 @@ PlatformFileError ObfuscatedFileUtil::CreateOrOpen(
if (created && base::PLATFORM_FILE_OK == error) {
*created = true;
UpdateUsage(context, url, growth);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnCreateFile, MakeTuple(url));
}
return error;
}
@@ -330,8 +332,11 @@ PlatformFileError ObfuscatedFileUtil::CreateOrOpen(
}
// If truncating we need to update the usage.
- if (error == base::PLATFORM_FILE_OK && delta)
+ if (error == base::PLATFORM_FILE_OK && delta) {
UpdateUsage(context, url, delta);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnModifyFile, MakeTuple(url));
+ }
return error;
}
@@ -379,6 +384,8 @@ PlatformFileError ObfuscatedFileUtil::EnsureFileExists(
if (created && base::PLATFORM_FILE_OK == error) {
*created = true;
UpdateUsage(context, url, growth);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnCreateFile, MakeTuple(url));
}
return error;
}
@@ -436,6 +443,8 @@ PlatformFileError ObfuscatedFileUtil::CreateDirectory(
return base::PLATFORM_FILE_ERROR_FAILED;
}
UpdateUsage(context, url, growth);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnCreateDirectory, MakeTuple(url));
if (first) {
first = false;
TouchDirectory(db, file_info.parent_id);
@@ -545,8 +554,11 @@ PlatformFileError ObfuscatedFileUtil::Truncate(
if (!AllocateQuota(context, growth))
return base::PLATFORM_FILE_ERROR_NO_SPACE;
error = NativeFileUtil::Truncate(local_path, length);
- if (error == base::PLATFORM_FILE_OK)
+ if (error == base::PLATFORM_FILE_OK) {
UpdateUsage(context, url, growth);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnModifyFile, MakeTuple(url));
+ }
return error;
}
@@ -695,8 +707,22 @@ PlatformFileError ObfuscatedFileUtil::CopyOrMoveFile(
if (error != base::PLATFORM_FILE_OK)
return error;
- if (!copy)
+ if (overwrite) {
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnModifyFile,
+ MakeTuple(dest_url));
+ } else {
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnCreateFileFrom,
+ MakeTuple(dest_url, src_url));
+ }
+
+ if (!copy) {
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnRemoveFile, MakeTuple(src_url));
TouchDirectory(db, src_file_info.parent_id);
+ }
+
TouchDirectory(db, dest_file_info.parent_id);
UpdateUsage(context, dest_url, growth);
@@ -769,6 +795,14 @@ PlatformFileError ObfuscatedFileUtil::CopyInForeignFile(
if (error != base::PLATFORM_FILE_OK)
return error;
+ if (overwrite) {
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnModifyFile, MakeTuple(dest_url));
+ } else {
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnCreateFile, MakeTuple(dest_url));
+ }
+
UpdateUsage(context, dest_url, growth);
TouchDirectory(db, dest_file_info.parent_id);
return base::PLATFORM_FILE_OK;
@@ -809,6 +843,9 @@ PlatformFileError ObfuscatedFileUtil::DeleteFile(
UpdateUsage(context, url, growth);
TouchDirectory(db, file_info.parent_id);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnRemoveFile, MakeTuple(url));
+
if (error == base::PLATFORM_FILE_ERROR_NOT_FOUND)
return base::PLATFORM_FILE_OK;
@@ -840,6 +877,8 @@ PlatformFileError ObfuscatedFileUtil::DeleteSingleDirectory(
AllocateQuota(context, growth);
UpdateUsage(context, url, growth);
TouchDirectory(db, file_info.parent_id);
+ context->change_observers()->Notify(
+ &FileChangeObserver::OnRemoveDirectory, MakeTuple(url));
return base::PLATFORM_FILE_OK;
}
diff --git a/webkit/fileapi/obfuscated_file_util_unittest.cc b/webkit/fileapi/obfuscated_file_util_unittest.cc
index 76c28ba..a7f9c4b 100644
--- a/webkit/fileapi/obfuscated_file_util_unittest.cc
+++ b/webkit/fileapi/obfuscated_file_util_unittest.cc
@@ -21,6 +21,7 @@
#include "webkit/fileapi/file_system_usage_cache.h"
#include "webkit/fileapi/file_util_helper.h"
#include "webkit/fileapi/local_file_system_test_helper.h"
+#include "webkit/fileapi/mock_file_change_observer.h"
#include "webkit/fileapi/mock_file_system_options.h"
#include "webkit/fileapi/obfuscated_file_util.h"
#include "webkit/fileapi/test_file_set.h"
@@ -28,7 +29,7 @@
#include "webkit/quota/quota_manager.h"
#include "webkit/quota/quota_types.h"
-using namespace fileapi;
+namespace fileapi {
namespace {
@@ -133,6 +134,8 @@ class ObfuscatedFileUtilTest : public testing::Test {
test_helper_.SetUp(file_system_context_.get(),
obfuscated_file_util_);
+
+ change_observers_ = MockFileChangeObserver::CreateList(&change_observer_);
}
void TearDown() {
@@ -154,15 +157,25 @@ class ObfuscatedFileUtilTest : public testing::Test {
FileSystemOperationContext* NewContext(
LocalFileSystemTestOriginHelper* helper) {
+ change_observer()->ResetCount();
FileSystemOperationContext* context;
if (helper)
context = helper->NewOperationContext();
else
context = test_helper_.NewOperationContext();
context->set_allowed_bytes_growth(1024 * 1024); // Big enough for all tests.
+ context->set_change_observers(change_observers());
return context;
}
+ const ChangeObserverList& change_observers() const {
+ return change_observers_;
+ }
+
+ MockFileChangeObserver* change_observer() {
+ return &change_observer_;
+ }
+
// This can only be used after SetUp has run and created file_system_context_
// and obfuscated_file_util_.
// Use this for tests which need to run in multiple origins; we need a test
@@ -428,6 +441,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
context.get(), ofu(), root_url, &entries));
std::vector<base::FileUtilProxy::Entry>::iterator entry_iter;
EXPECT_EQ(files.size() + directories.size(), entries.size());
+ EXPECT_TRUE(change_observer()->HasNoChange());
for (entry_iter = entries.begin(); entry_iter != entries.end();
++entry_iter) {
const base::FileUtilProxy::Entry& entry = *entry_iter;
@@ -452,6 +466,8 @@ class ObfuscatedFileUtilTest : public testing::Test {
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->Touch(
context.get(), url, last_access_time, last_modified_time));
+ // Currently we fire no change notifications for Touch.
+ EXPECT_TRUE(change_observer()->HasNoChange());
FilePath local_path;
base::PlatformFileInfo file_info;
context.reset(NewContext(NULL));
@@ -468,6 +484,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->Touch(
context.get(), url, last_access_time, last_modified_time));
+ EXPECT_TRUE(change_observer()->HasNoChange());
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->GetFileInfo(
context.get(), url, &file_info, &local_path));
@@ -503,6 +520,10 @@ class ObfuscatedFileUtilTest : public testing::Test {
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->EnsureFileExists(context.get(), dest_url, &created));
EXPECT_TRUE(created);
+
+ // We must have observed one (and only one) create_file_count.
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
const int64 path_cost =
@@ -552,6 +573,7 @@ class ObfuscatedFileUtilTest : public testing::Test {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->GetFileInfo(context.get(), url, &file_info, &data_path));
+ EXPECT_TRUE(change_observer()->HasNoChange());
return file_info.last_modified;
}
@@ -594,7 +616,6 @@ class ObfuscatedFileUtilTest : public testing::Test {
ofu()->CopyOrMoveFile(context.get(),
src_file_url, dest_file_url,
copy));
-
if (copy)
EXPECT_EQ(base::Time(), GetModifiedTime(src_dir_url));
else
@@ -623,6 +644,8 @@ class ObfuscatedFileUtilTest : public testing::Test {
LocalFileSystemTestOriginHelper test_helper_;
quota::QuotaStatusCode quota_status_;
int64 usage_;
+ MockFileChangeObserver change_observer_;
+ ChangeObserverList change_observers_;
DISALLOW_COPY_AND_ASSIGN(ObfuscatedFileUtilTest);
};
@@ -645,6 +668,8 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
url = CreateURLFromUTF8("test file");
+ EXPECT_TRUE(change_observer()->HasNoChange());
+
// Verify that file creation requires sufficient quota for the path.
context.reset(NewContext(NULL));
context->set_allowed_bytes_growth(
@@ -660,6 +685,7 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
ofu()->CreateOrOpen(
context.get(), url, file_flags, &file_handle, &created));
ASSERT_TRUE(created);
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
EXPECT_NE(base::kInvalidPlatformFileValue, file_handle);
CheckFileAndCloseHandle(url, file_handle);
@@ -676,6 +702,7 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
context->set_allowed_bytes_growth(0);
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->DeleteFile(context.get(), url));
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
EXPECT_FALSE(file_util::PathExists(local_path));
EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()),
context->allowed_bytes_growth());
@@ -688,6 +715,8 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
url = directory_url.WithPath(directory_url.path().AppendASCII("file name"));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
context.get(), directory_url, exclusive, recursive));
+ // The oepration created 3 directories recursively.
+ EXPECT_EQ(3, change_observer()->get_and_reset_create_directory_count());
context.reset(NewContext(NULL));
file_handle = base::kInvalidPlatformFileValue;
@@ -695,6 +724,7 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
ofu()->CreateOrOpen(
context.get(), url, file_flags, &file_handle, &created));
ASSERT_TRUE(created);
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
EXPECT_NE(base::kInvalidPlatformFileValue, file_handle);
CheckFileAndCloseHandle(url, file_handle);
@@ -707,7 +737,11 @@ TEST_F(ObfuscatedFileUtilTest, TestCreateAndDeleteFile) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->DeleteFile(context.get(), url));
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_file_count());
EXPECT_FALSE(file_util::PathExists(local_path));
+
+ // Make sure we have no unexpected changes.
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
@@ -722,6 +756,7 @@ TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
ASSERT_EQ(base::PLATFORM_FILE_OK,
ofu()->EnsureFileExists(context.get(), url, &created));
ASSERT_TRUE(created);
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
context.reset(NewContext(NULL));
FilePath local_path;
@@ -732,15 +767,20 @@ TEST_F(ObfuscatedFileUtilTest, TestTruncate) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
context.get(), url, 10));
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_EQ(10, GetSize(local_path));
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->Truncate(
context.get(), url, 1));
EXPECT_EQ(1, GetSize(local_path));
+ EXPECT_EQ(1, change_observer()->get_and_reset_modify_file_count());
EXPECT_FALSE(DirectoryExists(url));
EXPECT_TRUE(PathExists(url));
+
+ // Make sure we have no unexpected changes.
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(ObfuscatedFileUtilTest, TestQuotaOnTruncation) {
@@ -817,6 +857,7 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
ofu()->EnsureFileExists(
context.get(), url, &created));
+ EXPECT_TRUE(change_observer()->HasNoChange());
// Verify that file creation requires sufficient quota for the path.
context.reset(NewContext(NULL));
@@ -827,6 +868,7 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
ASSERT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE,
ofu()->EnsureFileExists(context.get(), url, &created));
ASSERT_FALSE(created);
+ EXPECT_TRUE(change_observer()->HasNoChange());
context.reset(NewContext(NULL));
context->set_allowed_bytes_growth(
@@ -834,6 +876,7 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
ASSERT_EQ(base::PLATFORM_FILE_OK,
ofu()->EnsureFileExists(context.get(), url, &created));
ASSERT_TRUE(created);
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_file_count());
CheckFileAndCloseHandle(url, base::kInvalidPlatformFileValue);
@@ -841,6 +884,7 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
ASSERT_EQ(base::PLATFORM_FILE_OK,
ofu()->EnsureFileExists(context.get(), url, &created));
ASSERT_FALSE(created);
+ EXPECT_TRUE(change_observer()->HasNoChange());
// Also test in a subdirectory.
url = CreateURLFromUTF8("path/to/file.txt");
@@ -851,6 +895,8 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
context.get(),
url.WithPath(url.path().DirName()),
exclusive, recursive));
+ // 2 directories: path/ and path/to.
+ EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
context.reset(NewContext(NULL));
ASSERT_EQ(base::PLATFORM_FILE_OK,
@@ -858,6 +904,7 @@ TEST_F(ObfuscatedFileUtilTest, TestEnsureFileExists) {
ASSERT_TRUE(created);
EXPECT_FALSE(DirectoryExists(url));
EXPECT_TRUE(PathExists(url));
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
@@ -884,6 +931,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
recursive = true;
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
EXPECT_TRUE(DirectoryExists(url));
EXPECT_TRUE(PathExists(url));
@@ -901,6 +949,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY,
ofu()->DeleteSingleDirectory(context.get(),
url.WithPath(url.path().DirName())));
+ EXPECT_TRUE(change_observer()->HasNoChange());
base::PlatformFileInfo file_info;
FilePath local_path;
@@ -914,12 +963,14 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
exclusive = true;
recursive = true;
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
// Verify that deleting a directory isn't stopped by zero quota, and that it
// frees up quota from its path.
@@ -927,6 +978,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context->set_allowed_bytes_growth(0);
EXPECT_EQ(base::PLATFORM_FILE_OK,
ofu()->DeleteSingleDirectory(context.get(), url));
+ EXPECT_EQ(1, change_observer()->get_and_reset_remove_directory_count());
EXPECT_EQ(ObfuscatedFileUtil::ComputeFilePathCost(url.path()),
context->allowed_bytes_growth());
@@ -948,12 +1000,14 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
ObfuscatedFileUtil::ComputeFilePathCost(url.path()) - 1);
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
context.reset(NewContext(NULL));
context->set_allowed_bytes_growth(
ObfuscatedFileUtil::ComputeFilePathCost(url.path()));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
EXPECT_TRUE(DirectoryExists(url));
EXPECT_TRUE(PathExists(url));
@@ -963,6 +1017,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
exclusive = true;
recursive = false;
@@ -970,6 +1025,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
url = CreateURLFromUTF8("blah");
@@ -981,6 +1037,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_EQ(1, change_observer()->get_and_reset_create_directory_count());
EXPECT_TRUE(DirectoryExists(url));
EXPECT_TRUE(PathExists(url));
@@ -990,6 +1047,7 @@ TEST_F(ObfuscatedFileUtilTest, TestDirectoryOps) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, ofu()->CreateDirectory(
context.get(), url, exclusive, recursive));
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(ObfuscatedFileUtilTest, TestReadDirectory) {
@@ -1103,11 +1161,13 @@ TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
is_copy_not_move));
+ EXPECT_TRUE(change_observer()->HasNoChange());
context.reset(NewContext(NULL));
is_copy_not_move = true;
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
is_copy_not_move));
+ EXPECT_TRUE(change_observer()->HasNoChange());
source_url = CreateURLFromUTF8("dir/dir/file");
bool exclusive = true;
bool recursive = true;
@@ -1116,15 +1176,18 @@ TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileNotFound) {
context.get(),
source_url.WithPath(source_url.path().DirName()),
exclusive, recursive));
+ EXPECT_EQ(2, change_observer()->get_and_reset_create_directory_count());
is_copy_not_move = false;
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
is_copy_not_move));
+ EXPECT_TRUE(change_observer()->HasNoChange());
context.reset(NewContext(NULL));
is_copy_not_move = true;
EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
ofu()->CopyOrMoveFile(context.get(), source_url, dest_url,
is_copy_not_move));
+ EXPECT_TRUE(change_observer()->HasNoChange());
}
TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
@@ -1183,6 +1246,7 @@ TEST_F(ObfuscatedFileUtilTest, TestCopyOrMoveFileSuccess) {
context.reset(NewContext(NULL));
EXPECT_EQ(base::PLATFORM_FILE_OK, ofu()->CopyOrMoveFile(context.get(),
source_url, dest_url, test_case.is_copy_not_move));
+
if (test_case.is_copy_not_move) {
base::PlatformFileInfo file_info;
FilePath local_path;
@@ -2210,3 +2274,5 @@ TEST_F(ObfuscatedFileUtilTest, TestQuotaOnOpen) {
ASSERT_EQ(0, ComputeTotalFileSize());
EXPECT_TRUE(base::ClosePlatformFile(file_handle));
}
+
+} // namespace fileapi
diff --git a/webkit/fileapi/task_runner_bound_observer_list.h b/webkit/fileapi/task_runner_bound_observer_list.h
index 17a8eec..9af380f5c 100644
--- a/webkit/fileapi/task_runner_bound_observer_list.h
+++ b/webkit/fileapi/task_runner_bound_observer_list.h
@@ -94,9 +94,11 @@ class TaskRunnerBoundObserverList {
};
class FileAccessObserver;
+class FileChangeObserver;
class FileUpdateObserver;
typedef TaskRunnerBoundObserverList<FileAccessObserver> AccessObserverList;
+typedef TaskRunnerBoundObserverList<FileChangeObserver> ChangeObserverList;
typedef TaskRunnerBoundObserverList<FileUpdateObserver> UpdateObserverList;
} // namespace fileapi