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/file_system_provider/operations/open_file.h" 6 7#include <string> 8#include <vector> 9 10#include "base/files/file.h" 11#include "base/files/file_path.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/memory/scoped_vector.h" 14#include "chrome/browser/chromeos/file_system_provider/operations/test_util.h" 15#include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" 16#include "chrome/common/extensions/api/file_system_provider.h" 17#include "chrome/common/extensions/api/file_system_provider_internal.h" 18#include "extensions/browser/event_router.h" 19#include "storage/browser/fileapi/async_file_util.h" 20#include "testing/gtest/include/gtest/gtest.h" 21 22namespace chromeos { 23namespace file_system_provider { 24namespace operations { 25namespace { 26 27const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj"; 28const char kFileSystemId[] = "testing-file-system"; 29const int kRequestId = 2; 30const base::FilePath::CharType kFilePath[] = "/directory/blueberries.txt"; 31 32// Callback invocation logger. Acts as a fileapi end-point. 33class CallbackLogger { 34 public: 35 class Event { 36 public: 37 Event(int file_handle, base::File::Error result) 38 : file_handle_(file_handle), result_(result) {} 39 virtual ~Event() {} 40 41 int file_handle() { return file_handle_; } 42 base::File::Error result() { return result_; } 43 44 private: 45 int file_handle_; 46 base::File::Error result_; 47 48 DISALLOW_COPY_AND_ASSIGN(Event); 49 }; 50 51 CallbackLogger() {} 52 virtual ~CallbackLogger() {} 53 54 void OnOpenFile(int file_handle, base::File::Error result) { 55 events_.push_back(new Event(file_handle, result)); 56 } 57 58 ScopedVector<Event>& events() { return events_; } 59 60 private: 61 ScopedVector<Event> events_; 62 bool dispatch_reply_; 63 64 DISALLOW_COPY_AND_ASSIGN(CallbackLogger); 65}; 66 67} // namespace 68 69class FileSystemProviderOperationsOpenFileTest : public testing::Test { 70 protected: 71 FileSystemProviderOperationsOpenFileTest() {} 72 virtual ~FileSystemProviderOperationsOpenFileTest() {} 73 74 virtual void SetUp() OVERRIDE { 75 file_system_info_ = 76 ProvidedFileSystemInfo(kExtensionId, 77 kFileSystemId, 78 "" /* display_name */, 79 false /* writable */, 80 base::FilePath() /* mount_path */); 81 } 82 83 ProvidedFileSystemInfo file_system_info_; 84}; 85 86TEST_F(FileSystemProviderOperationsOpenFileTest, Execute) { 87 using extensions::api::file_system_provider::OpenFileRequestedOptions; 88 89 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 90 CallbackLogger callback_logger; 91 92 OpenFile open_file(NULL, 93 file_system_info_, 94 base::FilePath::FromUTF8Unsafe(kFilePath), 95 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, 96 base::Bind(&CallbackLogger::OnOpenFile, 97 base::Unretained(&callback_logger))); 98 open_file.SetDispatchEventImplForTesting( 99 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 100 base::Unretained(&dispatcher))); 101 102 EXPECT_TRUE(open_file.Execute(kRequestId)); 103 104 ASSERT_EQ(1u, dispatcher.events().size()); 105 extensions::Event* event = dispatcher.events()[0]; 106 EXPECT_EQ( 107 extensions::api::file_system_provider::OnOpenFileRequested::kEventName, 108 event->event_name); 109 base::ListValue* event_args = event->event_args.get(); 110 ASSERT_EQ(1u, event_args->GetSize()); 111 112 const base::DictionaryValue* options_as_value = NULL; 113 ASSERT_TRUE(event_args->GetDictionary(0, &options_as_value)); 114 115 OpenFileRequestedOptions options; 116 ASSERT_TRUE(OpenFileRequestedOptions::Populate(*options_as_value, &options)); 117 EXPECT_EQ(kFileSystemId, options.file_system_id); 118 EXPECT_EQ(kRequestId, options.request_id); 119 EXPECT_EQ(kFilePath, options.file_path); 120 EXPECT_EQ(extensions::api::file_system_provider::OPEN_FILE_MODE_READ, 121 options.mode); 122} 123 124TEST_F(FileSystemProviderOperationsOpenFileTest, Execute_NoListener) { 125 util::LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */); 126 CallbackLogger callback_logger; 127 128 OpenFile open_file(NULL, 129 file_system_info_, 130 base::FilePath::FromUTF8Unsafe(kFilePath), 131 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, 132 base::Bind(&CallbackLogger::OnOpenFile, 133 base::Unretained(&callback_logger))); 134 open_file.SetDispatchEventImplForTesting( 135 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 136 base::Unretained(&dispatcher))); 137 138 EXPECT_FALSE(open_file.Execute(kRequestId)); 139} 140 141TEST_F(FileSystemProviderOperationsOpenFileTest, Execute_ReadOnly) { 142 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 143 CallbackLogger callback_logger; 144 145 const ProvidedFileSystemInfo read_only_file_system_info( 146 kExtensionId, 147 kFileSystemId, 148 "" /* file_system_name */, 149 false /* writable */, 150 base::FilePath() /* mount_path */); 151 152 // Opening for read on a read-only file system is allowed. 153 { 154 OpenFile open_file(NULL, 155 read_only_file_system_info, 156 base::FilePath::FromUTF8Unsafe(kFilePath), 157 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, 158 base::Bind(&CallbackLogger::OnOpenFile, 159 base::Unretained(&callback_logger))); 160 open_file.SetDispatchEventImplForTesting( 161 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 162 base::Unretained(&dispatcher))); 163 164 EXPECT_TRUE(open_file.Execute(kRequestId)); 165 } 166 167 // Opening for write on a read-only file system is forbidden and must fail. 168 { 169 OpenFile open_file(NULL, 170 read_only_file_system_info, 171 base::FilePath::FromUTF8Unsafe(kFilePath), 172 ProvidedFileSystemInterface::OPEN_FILE_MODE_WRITE, 173 base::Bind(&CallbackLogger::OnOpenFile, 174 base::Unretained(&callback_logger))); 175 open_file.SetDispatchEventImplForTesting( 176 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 177 base::Unretained(&dispatcher))); 178 179 EXPECT_FALSE(open_file.Execute(kRequestId)); 180 } 181} 182 183TEST_F(FileSystemProviderOperationsOpenFileTest, OnSuccess) { 184 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 185 CallbackLogger callback_logger; 186 187 OpenFile open_file(NULL, 188 file_system_info_, 189 base::FilePath::FromUTF8Unsafe(kFilePath), 190 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, 191 base::Bind(&CallbackLogger::OnOpenFile, 192 base::Unretained(&callback_logger))); 193 open_file.SetDispatchEventImplForTesting( 194 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 195 base::Unretained(&dispatcher))); 196 197 EXPECT_TRUE(open_file.Execute(kRequestId)); 198 199 open_file.OnSuccess(kRequestId, 200 scoped_ptr<RequestValue>(new RequestValue()), 201 false /* has_more */); 202 ASSERT_EQ(1u, callback_logger.events().size()); 203 CallbackLogger::Event* event = callback_logger.events()[0]; 204 EXPECT_EQ(base::File::FILE_OK, event->result()); 205 EXPECT_LT(0, event->file_handle()); 206} 207 208TEST_F(FileSystemProviderOperationsOpenFileTest, OnError) { 209 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 210 CallbackLogger callback_logger; 211 212 OpenFile open_file(NULL, 213 file_system_info_, 214 base::FilePath::FromUTF8Unsafe(kFilePath), 215 ProvidedFileSystemInterface::OPEN_FILE_MODE_READ, 216 base::Bind(&CallbackLogger::OnOpenFile, 217 base::Unretained(&callback_logger))); 218 open_file.SetDispatchEventImplForTesting( 219 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 220 base::Unretained(&dispatcher))); 221 222 EXPECT_TRUE(open_file.Execute(kRequestId)); 223 224 open_file.OnError(kRequestId, 225 scoped_ptr<RequestValue>(new RequestValue()), 226 base::File::FILE_ERROR_TOO_MANY_OPENED); 227 ASSERT_EQ(1u, callback_logger.events().size()); 228 CallbackLogger::Event* event = callback_logger.events()[0]; 229 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, event->result()); 230 ASSERT_EQ(0, event->file_handle()); 231} 232 233} // namespace operations 234} // namespace file_system_provider 235} // namespace chromeos 236