1 // Copyright 2014 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/drive/fileapi/fileapi_worker.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/file_util.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "chrome/browser/chromeos/drive/dummy_file_system.h" 12 #include "chrome/browser/chromeos/drive/test_util.h" 13 #include "content/public/test/test_browser_thread_bundle.h" 14 #include "google_apis/drive/test_util.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace drive { 18 namespace fileapi_internal { 19 namespace { 20 21 // Increments |num_called| for checking how many times the closure is called. 22 void Increment(int* num_called) { 23 ++*num_called; 24 } 25 26 // Returns the |instance| as is. 27 FileSystemInterface* GetFileSystem(FileSystemInterface* instance) { 28 return instance; 29 } 30 31 // A test file system that always returns |local_file_path|. For testing 32 // purpose, it checks if |open_mode| is the expected value, and record if the 33 // close callback is called. 34 class TestFileSystemForOpenFile : public DummyFileSystem { 35 public: 36 TestFileSystemForOpenFile(const base::FilePath& local_file_path, 37 OpenMode expected_open_mode) 38 : local_file_path_(local_file_path), 39 expected_open_mode_(expected_open_mode), 40 closed_(false) { 41 } 42 43 virtual void OpenFile(const base::FilePath& file_path, 44 OpenMode open_mode, 45 const std::string& mime_type, 46 const drive::OpenFileCallback& callback) OVERRIDE { 47 EXPECT_EQ(expected_open_mode_, open_mode); 48 49 callback.Run( 50 FILE_ERROR_OK, 51 local_file_path_, 52 base::Bind(&TestFileSystemForOpenFile::Close, base::Unretained(this))); 53 } 54 55 void Close() { 56 closed_ = true; 57 } 58 59 bool closed() const { return closed_; } 60 61 private: 62 const base::FilePath local_file_path_; 63 const OpenMode expected_open_mode_; 64 bool closed_; 65 }; 66 67 // Helper function of testing OpenFile() for write access. It checks that the 68 // file handle correctly writes to the expected file. 69 void VerifyWrite( 70 int64 expected_size, 71 const base::FilePath& expected_written_path, 72 const std::string& write_data, 73 base::File file, 74 const base::Closure& close_callback) { 75 // Check that the file was properly opened. 76 EXPECT_TRUE(file.IsValid()); 77 EXPECT_FALSE(close_callback.is_null()); 78 79 // Check that the file has the expected length (i.e., truncated or not) 80 base::File::Info info; 81 EXPECT_TRUE(file.GetInfo(&info)); 82 EXPECT_EQ(expected_size, info.size); 83 84 // Write some data. 85 const int data_size = static_cast<int>(write_data.size()); 86 EXPECT_EQ(data_size, file.Write(0, write_data.c_str(), data_size)); 87 EXPECT_TRUE(file.SetLength(data_size)); 88 89 // Close. 90 file.Close(); 91 close_callback.Run(); 92 93 // Checks that the written content goes to |expected_written_path|. I.e., 94 // the |file| handle is pointing to the file. 95 std::string written; 96 EXPECT_TRUE(base::ReadFileToString(expected_written_path, &written)); 97 EXPECT_EQ(write_data, written); 98 } 99 100 // Helper function of testing OpenFile() for read access. It checks that the 101 // file is readable and contains |expected_data|. 102 void VerifyRead(const std::string& expected_data, 103 base::File file, 104 const base::Closure& close_callback) { 105 // Check that the file was properly opened. 106 EXPECT_TRUE(file.IsValid()); 107 EXPECT_FALSE(close_callback.is_null()); 108 109 // Check that the file has the expected content. 110 const int data_size = static_cast<int>(expected_data.size()); 111 base::File::Info info; 112 EXPECT_TRUE(file.GetInfo(&info)); 113 EXPECT_EQ(data_size, info.size); 114 115 std::vector<char> buffer(data_size); 116 EXPECT_EQ(data_size, file.Read(0, buffer.data(), data_size)); 117 EXPECT_EQ(expected_data, std::string(buffer.begin(), buffer.end())); 118 119 // Close. 120 file.Close(); 121 close_callback.Run(); 122 } 123 124 } // namespace 125 126 class FileApiWorkerTest : public testing::Test { 127 private: 128 content::TestBrowserThreadBundle thread_bundle_; 129 }; 130 131 TEST_F(FileApiWorkerTest, RunFileSystemCallbackSuccess) { 132 DummyFileSystem dummy_file_system; 133 134 FileSystemInterface* file_system = NULL; 135 RunFileSystemCallback( 136 base::Bind(&GetFileSystem, &dummy_file_system), 137 google_apis::test_util::CreateCopyResultCallback(&file_system), 138 base::Closure()); 139 140 EXPECT_EQ(&dummy_file_system, file_system); 141 } 142 143 TEST_F(FileApiWorkerTest, RunFileSystemCallbackFail) { 144 FileSystemInterface* file_system = NULL; 145 146 // Make sure on_error_callback is called if file_system_getter returns NULL. 147 int num_called = 0; 148 RunFileSystemCallback( 149 base::Bind(&GetFileSystem, static_cast<FileSystemInterface*>(NULL)), 150 google_apis::test_util::CreateCopyResultCallback(&file_system), 151 base::Bind(&Increment, &num_called)); 152 EXPECT_EQ(1, num_called); 153 154 // Just make sure this null |on_error_callback| doesn't cause a crash. 155 RunFileSystemCallback( 156 base::Bind(&GetFileSystem, static_cast<FileSystemInterface*>(NULL)), 157 google_apis::test_util::CreateCopyResultCallback(&file_system), 158 base::Closure()); 159 } 160 161 TEST_F(FileApiWorkerTest, OpenFileForCreateWrite) { 162 const base::FilePath kDummyPath = base::FilePath::FromUTF8Unsafe("whatever"); 163 const std::string kWriteData = "byebye"; 164 165 base::FilePath temp_path; 166 base::CreateTemporaryFile(&temp_path); 167 168 // CREATE => CREATE (fails if file exists.) 169 TestFileSystemForOpenFile file_system(temp_path, CREATE_FILE); 170 const int64 kExpectedSize = 0; 171 172 OpenFile(kDummyPath, 173 base::File::FLAG_CREATE | base::File::FLAG_WRITE, 174 base::Bind(&VerifyWrite, kExpectedSize, temp_path, kWriteData), 175 &file_system); 176 test_util::RunBlockingPoolTask(); 177 EXPECT_TRUE(file_system.closed()); 178 } 179 180 TEST_F(FileApiWorkerTest, OpenFileForOpenAlwaysWrite) { 181 const base::FilePath kDummyPath = base::FilePath::FromUTF8Unsafe("whatever"); 182 const std::string kWriteData = "byebye"; 183 const std::string kInitialData = "hello"; 184 185 base::FilePath temp_path; 186 base::CreateTemporaryFile(&temp_path); 187 google_apis::test_util::WriteStringToFile(temp_path, kInitialData); 188 189 // OPEN_ALWAYS => OPEN_OR_CREATE (success whether file exists or not.) 190 // No truncation should take place. 191 TestFileSystemForOpenFile file_system(temp_path, OPEN_OR_CREATE_FILE); 192 const int64 kExpectedSize = static_cast<int64>(kInitialData.size()); 193 194 OpenFile(kDummyPath, 195 base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE, 196 base::Bind(&VerifyWrite, kExpectedSize, temp_path, kWriteData), 197 &file_system); 198 test_util::RunBlockingPoolTask(); 199 EXPECT_TRUE(file_system.closed()); 200 } 201 202 TEST_F(FileApiWorkerTest, OpenFileForOpenTruncatedWrite) { 203 const base::FilePath kDummyPath = base::FilePath::FromUTF8Unsafe("whatever"); 204 const std::string kInitialData = "hello"; 205 const std::string kWriteData = "byebye"; 206 207 base::FilePath temp_path; 208 base::CreateTemporaryFile(&temp_path); 209 google_apis::test_util::WriteStringToFile(temp_path, kInitialData); 210 211 // OPEN_TRUNCATED => OPEN (failure when the file did not exist.) 212 // It should truncate the file before passing to the callback. 213 TestFileSystemForOpenFile file_system(temp_path, OPEN_FILE); 214 const int64 kExpectedSize = 0; 215 216 OpenFile(kDummyPath, 217 base::File::FLAG_OPEN_TRUNCATED | base::File::FLAG_WRITE, 218 base::Bind(&VerifyWrite, kExpectedSize, temp_path, kWriteData), 219 &file_system); 220 test_util::RunBlockingPoolTask(); 221 EXPECT_TRUE(file_system.closed()); 222 } 223 224 TEST_F(FileApiWorkerTest, OpenFileForOpenCreateAlwaysWrite) { 225 const base::FilePath kDummyPath = base::FilePath::FromUTF8Unsafe("whatever"); 226 const std::string kInitialData = "hello"; 227 const std::string kWriteData = "byebye"; 228 229 base::FilePath temp_path; 230 base::CreateTemporaryFile(&temp_path); 231 google_apis::test_util::WriteStringToFile(temp_path, kInitialData); 232 233 // CREATE_ALWAYS => OPEN_OR_CREATE (success whether file exists or not.) 234 // It should truncate the file before passing to the callback. 235 TestFileSystemForOpenFile file_system(temp_path, OPEN_OR_CREATE_FILE); 236 const int64 kExpectedSize = 0; 237 238 OpenFile(kDummyPath, 239 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE, 240 base::Bind(&VerifyWrite, kExpectedSize, temp_path, kWriteData), 241 &file_system); 242 test_util::RunBlockingPoolTask(); 243 EXPECT_TRUE(file_system.closed()); 244 } 245 246 TEST_F(FileApiWorkerTest, OpenFileForOpenRead) { 247 const base::FilePath kDummyPath = base::FilePath::FromUTF8Unsafe("whatever"); 248 const std::string kInitialData = "hello"; 249 250 base::FilePath temp_path; 251 base::CreateTemporaryFile(&temp_path); 252 google_apis::test_util::WriteStringToFile(temp_path, kInitialData); 253 254 // OPEN => OPEN (failure when the file did not exist.) 255 TestFileSystemForOpenFile file_system(temp_path, OPEN_FILE); 256 257 OpenFile(kDummyPath, 258 base::File::FLAG_OPEN | base::File::FLAG_READ, 259 base::Bind(&VerifyRead, kInitialData), 260 &file_system); 261 test_util::RunBlockingPoolTask(); 262 EXPECT_TRUE(file_system.closed()); 263 } 264 265 } // namespace fileapi_internal 266 } // namespace drive 267