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.
5 #include "chrome/browser/chromeos/file_system_provider/operations/get_metadata.h"
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"
23 namespace file_system_provider
{
24 namespace operations
{
27 const char kExtensionId
[] = "mbflcebpggnecokmikipoihdbecnjfoj";
28 const char kFileSystemId
[] = "testing-file-system";
29 const char kMimeType
[] = "text/plain";
30 const int kRequestId
= 2;
31 const base::FilePath::CharType kDirectoryPath
[] =
32 FILE_PATH_LITERAL("/directory");
34 // URLs are case insensitive, so it should pass the sanity check.
35 const char kThumbnail
[] = "DaTa:ImAgE/pNg;base64,";
37 // Returns the request value as |result| in case of successful parse.
38 void CreateRequestValueFromJSON(const std::string
& json
,
39 scoped_ptr
<RequestValue
>* result
) {
40 using extensions::api::file_system_provider_internal::
41 GetMetadataRequestedSuccess::Params
;
44 std::string json_error_msg
;
45 scoped_ptr
<base::Value
> value(base::JSONReader::ReadAndReturnError(
46 json
, base::JSON_PARSE_RFC
, &json_error_code
, &json_error_msg
));
47 ASSERT_TRUE(value
.get()) << json_error_msg
;
49 base::ListValue
* value_as_list
;
50 ASSERT_TRUE(value
->GetAsList(&value_as_list
));
51 scoped_ptr
<Params
> params(Params::Create(*value_as_list
));
52 ASSERT_TRUE(params
.get());
53 *result
= RequestValue::CreateForGetMetadataSuccess(params
.Pass());
54 ASSERT_TRUE(result
->get());
57 // Callback invocation logger. Acts as a fileapi end-point.
58 class CallbackLogger
{
62 Event(scoped_ptr
<EntryMetadata
> metadata
, base::File::Error result
)
63 : metadata_(metadata
.Pass()), result_(result
) {}
66 const EntryMetadata
* metadata() const { return metadata_
.get(); }
67 base::File::Error
result() const { return result_
; }
70 scoped_ptr
<EntryMetadata
> metadata_
;
71 base::File::Error result_
;
73 DISALLOW_COPY_AND_ASSIGN(Event
);
77 virtual ~CallbackLogger() {}
79 void OnGetMetadata(scoped_ptr
<EntryMetadata
> metadata
,
80 base::File::Error result
) {
81 events_
.push_back(new Event(metadata
.Pass(), result
));
84 const ScopedVector
<Event
>& events() const { return events_
; }
87 ScopedVector
<Event
> events_
;
89 DISALLOW_COPY_AND_ASSIGN(CallbackLogger
);
94 class FileSystemProviderOperationsGetMetadataTest
: public testing::Test
{
96 FileSystemProviderOperationsGetMetadataTest() {}
97 ~FileSystemProviderOperationsGetMetadataTest() override
{}
99 void SetUp() override
{
100 file_system_info_
= ProvidedFileSystemInfo(
102 MountOptions(kFileSystemId
, "" /* display_name */),
106 ProvidedFileSystemInfo file_system_info_
;
109 TEST_F(FileSystemProviderOperationsGetMetadataTest
, ValidateName
) {
110 EXPECT_TRUE(ValidateName("hello-world!@#$%^&*()-_=+\"':,.<>?[]{}|\\",
111 false /* root_entry */));
112 EXPECT_FALSE(ValidateName("hello-world!@#$%^&*()-_=+\"':,.<>?[]{}|\\",
113 true /* root_entry */));
114 EXPECT_FALSE(ValidateName("", false /* root_path */));
115 EXPECT_TRUE(ValidateName("", true /* root_path */));
116 EXPECT_FALSE(ValidateName("hello/world", false /* root_path */));
117 EXPECT_FALSE(ValidateName("hello/world", true /* root_path */));
120 TEST_F(FileSystemProviderOperationsGetMetadataTest
, ValidateIDLEntryMetadata
) {
121 using extensions::api::file_system_provider::EntryMetadata
;
122 const std::string kValidFileName
= "hello-world";
123 const std::string kValidThumbnailUrl
= "data:something";
125 // Correct metadata for non-root.
127 EntryMetadata metadata
;
128 metadata
.name
= kValidFileName
;
129 metadata
.modification_time
.additional_properties
.SetString(
130 "value", "invalid-date-time"); // Invalid modification time is OK.
131 metadata
.thumbnail
.reset(new std::string(kValidThumbnailUrl
));
132 EXPECT_TRUE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
135 // Correct metadata for non-root (without thumbnail).
137 EntryMetadata metadata
;
138 metadata
.name
= kValidFileName
;
139 metadata
.modification_time
.additional_properties
.SetString(
140 "value", "invalid-date-time"); // Invalid modification time is OK.
141 EXPECT_TRUE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
144 // Correct metadata for root.
146 EntryMetadata metadata
;
148 metadata
.modification_time
.additional_properties
.SetString(
149 "value", "invalid-date-time"); // Invalid modification time is OK.
150 EXPECT_TRUE(ValidateIDLEntryMetadata(metadata
, true /* root_path */));
153 // Invalid characters in the name.
155 EntryMetadata metadata
;
156 metadata
.name
= "hello/world";
157 metadata
.modification_time
.additional_properties
.SetString(
158 "value", "invalid-date-time"); // Invalid modification time is OK.
159 metadata
.thumbnail
.reset(new std::string(kValidThumbnailUrl
));
160 EXPECT_FALSE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
163 // Empty name for non-root.
165 EntryMetadata metadata
;
167 metadata
.modification_time
.additional_properties
.SetString(
168 "value", "invalid-date-time"); // Invalid modification time is OK.
169 metadata
.thumbnail
.reset(new std::string(kValidThumbnailUrl
));
170 EXPECT_FALSE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
173 // Missing date time.
175 EntryMetadata metadata
;
176 metadata
.name
= kValidFileName
;
177 metadata
.thumbnail
.reset(new std::string(kValidThumbnailUrl
));
178 EXPECT_FALSE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
181 // Invalid thumbnail.
183 EntryMetadata metadata
;
184 metadata
.name
= kValidFileName
;
185 metadata
.modification_time
.additional_properties
.SetString(
186 "value", "invalid-date-time"); // Invalid modification time is OK.
187 metadata
.thumbnail
.reset(new std::string("http://invalid-scheme"));
188 EXPECT_FALSE(ValidateIDLEntryMetadata(metadata
, false /* root_path */));
192 TEST_F(FileSystemProviderOperationsGetMetadataTest
, Execute
) {
193 using extensions::api::file_system_provider::GetMetadataRequestedOptions
;
195 util::LoggingDispatchEventImpl
dispatcher(true /* dispatch_reply */);
196 CallbackLogger callback_logger
;
198 GetMetadata
get_metadata(
199 NULL
, file_system_info_
, base::FilePath(kDirectoryPath
),
200 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL
,
201 base::Bind(&CallbackLogger::OnGetMetadata
,
202 base::Unretained(&callback_logger
)));
203 get_metadata
.SetDispatchEventImplForTesting(
204 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl
,
205 base::Unretained(&dispatcher
)));
207 EXPECT_TRUE(get_metadata
.Execute(kRequestId
));
209 ASSERT_EQ(1u, dispatcher
.events().size());
210 extensions::Event
* event
= dispatcher
.events()[0];
212 extensions::api::file_system_provider::OnGetMetadataRequested::kEventName
,
214 base::ListValue
* event_args
= event
->event_args
.get();
215 ASSERT_EQ(1u, event_args
->GetSize());
217 const base::DictionaryValue
* options_as_value
= NULL
;
218 ASSERT_TRUE(event_args
->GetDictionary(0, &options_as_value
));
220 GetMetadataRequestedOptions options
;
222 GetMetadataRequestedOptions::Populate(*options_as_value
, &options
));
223 EXPECT_EQ(kFileSystemId
, options
.file_system_id
);
224 EXPECT_EQ(kRequestId
, options
.request_id
);
225 EXPECT_EQ(kDirectoryPath
, options
.entry_path
);
226 EXPECT_TRUE(options
.thumbnail
);
229 TEST_F(FileSystemProviderOperationsGetMetadataTest
, Execute_NoListener
) {
230 util::LoggingDispatchEventImpl
dispatcher(false /* dispatch_reply */);
231 CallbackLogger callback_logger
;
233 GetMetadata
get_metadata(
234 NULL
, file_system_info_
, base::FilePath(kDirectoryPath
),
235 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL
,
236 base::Bind(&CallbackLogger::OnGetMetadata
,
237 base::Unretained(&callback_logger
)));
238 get_metadata
.SetDispatchEventImplForTesting(
239 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl
,
240 base::Unretained(&dispatcher
)));
242 EXPECT_FALSE(get_metadata
.Execute(kRequestId
));
245 TEST_F(FileSystemProviderOperationsGetMetadataTest
, OnSuccess
) {
246 util::LoggingDispatchEventImpl
dispatcher(true /* dispatch_reply */);
247 CallbackLogger callback_logger
;
249 GetMetadata
get_metadata(
250 NULL
, file_system_info_
, base::FilePath(kDirectoryPath
),
251 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL
,
252 base::Bind(&CallbackLogger::OnGetMetadata
,
253 base::Unretained(&callback_logger
)));
254 get_metadata
.SetDispatchEventImplForTesting(
255 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl
,
256 base::Unretained(&dispatcher
)));
258 EXPECT_TRUE(get_metadata
.Execute(kRequestId
));
260 // Sample input as JSON. Keep in sync with file_system_provider_api.idl.
261 // As for now, it is impossible to create *::Params class directly, not from
263 const std::string input
=
265 " \"testing-file-system\",\n" // kFileSystemId
266 " 2,\n" // kRequestId
268 " \"isDirectory\": false,\n"
269 " \"name\": \"blueberries.txt\",\n"
271 " \"modificationTime\": {\n"
272 " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
274 " \"mimeType\": \"text/plain\",\n" // kMimeType
275 " \"thumbnail\": \"DaTa:ImAgE/pNg;base64,\"\n" // kThumbnail
277 " 0\n" // execution_time
279 scoped_ptr
<RequestValue
> request_value
;
280 ASSERT_NO_FATAL_FAILURE(CreateRequestValueFromJSON(input
, &request_value
));
282 const bool has_more
= false;
283 get_metadata
.OnSuccess(kRequestId
, request_value
.Pass(), has_more
);
285 ASSERT_EQ(1u, callback_logger
.events().size());
286 CallbackLogger::Event
* event
= callback_logger
.events()[0];
287 EXPECT_EQ(base::File::FILE_OK
, event
->result());
289 const EntryMetadata
* metadata
= event
->metadata();
290 EXPECT_FALSE(metadata
->is_directory
);
291 EXPECT_EQ(4096, metadata
->size
);
292 base::Time expected_time
;
294 base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time
));
295 EXPECT_EQ(expected_time
, metadata
->modification_time
);
296 EXPECT_EQ(kMimeType
, metadata
->mime_type
);
297 EXPECT_EQ(kThumbnail
, metadata
->thumbnail
);
300 TEST_F(FileSystemProviderOperationsGetMetadataTest
, OnSuccess_InvalidMetadata
) {
301 util::LoggingDispatchEventImpl
dispatcher(true /* dispatch_reply */);
302 CallbackLogger callback_logger
;
304 GetMetadata
get_metadata(
305 NULL
, file_system_info_
, base::FilePath(kDirectoryPath
),
306 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL
,
307 base::Bind(&CallbackLogger::OnGetMetadata
,
308 base::Unretained(&callback_logger
)));
309 get_metadata
.SetDispatchEventImplForTesting(
310 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl
,
311 base::Unretained(&dispatcher
)));
313 EXPECT_TRUE(get_metadata
.Execute(kRequestId
));
315 // Sample input as JSON. Keep in sync with file_system_provider_api.idl.
316 // As for now, it is impossible to create *::Params class directly, not from
318 const std::string input
=
320 " \"testing-file-system\",\n" // kFileSystemId
321 " 2,\n" // kRequestId
323 " \"isDirectory\": false,\n"
324 " \"name\": \"blue/berries.txt\",\n"
326 " \"modificationTime\": {\n"
327 " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
329 " \"mimeType\": \"text/plain\",\n" // kMimeType
330 " \"thumbnail\": \"http://www.foobar.com/evil\"\n" // kThumbnail
332 " 0\n" // execution_time
335 scoped_ptr
<RequestValue
> request_value
;
336 ASSERT_NO_FATAL_FAILURE(CreateRequestValueFromJSON(input
, &request_value
));
338 const bool has_more
= false;
339 get_metadata
.OnSuccess(kRequestId
, request_value
.Pass(), has_more
);
341 ASSERT_EQ(1u, callback_logger
.events().size());
342 CallbackLogger::Event
* event
= callback_logger
.events()[0];
343 EXPECT_EQ(base::File::FILE_ERROR_IO
, event
->result());
345 const EntryMetadata
* metadata
= event
->metadata();
346 EXPECT_FALSE(metadata
);
349 TEST_F(FileSystemProviderOperationsGetMetadataTest
, OnError
) {
350 util::LoggingDispatchEventImpl
dispatcher(true /* dispatch_reply */);
351 CallbackLogger callback_logger
;
353 GetMetadata
get_metadata(
354 NULL
, file_system_info_
, base::FilePath(kDirectoryPath
),
355 ProvidedFileSystemInterface::METADATA_FIELD_THUMBNAIL
,
356 base::Bind(&CallbackLogger::OnGetMetadata
,
357 base::Unretained(&callback_logger
)));
358 get_metadata
.SetDispatchEventImplForTesting(
359 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl
,
360 base::Unretained(&dispatcher
)));
362 EXPECT_TRUE(get_metadata
.Execute(kRequestId
));
364 get_metadata
.OnError(kRequestId
,
365 scoped_ptr
<RequestValue
>(new RequestValue()),
366 base::File::FILE_ERROR_TOO_MANY_OPENED
);
368 ASSERT_EQ(1u, callback_logger
.events().size());
369 CallbackLogger::Event
* event
= callback_logger
.events()[0];
370 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED
, event
->result());
373 } // namespace operations
374 } // namespace file_system_provider
375 } // namespace chromeos