OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chromeos/drive/file_write_helper.h" | 5 #include "chrome/browser/chromeos/drive/file_write_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
10 #include "chrome/browser/chromeos/drive/mock_file_system.h" | 10 #include "chrome/browser/chromeos/drive/dummy_file_system.h" |
11 #include "chrome/browser/chromeos/drive/test_util.h" | 11 #include "chrome/browser/chromeos/drive/test_util.h" |
12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
13 #include "content/public/test/test_browser_thread.h" | 13 #include "content/public/test/test_browser_thread.h" |
14 #include "testing/gmock/include/gmock/gmock.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
16 | 15 |
17 using ::testing::StrictMock; | |
18 using ::testing::_; | |
19 | |
20 namespace drive { | 16 namespace drive { |
21 | 17 |
22 namespace { | 18 namespace { |
23 | 19 |
24 ACTION_P(MockCreateFile, error) { | 20 const base::FilePath::CharType kDrivePath[] = |
25 DCHECK(!arg2.is_null()); | 21 FILE_PATH_LITERAL("drive/root/file.txt"); |
26 arg2.Run(error); | 22 const base::FilePath::CharType kInvalidPath[] = |
27 } | 23 FILE_PATH_LITERAL("drive/invalid/path"); |
| 24 const base::FilePath::CharType kLocalPath[] = |
| 25 FILE_PATH_LITERAL("/tmp/local.txt"); |
28 | 26 |
29 ACTION_P2(MockOpenFile, error, local_path) { | 27 class TestFileSystem : public DummyFileSystem { |
30 DCHECK(!arg1.is_null()); | 28 public: |
31 arg1.Run(error, local_path); | 29 // Mimics CreateFile. It always succeeds unless kInvalidPath is passed. |
32 } | 30 virtual void CreateFile(const base::FilePath& file_path, |
| 31 bool is_exclusive, |
| 32 const FileOperationCallback& callback) OVERRIDE { |
| 33 if (file_path == base::FilePath(kInvalidPath)) { |
| 34 callback.Run(FILE_ERROR_ACCESS_DENIED); |
| 35 return; |
| 36 } |
| 37 created.insert(file_path); |
| 38 callback.Run(FILE_ERROR_OK); |
| 39 } |
33 | 40 |
34 ACTION_P(MockCloseFile, error) { | 41 // Mimics OpenFile. It fails if the |file_path| is a path that is not |
35 DCHECK(!arg1.is_null()); | 42 // passed to CreateFile before. This tests that FileWriteHelper always |
36 arg1.Run(error); | 43 // ensures file existence before trying to open. It also fails if the |
37 } | 44 // path is already opened, to match the behavior of real FileSystem. |
| 45 virtual void OpenFile(const base::FilePath& file_path, |
| 46 const OpenFileCallback& callback) OVERRIDE { |
| 47 // Files failed to create should never be opened. |
| 48 EXPECT_TRUE(created.count(file_path)); |
| 49 created.erase(file_path); |
| 50 if (opened.count(file_path)) { |
| 51 callback.Run(FILE_ERROR_IN_USE, base::FilePath()); |
| 52 } else { |
| 53 opened.insert(file_path); |
| 54 callback.Run(FILE_ERROR_OK, base::FilePath(kLocalPath)); |
| 55 } |
| 56 } |
38 | 57 |
39 void RecordOpenFileCallbackArguments(FileError* error, | 58 // Mimics CloseFile. It fails if it is passed a path not OpenFile'd. |
40 base::FilePath* path, | 59 virtual void CloseFile(const base::FilePath& file_path, |
41 FileError error_arg, | 60 const FileOperationCallback& callback) OVERRIDE { |
42 const base::FilePath& path_arg) { | 61 // Files failed to open should never be closed. |
43 base::ThreadRestrictions::AssertIOAllowed(); | 62 EXPECT_TRUE(opened.count(file_path)); |
44 *error = error_arg; | 63 opened.erase(file_path); |
45 *path = path_arg; | 64 callback.Run(FILE_ERROR_OK); |
46 } | 65 } |
| 66 std::set<base::FilePath> created; |
| 67 std::set<base::FilePath> opened; |
| 68 }; |
47 | 69 |
48 } // namespace | 70 } // namespace |
49 | 71 |
50 class FileWriteHelperTest : public testing::Test { | 72 class FileWriteHelperTest : public testing::Test { |
51 public: | 73 public: |
52 FileWriteHelperTest() | 74 FileWriteHelperTest() |
53 : ui_thread_(content::BrowserThread::UI, &message_loop_), | 75 : ui_thread_(content::BrowserThread::UI, &message_loop_), |
54 mock_file_system_(new StrictMock<MockFileSystem>) { | 76 test_file_system_(new TestFileSystem) { |
55 } | 77 } |
56 | 78 |
57 protected: | 79 protected: |
58 MessageLoopForUI message_loop_; | 80 MessageLoopForUI message_loop_; |
59 content::TestBrowserThread ui_thread_; | 81 content::TestBrowserThread ui_thread_; |
60 scoped_ptr< StrictMock<MockFileSystem> > mock_file_system_; | 82 scoped_ptr<TestFileSystem> test_file_system_; |
61 }; | 83 }; |
62 | 84 |
63 TEST_F(FileWriteHelperTest, PrepareFileForWritingSuccess) { | 85 TEST_F(FileWriteHelperTest, PrepareFileForWritingSuccess) { |
64 const base::FilePath kDrivePath(FILE_PATH_LITERAL("/drive/file.txt")); | 86 FileWriteHelper file_write_helper(test_file_system_.get()); |
65 const base::FilePath kLocalPath(FILE_PATH_LITERAL("/tmp/dummy.txt")); | |
66 | |
67 EXPECT_CALL(*mock_file_system_, CreateFile(kDrivePath, false, _)) | |
68 .WillOnce(MockCreateFile(FILE_ERROR_OK)); | |
69 EXPECT_CALL(*mock_file_system_, OpenFile(kDrivePath, _)) | |
70 .WillOnce(MockOpenFile(FILE_ERROR_OK, kLocalPath)); | |
71 EXPECT_CALL(*mock_file_system_, CloseFile(kDrivePath, _)) | |
72 .WillOnce(MockCloseFile(FILE_ERROR_OK)); | |
73 | |
74 FileWriteHelper file_write_helper(mock_file_system_.get()); | |
75 FileError error = FILE_ERROR_FAILED; | 87 FileError error = FILE_ERROR_FAILED; |
76 base::FilePath path; | 88 base::FilePath path; |
| 89 // The file should successfully be opened. |
77 file_write_helper.PrepareWritableFileAndRun( | 90 file_write_helper.PrepareWritableFileAndRun( |
78 kDrivePath, base::Bind(&RecordOpenFileCallbackArguments, &error, &path)); | 91 base::FilePath(kDrivePath), |
| 92 google_apis::test_util::CreateCopyResultCallback(&error, &path)); |
79 google_apis::test_util::RunBlockingPoolTask(); | 93 google_apis::test_util::RunBlockingPoolTask(); |
80 | 94 |
81 EXPECT_EQ(FILE_ERROR_OK, error); | 95 EXPECT_EQ(FILE_ERROR_OK, error); |
82 EXPECT_EQ(kLocalPath, path); | 96 EXPECT_EQ(kLocalPath, path.value()); |
83 } | 97 } |
84 | 98 |
85 TEST_F(FileWriteHelperTest, PrepareFileForWritingCreateFail) { | 99 TEST_F(FileWriteHelperTest, PrepareFileForWritingCreateFail) { |
86 const base::FilePath kDrivePath(FILE_PATH_LITERAL("/drive/file.txt")); | 100 FileWriteHelper file_write_helper(test_file_system_.get()); |
87 | |
88 EXPECT_CALL(*mock_file_system_, CreateFile(kDrivePath, false, _)) | |
89 .WillOnce(MockCreateFile(FILE_ERROR_ACCESS_DENIED)); | |
90 EXPECT_CALL(*mock_file_system_, OpenFile(_, _)).Times(0); | |
91 EXPECT_CALL(*mock_file_system_, CloseFile(_, _)).Times(0); | |
92 | |
93 FileWriteHelper file_write_helper(mock_file_system_.get()); | |
94 FileError error = FILE_ERROR_FAILED; | 101 FileError error = FILE_ERROR_FAILED; |
95 base::FilePath path; | 102 base::FilePath path; |
| 103 // Access to kInvalidPath should fail, and FileWriteHelper should not try to |
| 104 // open or close the file. |
96 file_write_helper.PrepareWritableFileAndRun( | 105 file_write_helper.PrepareWritableFileAndRun( |
97 kDrivePath, base::Bind(&RecordOpenFileCallbackArguments, &error, &path)); | 106 base::FilePath(kInvalidPath), |
| 107 google_apis::test_util::CreateCopyResultCallback(&error, &path)); |
98 google_apis::test_util::RunBlockingPoolTask(); | 108 google_apis::test_util::RunBlockingPoolTask(); |
99 | 109 |
100 EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, error); | 110 EXPECT_EQ(FILE_ERROR_ACCESS_DENIED, error); |
101 EXPECT_EQ(base::FilePath(), path); | 111 EXPECT_TRUE(path.empty()); |
102 } | 112 } |
103 | 113 |
104 TEST_F(FileWriteHelperTest, PrepareFileForWritingOpenFail) { | 114 TEST_F(FileWriteHelperTest, PrepareFileForWritingOpenFail) { |
105 const base::FilePath kDrivePath(FILE_PATH_LITERAL("/drive/file.txt")); | 115 // Externally open the path beforehand. |
106 | |
107 EXPECT_CALL(*mock_file_system_, CreateFile(kDrivePath, false, _)) | |
108 .WillOnce(MockCreateFile(FILE_ERROR_OK)); | |
109 EXPECT_CALL(*mock_file_system_, OpenFile(kDrivePath, _)) | |
110 .WillOnce(MockOpenFile(FILE_ERROR_IN_USE, base::FilePath())); | |
111 EXPECT_CALL(*mock_file_system_, CloseFile(_, _)).Times(0); | |
112 | |
113 FileWriteHelper file_write_helper(mock_file_system_.get()); | |
114 FileError error = FILE_ERROR_FAILED; | 116 FileError error = FILE_ERROR_FAILED; |
115 base::FilePath path; | 117 base::FilePath path; |
| 118 test_file_system_->CreateFile( |
| 119 base::FilePath(kDrivePath), |
| 120 false, |
| 121 google_apis::test_util::CreateCopyResultCallback(&error)); |
| 122 ASSERT_EQ(FILE_ERROR_OK, error); |
| 123 error = FILE_ERROR_FAILED; |
| 124 test_file_system_->OpenFile( |
| 125 base::FilePath(kDrivePath), |
| 126 google_apis::test_util::CreateCopyResultCallback(&error, &path)); |
| 127 ASSERT_EQ(FILE_ERROR_OK, error); |
| 128 |
| 129 // Run FileWriteHelper on a file already opened in somewhere else. |
| 130 // It should fail to open the file, and should not try to close it. |
| 131 FileWriteHelper file_write_helper(test_file_system_.get()); |
116 file_write_helper.PrepareWritableFileAndRun( | 132 file_write_helper.PrepareWritableFileAndRun( |
117 kDrivePath, base::Bind(&RecordOpenFileCallbackArguments, &error, &path)); | 133 base::FilePath(kDrivePath), |
| 134 google_apis::test_util::CreateCopyResultCallback(&error, &path)); |
118 google_apis::test_util::RunBlockingPoolTask(); | 135 google_apis::test_util::RunBlockingPoolTask(); |
119 | 136 |
120 EXPECT_EQ(FILE_ERROR_IN_USE, error); | 137 EXPECT_EQ(FILE_ERROR_IN_USE, error); |
121 EXPECT_EQ(base::FilePath(), path); | 138 EXPECT_TRUE(path.empty()); |
122 } | 139 } |
123 | 140 |
124 } // namespace drive | 141 } // namespace drive |
OLD | NEW |