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 <string> 6 7 #include "base/files/file.h" 8 #include "base/files/file_path.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/memory/scoped_vector.h" 12 #include "base/values.h" 13 #include "chrome/browser/chromeos/file_system_provider/operations/read_file.h" 14 #include "chrome/common/extensions/api/file_system_provider.h" 15 #include "chrome/common/extensions/api/file_system_provider_internal.h" 16 #include "extensions/browser/event_router.h" 17 #include "net/base/io_buffer.h" 18 #include "testing/gtest/include/gtest/gtest.h" 19 #include "webkit/browser/fileapi/async_file_util.h" 20 21 namespace chromeos { 22 namespace file_system_provider { 23 namespace operations { 24 namespace { 25 26 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj"; 27 const char kFileSystemId[] = "testing-file-system"; 28 const int kRequestId = 2; 29 const int kFileHandle = 3; 30 const int kOffset = 10; 31 const int kLength = 5; 32 33 // Fake event dispatcher implementation with extra logging capability. Acts as 34 // a providing extension end-point. 35 class LoggingDispatchEventImpl { 36 public: 37 explicit LoggingDispatchEventImpl(bool dispatch_reply) 38 : dispatch_reply_(dispatch_reply) {} 39 virtual ~LoggingDispatchEventImpl() {} 40 41 bool OnDispatchEventImpl(scoped_ptr<extensions::Event> event) { 42 events_.push_back(event->DeepCopy()); 43 return dispatch_reply_; 44 } 45 46 ScopedVector<extensions::Event>& events() { return events_; } 47 48 private: 49 ScopedVector<extensions::Event> events_; 50 bool dispatch_reply_; 51 52 DISALLOW_COPY_AND_ASSIGN(LoggingDispatchEventImpl); 53 }; 54 55 // Callback invocation logger. Acts as a fileapi end-point. 56 class CallbackLogger { 57 public: 58 class Event { 59 public: 60 Event(int chunk_length, bool has_more, base::File::Error result) 61 : chunk_length_(chunk_length), has_more_(has_more), result_(result) {} 62 virtual ~Event() {} 63 64 int chunk_length() const { return chunk_length_; } 65 bool has_more() const { return has_more_; } 66 base::File::Error result() const { return result_; } 67 68 private: 69 int chunk_length_; 70 bool has_more_; 71 base::File::Error result_; 72 73 DISALLOW_COPY_AND_ASSIGN(Event); 74 }; 75 76 CallbackLogger() : weak_ptr_factory_(this) {} 77 virtual ~CallbackLogger() {} 78 79 void OnReadFile(int chunk_length, bool has_more, base::File::Error result) { 80 events_.push_back(new Event(chunk_length, has_more, result)); 81 } 82 83 ScopedVector<Event>& events() { return events_; } 84 85 base::WeakPtr<CallbackLogger> GetWeakPtr() { 86 return weak_ptr_factory_.GetWeakPtr(); 87 } 88 89 private: 90 ScopedVector<Event> events_; 91 bool dispatch_reply_; 92 base::WeakPtrFactory<CallbackLogger> weak_ptr_factory_; 93 94 DISALLOW_COPY_AND_ASSIGN(CallbackLogger); 95 }; 96 97 } // namespace 98 99 class FileSystemProviderOperationsReadFileTest : public testing::Test { 100 protected: 101 FileSystemProviderOperationsReadFileTest() {} 102 virtual ~FileSystemProviderOperationsReadFileTest() {} 103 104 virtual void SetUp() OVERRIDE { 105 file_system_info_ = 106 ProvidedFileSystemInfo(kExtensionId, 107 kFileSystemId, 108 "" /* file_system_name */, 109 base::FilePath() /* mount_path */); 110 io_buffer_ = make_scoped_refptr(new net::IOBuffer(kOffset + kLength)); 111 } 112 113 ProvidedFileSystemInfo file_system_info_; 114 scoped_refptr<net::IOBuffer> io_buffer_; 115 }; 116 117 TEST_F(FileSystemProviderOperationsReadFileTest, Execute) { 118 LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 119 CallbackLogger callback_logger; 120 121 ReadFile read_file( 122 NULL, 123 file_system_info_, 124 kFileHandle, 125 io_buffer_.get(), 126 kOffset, 127 kLength, 128 base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); 129 read_file.SetDispatchEventImplForTesting( 130 base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, 131 base::Unretained(&dispatcher))); 132 133 EXPECT_TRUE(read_file.Execute(kRequestId)); 134 135 ASSERT_EQ(1u, dispatcher.events().size()); 136 extensions::Event* event = dispatcher.events()[0]; 137 EXPECT_EQ( 138 extensions::api::file_system_provider::OnReadFileRequested::kEventName, 139 event->event_name); 140 base::ListValue* event_args = event->event_args.get(); 141 ASSERT_EQ(1u, event_args->GetSize()); 142 143 base::DictionaryValue* options = NULL; 144 ASSERT_TRUE(event_args->GetDictionary(0, &options)); 145 146 std::string event_file_system_id; 147 EXPECT_TRUE(options->GetString("fileSystemId", &event_file_system_id)); 148 EXPECT_EQ(kFileSystemId, event_file_system_id); 149 150 int event_request_id = -1; 151 EXPECT_TRUE(options->GetInteger("requestId", &event_request_id)); 152 EXPECT_EQ(kRequestId, event_request_id); 153 154 int event_file_handle = -1; 155 EXPECT_TRUE(options->GetInteger("openRequestId", &event_file_handle)); 156 EXPECT_EQ(kFileHandle, event_file_handle); 157 158 double event_offset = -1; 159 EXPECT_TRUE(options->GetDouble("offset", &event_offset)); 160 EXPECT_EQ(kOffset, static_cast<double>(event_offset)); 161 162 int event_length = -1; 163 EXPECT_TRUE(options->GetInteger("length", &event_length)); 164 EXPECT_EQ(kLength, event_length); 165 } 166 167 TEST_F(FileSystemProviderOperationsReadFileTest, Execute_NoListener) { 168 LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */); 169 CallbackLogger callback_logger; 170 171 ReadFile read_file( 172 NULL, 173 file_system_info_, 174 kFileHandle, 175 io_buffer_.get(), 176 kOffset, 177 kLength, 178 base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); 179 read_file.SetDispatchEventImplForTesting( 180 base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, 181 base::Unretained(&dispatcher))); 182 183 EXPECT_FALSE(read_file.Execute(kRequestId)); 184 } 185 186 TEST_F(FileSystemProviderOperationsReadFileTest, OnSuccess) { 187 using extensions::api::file_system_provider_internal:: 188 ReadFileRequestedSuccess::Params; 189 190 LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 191 CallbackLogger callback_logger; 192 193 ReadFile read_file( 194 NULL, 195 file_system_info_, 196 kFileHandle, 197 io_buffer_.get(), 198 kOffset, 199 kLength, 200 base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); 201 read_file.SetDispatchEventImplForTesting( 202 base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, 203 base::Unretained(&dispatcher))); 204 205 EXPECT_TRUE(read_file.Execute(kRequestId)); 206 207 const std::string data = "ABCDE"; 208 const bool has_more = false; 209 210 base::ListValue value_as_list; 211 value_as_list.Set(0, new base::StringValue(kFileSystemId)); 212 value_as_list.Set(1, new base::FundamentalValue(kRequestId)); 213 value_as_list.Set( 214 2, base::BinaryValue::CreateWithCopiedBuffer(data.c_str(), data.size())); 215 value_as_list.Set(3, new base::FundamentalValue(has_more)); 216 217 scoped_ptr<Params> params(Params::Create(value_as_list)); 218 ASSERT_TRUE(params.get()); 219 scoped_ptr<RequestValue> request_value( 220 RequestValue::CreateForReadFileSuccess(params.Pass())); 221 ASSERT_TRUE(request_value.get()); 222 223 read_file.OnSuccess(kRequestId, request_value.Pass(), has_more); 224 225 ASSERT_EQ(1u, callback_logger.events().size()); 226 CallbackLogger::Event* event = callback_logger.events()[0]; 227 EXPECT_EQ(kLength, event->chunk_length()); 228 EXPECT_FALSE(event->has_more()); 229 EXPECT_EQ(data, std::string(io_buffer_->data(), kLength)); 230 EXPECT_EQ(base::File::FILE_OK, event->result()); 231 } 232 233 TEST_F(FileSystemProviderOperationsReadFileTest, OnError) { 234 using extensions::api::file_system_provider_internal::ReadFileRequestedError:: 235 Params; 236 237 LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 238 CallbackLogger callback_logger; 239 240 ReadFile read_file( 241 NULL, 242 file_system_info_, 243 kFileHandle, 244 io_buffer_.get(), 245 kOffset, 246 kLength, 247 base::Bind(&CallbackLogger::OnReadFile, callback_logger.GetWeakPtr())); 248 read_file.SetDispatchEventImplForTesting( 249 base::Bind(&LoggingDispatchEventImpl::OnDispatchEventImpl, 250 base::Unretained(&dispatcher))); 251 252 EXPECT_TRUE(read_file.Execute(kRequestId)); 253 254 read_file.OnError(kRequestId, base::File::FILE_ERROR_TOO_MANY_OPENED); 255 256 ASSERT_EQ(1u, callback_logger.events().size()); 257 CallbackLogger::Event* event = callback_logger.events()[0]; 258 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, event->result()); 259 } 260 261 } // namespace operations 262 } // namespace file_system_provider 263 } // namespace chromeos 264