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/read_directory.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 int kRequestId = 2; 30const base::FilePath::CharType kDirectoryPath[] = "/directory"; 31 32// Callback invocation logger. Acts as a fileapi end-point. 33class CallbackLogger { 34 public: 35 class Event { 36 public: 37 Event(base::File::Error result, 38 const storage::AsyncFileUtil::EntryList& entry_list, 39 bool has_more) 40 : result_(result), entry_list_(entry_list), has_more_(has_more) {} 41 virtual ~Event() {} 42 43 base::File::Error result() { return result_; } 44 const storage::AsyncFileUtil::EntryList& entry_list() { 45 return entry_list_; 46 } 47 bool has_more() { return has_more_; } 48 49 private: 50 base::File::Error result_; 51 storage::AsyncFileUtil::EntryList entry_list_; 52 bool has_more_; 53 54 DISALLOW_COPY_AND_ASSIGN(Event); 55 }; 56 57 CallbackLogger() {} 58 virtual ~CallbackLogger() {} 59 60 void OnReadDirectory(base::File::Error result, 61 const storage::AsyncFileUtil::EntryList& entry_list, 62 bool has_more) { 63 events_.push_back(new Event(result, entry_list, has_more)); 64 } 65 66 ScopedVector<Event>& events() { return events_; } 67 68 private: 69 ScopedVector<Event> events_; 70 bool dispatch_reply_; 71 72 DISALLOW_COPY_AND_ASSIGN(CallbackLogger); 73}; 74 75} // namespace 76 77class FileSystemProviderOperationsReadDirectoryTest : public testing::Test { 78 protected: 79 FileSystemProviderOperationsReadDirectoryTest() {} 80 virtual ~FileSystemProviderOperationsReadDirectoryTest() {} 81 82 virtual void SetUp() OVERRIDE { 83 file_system_info_ = 84 ProvidedFileSystemInfo(kExtensionId, 85 kFileSystemId, 86 "" /* display_name */, 87 false /* writable */, 88 base::FilePath() /* mount_path */); 89 } 90 91 ProvidedFileSystemInfo file_system_info_; 92}; 93 94TEST_F(FileSystemProviderOperationsReadDirectoryTest, Execute) { 95 using extensions::api::file_system_provider::ReadDirectoryRequestedOptions; 96 97 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 98 CallbackLogger callback_logger; 99 100 ReadDirectory read_directory(NULL, 101 file_system_info_, 102 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 103 base::Bind(&CallbackLogger::OnReadDirectory, 104 base::Unretained(&callback_logger))); 105 read_directory.SetDispatchEventImplForTesting( 106 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 107 base::Unretained(&dispatcher))); 108 109 EXPECT_TRUE(read_directory.Execute(kRequestId)); 110 111 ASSERT_EQ(1u, dispatcher.events().size()); 112 extensions::Event* event = dispatcher.events()[0]; 113 EXPECT_EQ(extensions::api::file_system_provider::OnReadDirectoryRequested:: 114 kEventName, 115 event->event_name); 116 base::ListValue* event_args = event->event_args.get(); 117 ASSERT_EQ(1u, event_args->GetSize()); 118 119 const base::DictionaryValue* options_as_value = NULL; 120 ASSERT_TRUE(event_args->GetDictionary(0, &options_as_value)); 121 122 ReadDirectoryRequestedOptions options; 123 ASSERT_TRUE( 124 ReadDirectoryRequestedOptions::Populate(*options_as_value, &options)); 125 EXPECT_EQ(kFileSystemId, options.file_system_id); 126 EXPECT_EQ(kRequestId, options.request_id); 127 EXPECT_EQ(kDirectoryPath, options.directory_path); 128} 129 130TEST_F(FileSystemProviderOperationsReadDirectoryTest, Execute_NoListener) { 131 util::LoggingDispatchEventImpl dispatcher(false /* dispatch_reply */); 132 CallbackLogger callback_logger; 133 134 ReadDirectory read_directory(NULL, 135 file_system_info_, 136 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 137 base::Bind(&CallbackLogger::OnReadDirectory, 138 base::Unretained(&callback_logger))); 139 read_directory.SetDispatchEventImplForTesting( 140 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 141 base::Unretained(&dispatcher))); 142 143 EXPECT_FALSE(read_directory.Execute(kRequestId)); 144} 145 146TEST_F(FileSystemProviderOperationsReadDirectoryTest, OnSuccess) { 147 using extensions::api::file_system_provider_internal:: 148 ReadDirectoryRequestedSuccess::Params; 149 150 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 151 CallbackLogger callback_logger; 152 153 ReadDirectory read_directory(NULL, 154 file_system_info_, 155 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 156 base::Bind(&CallbackLogger::OnReadDirectory, 157 base::Unretained(&callback_logger))); 158 read_directory.SetDispatchEventImplForTesting( 159 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 160 base::Unretained(&dispatcher))); 161 162 EXPECT_TRUE(read_directory.Execute(kRequestId)); 163 164 // Sample input as JSON. Keep in sync with file_system_provider_api.idl. 165 // As for now, it is impossible to create *::Params class directly, not from 166 // base::Value. 167 const std::string input = 168 "[\n" 169 " \"testing-file-system\",\n" // kFileSystemId 170 " 2,\n" // kRequestId 171 " [\n" 172 " {\n" 173 " \"isDirectory\": false,\n" 174 " \"name\": \"blueberries.txt\",\n" 175 " \"size\": 4096,\n" 176 " \"modificationTime\": {\n" 177 " \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n" 178 " }\n" 179 " }\n" 180 " ],\n" 181 " false,\n" // has_more 182 " 0\n" // execution_time 183 "]\n"; 184 185 int json_error_code; 186 std::string json_error_msg; 187 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( 188 input, base::JSON_PARSE_RFC, &json_error_code, &json_error_msg)); 189 ASSERT_TRUE(value.get()) << json_error_msg; 190 191 base::ListValue* value_as_list; 192 ASSERT_TRUE(value->GetAsList(&value_as_list)); 193 scoped_ptr<Params> params(Params::Create(*value_as_list)); 194 ASSERT_TRUE(params.get()); 195 scoped_ptr<RequestValue> request_value( 196 RequestValue::CreateForReadDirectorySuccess(params.Pass())); 197 ASSERT_TRUE(request_value.get()); 198 199 const bool has_more = false; 200 read_directory.OnSuccess(kRequestId, request_value.Pass(), has_more); 201 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 206 ASSERT_EQ(1u, event->entry_list().size()); 207 const storage::DirectoryEntry entry = event->entry_list()[0]; 208 EXPECT_FALSE(entry.is_directory); 209 EXPECT_EQ("blueberries.txt", entry.name); 210 EXPECT_EQ(4096, entry.size); 211 base::Time expected_time; 212 EXPECT_TRUE( 213 base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time)); 214 EXPECT_EQ(expected_time, entry.last_modified_time); 215} 216 217TEST_F(FileSystemProviderOperationsReadDirectoryTest, OnError) { 218 util::LoggingDispatchEventImpl dispatcher(true /* dispatch_reply */); 219 CallbackLogger callback_logger; 220 221 ReadDirectory read_directory(NULL, 222 file_system_info_, 223 base::FilePath::FromUTF8Unsafe(kDirectoryPath), 224 base::Bind(&CallbackLogger::OnReadDirectory, 225 base::Unretained(&callback_logger))); 226 read_directory.SetDispatchEventImplForTesting( 227 base::Bind(&util::LoggingDispatchEventImpl::OnDispatchEventImpl, 228 base::Unretained(&dispatcher))); 229 230 EXPECT_TRUE(read_directory.Execute(kRequestId)); 231 232 read_directory.OnError(kRequestId, 233 scoped_ptr<RequestValue>(new RequestValue()), 234 base::File::FILE_ERROR_TOO_MANY_OPENED); 235 236 ASSERT_EQ(1u, callback_logger.events().size()); 237 CallbackLogger::Event* event = callback_logger.events()[0]; 238 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, event->result()); 239 ASSERT_EQ(0u, event->entry_list().size()); 240} 241 242} // namespace operations 243} // namespace file_system_provider 244} // namespace chromeos 245