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/get_metadata.h" 6 7#include <string> 8 9#include "base/files/file.h" 10#include "base/files/file_path.h" 11#include "base/json/json_reader.h" 12#include "base/memory/scoped_ptr.h" 13#include "base/memory/scoped_vector.h" 14#include "base/values.h" 15#include "chrome/browser/chromeos/file_system_provider/operations/test_util.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 char kMimeType[] = "text/plain"; 30const int kRequestId = 2; 31const base::FilePath::CharType kDirectoryPath[] = "/directory"; 32 33// URLs are case insensitive, so it should pass the sanity check. 34const char kThumbnail[] = "DaTa:ImAgE/pNg;base64,"; 35 36// Callback invocation logger. Acts as a fileapi end-point. 37class CallbackLogger { 38 public: 39 class Event { 40 public: 41 Event(scoped_ptr<EntryMetadata> metadata, base::File::Error result) 42 : metadata_(metadata.Pass()), result_(result) {} 43 virtual ~Event() {} 44 45 const EntryMetadata* metadata() const { return metadata_.get(); } 46 base::File::Error result() const { return result_; } 47 48 private: 49 scoped_ptr<EntryMetadata> metadata_; 50 base::File::Error result_; 51 52 DISALLOW_COPY_AND_ASSIGN(Event); 53 }; 54 55 CallbackLogger() {} 56 virtual ~CallbackLogger() {} 57 58 void OnGetMetadata(scoped_ptr<EntryMetadata> metadata, 59 base::File::Error result) { 60 events_.push_back(new Event(metadata.Pass(), result)); 61 } 62 63 const ScopedVector<Event>& events() const { return events_; } 64 65 private: 66 ScopedVector<Event> events_; 67 bool dispatch_reply_; 68 69 DISALLOW_COPY_AND_ASSIGN(CallbackLogger); 70}; 71 72} // namespace 73 74class FileSystemProviderOperationsGetMetadataTest : public testing::Test { 75 protected: 76 FileSystemProviderOperationsGetMetadataTest() {} 77 virtual ~FileSystemProviderOperationsGetMetadataTest() {} 78 79 virtual void SetUp() OVERRIDE { 80 file_system_info_ = 81 ProvidedFileSystemInfo(kExtensionId, 82 kFileSystemId, 83 "" /* display_name */, 84 false /* writable */, 85 base::FilePath() /* mount_path */); 86 } 87 88 ProvidedFileSystemInfo file_system_info_; 89}; 90 91TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute) { 92 using extensions::api::file_system_provider::GetMetadataRequestedOptions; 93 94 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 95 CallbackLogger callback_logger; 96 97 GetMetadata get_metadata( 98 NULL, 99 file_system_info_, 100 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 101 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL, 102 base::Bind(&CallbackLogger::OnGetMetadata, 103 base::Unretained(&callback_logger))); 104 get_metadata.SetDispatchEventImplForTesting( 105 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 106 base::Unretained(&dispatcher))); 107 108 EXPECT_TRUE(get_metadata.Execute(kRequestId)); 109 110 ASSERT_EQ(1u, dispatcher.events().size()); 111 extensions::Event* event = dispatcher.events()[0]; 112 EXPECT_EQ( 113 extensions::api::file_system_provider::OnGetMetadataRequested::kEventName, 114 event->event_name); 115 base::ListValue* event_args = event->event_args.get(); 116 ASSERT_EQ(1u, event_args->GetSize()); 117 118 const base::DictionaryValue* options_as_value = NULL; 119 ASSERT_TRUE(event_args->GetDictionary(0, &options_as_value)); 120 121 GetMetadataRequestedOptions options; 122 ASSERT_TRUE( 123 GetMetadataRequestedOptions::Populate(*options_as_value, &options)); 124 EXPECT_EQ(kFileSystemId, options.file_system_id); 125 EXPECT_EQ(kRequestId, options.request_id); 126 EXPECT_EQ(kDirectoryPath, options.entry_path); 127 EXPECT_TRUE(options.thumbnail); 128} 129 130TEST_F(FileSystemProviderOperationsGetMetadataTest, Execute_NoListener) { 131 util::LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */); 132 CallbackLogger callback_logger; 133 134 GetMetadata get_metadata( 135 NULL, 136 file_system_info_, 137 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 138 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL, 139 base::Bind(&CallbackLogger::OnGetMetadata, 140 base::Unretained(&callback_logger))); 141 get_metadata.SetDispatchEventImplForTesting( 142 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 143 base::Unretained(&dispatcher))); 144 145 EXPECT_FALSE(get_metadata.Execute(kRequestId)); 146} 147 148TEST_F(FileSystemProviderOperationsGetMetadataTest, OnSuccess) { 149 using extensions::api::file_system_provider_internal:: 150 GetMetadataRequestedSuccess::Params; 151 152 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 153 CallbackLogger callback_logger; 154 155 GetMetadata get_metadata( 156 NULL, 157 file_system_info_, 158 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 159 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL, 160 base::Bind(&CallbackLogger::OnGetMetadata, 161 base::Unretained(&callback_logger))); 162 get_metadata.SetDispatchEventImplForTesting( 163 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 164 base::Unretained(&dispatcher))); 165 166 EXPECT_TRUE(get_metadata.Execute(kRequestId)); 167 168 // Sample input as JSON. Keep in sync with file_system_provider_api.idl. 169 // As for now, it is impossible to create *::Params class directly, not from 170 // base::Value. 171 const std::string input = 172 "[\n" 173 " \"testing-file-system\",\n" // kFileSystemId 174 " 2,\n" // kRequestId 175 " {\n" 176 " \"isDirectory\": false,\n" 177 " \"name\": \"blueberries.txt\",\n" 178 " \"size\": 4096,\n" 179 " \"modificationTime\": {\n" 180 " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n" 181 " },\n" 182 " \"mimeType\": \"text/plain\",\n" // kMimeType 183 " \"thumbnail\": \"DaTa:ImAgE/pNg;base64,\"\n" // kThumbnail 184 " },\n" 185 " 0\n" // execution_time 186 "]\n"; 187 188 int json_error_code; 189 std::string json_error_msg; 190 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( 191 input, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg)); 192 ASSERT_TRUE(value.get()) << json_error_msg; 193 194 base::ListValue* value_as_list; 195 ASSERT_TRUE(value->GetAsList(&value_as_list)); 196 scoped_ptr<Params> params(Params::Create(*value_as_list)); 197 ASSERT_TRUE(params.get()); 198 scoped_ptr<RequestValue> request_value( 199 RequestValue::CreateForGetMetadataSuccess(params.Pass())); 200 ASSERT_TRUE(request_value.get()); 201 202 const bool has_more = false; 203 get_metadata.OnSuccess(kRequestId, request_value.Pass(), has_more); 204 205 ASSERT_EQ(1u, callback_logger.events().size()); 206 CallbackLogger::Event* event = callback_logger.events()[0]; 207 EXPECT_EQ(base::File::FILE_OK, event->result()); 208 209 const EntryMetadata* metadata = event->metadata(); 210 EXPECT_FALSE(metadata->is_directory); 211 EXPECT_EQ(4096, metadata->size); 212 base::Time expected_time; 213 EXPECT_TRUE( 214 base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time)); 215 EXPECT_EQ(expected_time, metadata->modification_time); 216 EXPECT_EQ(kMimeType, metadata->mime_type); 217 EXPECT_EQ(kThumbnail, metadata->thumbnail); 218} 219 220TEST_F(FileSystemProviderOperationsGetMetadataTest, 221 OnSuccess_InvalidThumbnail) { 222 using extensions::api::file_system_provider_internal:: 223 GetMetadataRequestedSuccess::Params; 224 225 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 226 CallbackLogger callback_logger; 227 228 GetMetadata get_metadata( 229 NULL, 230 file_system_info_, 231 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 232 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL, 233 base::Bind(&CallbackLogger::OnGetMetadata, 234 base::Unretained(&callback_logger))); 235 get_metadata.SetDispatchEventImplForTesting( 236 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 237 base::Unretained(&dispatcher))); 238 239 EXPECT_TRUE(get_metadata.Execute(kRequestId)); 240 241 // Sample input as JSON. Keep in sync with file_system_provider_api.idl. 242 // As for now, it is impossible to create *::Params class directly, not from 243 // base::Value. 244 const std::string input = 245 "[\n" 246 " \"testing-file-system\",\n" // kFileSystemId 247 " 2,\n" // kRequestId 248 " {\n" 249 " \"isDirectory\": false,\n" 250 " \"name\": \"blueberries.txt\",\n" 251 " \"size\": 4096,\n" 252 " \"modificationTime\": {\n" 253 " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n" 254 " },\n" 255 " \"mimeType\": \"text/plain\",\n" // kMimeType 256 " \"thumbnail\": \"http://www.foobar.com/evil\"\n" // kThumbnail 257 " },\n" 258 " 0\n" // execution_time 259 "]\n"; 260 261 int json_error_code; 262 std::string json_error_msg; 263 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( 264 input, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg)); 265 ASSERT_TRUE(value.get()) << json_error_msg; 266 267 base::ListValue* value_as_list; 268 ASSERT_TRUE(value->GetAsList(&value_as_list)); 269 scoped_ptr<Params> params(Params::Create(*value_as_list)); 270 ASSERT_TRUE(params.get()); 271 scoped_ptr<RequestValue> request_value( 272 RequestValue::CreateForGetMetadataSuccess(params.Pass())); 273 ASSERT_TRUE(request_value.get()); 274 275 const bool has_more = false; 276 get_metadata.OnSuccess(kRequestId, request_value.Pass(), has_more); 277 278 ASSERT_EQ(1u, callback_logger.events().size()); 279 CallbackLogger::Event* event = callback_logger.events()[0]; 280 EXPECT_EQ(base::File::FILE_ERROR_IO, event->result()); 281 282 const EntryMetadata* metadata = event->metadata(); 283 EXPECT_FALSE(metadata); 284} 285 286TEST_F(FileSystemProviderOperationsGetMetadataTest, OnError) { 287 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 288 CallbackLogger callback_logger; 289 290 GetMetadata get_metadata( 291 NULL, 292 file_system_info_, 293 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 294 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL, 295 base::Bind(&CallbackLogger::OnGetMetadata, 296 base::Unretained(&callback_logger))); 297 get_metadata.SetDispatchEventImplForTesting( 298 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 299 base::Unretained(&dispatcher))); 300 301 EXPECT_TRUE(get_metadata.Execute(kRequestId)); 302 303 get_metadata.OnError(kRequestId, 304 scoped_ptr<RequestValue>(new RequestValue()), 305 base::File::FILE_ERROR_TOO_MANY_OPENED); 306 307 ASSERT_EQ(1u, callback_logger.events().size()); 308 CallbackLogger::Event* event = callback_logger.events()[0]; 309 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, event->result()); 310} 311 312} // namespace operations 313} // namespace file_system_provider 314} // namespace chromeos 315