file_manager_browsertest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright (c) 2013 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// Browser test for basic Chrome OS file manager functionality: 6// - The file list is updated when a file is added externally to the Downloads 7// folder. 8// - Selecting a file and copy-pasting it with the keyboard copies the file. 9// - Selecting a file and pressing delete deletes it. 10 11#include <deque> 12#include <string> 13 14#include "apps/app_window.h" 15#include "apps/app_window_registry.h" 16#include "ash/session_state_delegate.h" 17#include "ash/shell.h" 18#include "base/bind.h" 19#include "base/callback.h" 20#include "base/file_util.h" 21#include "base/files/file_path.h" 22#include "base/json/json_reader.h" 23#include "base/json/json_value_converter.h" 24#include "base/json/json_writer.h" 25#include "base/prefs/pref_service.h" 26#include "base/strings/string_piece.h" 27#include "base/strings/stringprintf.h" 28#include "base/strings/utf_string_conversions.h" 29#include "base/time/time.h" 30#include "chrome/browser/browser_process.h" 31#include "chrome/browser/chrome_notification_types.h" 32#include "chrome/browser/chromeos/drive/drive_integration_service.h" 33#include "chrome/browser/chromeos/drive/file_system_interface.h" 34#include "chrome/browser/chromeos/drive/test_util.h" 35#include "chrome/browser/chromeos/file_manager/app_id.h" 36#include "chrome/browser/chromeos/file_manager/drive_test_util.h" 37#include "chrome/browser/chromeos/file_manager/path_util.h" 38#include "chrome/browser/chromeos/file_manager/volume_manager.h" 39#include "chrome/browser/chromeos/login/user_manager.h" 40#include "chrome/browser/chromeos/profiles/profile_helper.h" 41#include "chrome/browser/drive/fake_drive_service.h" 42#include "chrome/browser/extensions/api/test/test_api.h" 43#include "chrome/browser/extensions/component_loader.h" 44#include "chrome/browser/extensions/extension_apitest.h" 45#include "chrome/browser/extensions/extension_test_message_listener.h" 46#include "chrome/browser/profiles/profile.h" 47#include "chrome/browser/profiles/profile_manager.h" 48#include "chrome/browser/ui/ash/multi_user/multi_user_util.h" 49#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" 50#include "chrome/common/chrome_switches.h" 51#include "chrome/common/pref_names.h" 52#include "chromeos/chromeos_switches.h" 53#include "content/public/browser/browser_context.h" 54#include "content/public/browser/notification_service.h" 55#include "content/public/test/test_utils.h" 56#include "extensions/common/extension.h" 57#include "google_apis/drive/gdata_wapi_parser.h" 58#include "google_apis/drive/test_util.h" 59#include "net/test/embedded_test_server/embedded_test_server.h" 60#include "webkit/browser/fileapi/external_mount_points.h" 61 62using drive::DriveIntegrationServiceFactory; 63 64namespace file_manager { 65namespace { 66 67enum EntryType { 68 FILE, 69 DIRECTORY, 70}; 71 72enum TargetVolume { 73 LOCAL_VOLUME, 74 DRIVE_VOLUME, 75}; 76 77enum SharedOption { 78 NONE, 79 SHARED, 80}; 81 82enum GuestMode { 83 NOT_IN_GUEST_MODE, 84 IN_GUEST_MODE, 85}; 86 87// This global operator is used from Google Test to format error messages. 88std::ostream& operator<<(std::ostream& os, const GuestMode& guest_mode) { 89 return os << (guest_mode == IN_GUEST_MODE ? 90 "IN_GUEST_MODE" : "NOT_IN_GUEST_MODE"); 91} 92 93// Maps the given string to EntryType. Returns true on success. 94bool MapStringToEntryType(const base::StringPiece& value, EntryType* output) { 95 if (value == "file") 96 *output = FILE; 97 else if (value == "directory") 98 *output = DIRECTORY; 99 else 100 return false; 101 return true; 102} 103 104// Maps the given string to SharedOption. Returns true on success. 105bool MapStringToSharedOption(const base::StringPiece& value, 106 SharedOption* output) { 107 if (value == "shared") 108 *output = SHARED; 109 else if (value == "none") 110 *output = NONE; 111 else 112 return false; 113 return true; 114} 115 116// Maps the given string to TargetVolume. Returns true on success. 117bool MapStringToTargetVolume(const base::StringPiece& value, 118 TargetVolume* output) { 119 if (value == "drive") 120 *output = DRIVE_VOLUME; 121 else if (value == "local") 122 *output = LOCAL_VOLUME; 123 else 124 return false; 125 return true; 126} 127 128// Maps the given string to base::Time. Returns true on success. 129bool MapStringToTime(const base::StringPiece& value, base::Time* time) { 130 return base::Time::FromString(value.as_string().c_str(), time); 131} 132 133// Test data of file or directory. 134struct TestEntryInfo { 135 TestEntryInfo() : type(FILE), shared_option(NONE) {} 136 137 TestEntryInfo(EntryType type, 138 const std::string& source_file_name, 139 const std::string& target_path, 140 const std::string& mime_type, 141 SharedOption shared_option, 142 const base::Time& last_modified_time) : 143 type(type), 144 source_file_name(source_file_name), 145 target_path(target_path), 146 mime_type(mime_type), 147 shared_option(shared_option), 148 last_modified_time(last_modified_time) { 149 } 150 151 EntryType type; 152 std::string source_file_name; // Source file name to be used as a prototype. 153 std::string target_path; // Target file or directory path. 154 std::string mime_type; 155 SharedOption shared_option; 156 base::Time last_modified_time; 157 158 // Registers the member information to the given converter. 159 static void RegisterJSONConverter( 160 base::JSONValueConverter<TestEntryInfo>* converter); 161}; 162 163// static 164void TestEntryInfo::RegisterJSONConverter( 165 base::JSONValueConverter<TestEntryInfo>* converter) { 166 converter->RegisterCustomField("type", 167 &TestEntryInfo::type, 168 &MapStringToEntryType); 169 converter->RegisterStringField("sourceFileName", 170 &TestEntryInfo::source_file_name); 171 converter->RegisterStringField("targetPath", &TestEntryInfo::target_path); 172 converter->RegisterStringField("mimeType", &TestEntryInfo::mime_type); 173 converter->RegisterCustomField("sharedOption", 174 &TestEntryInfo::shared_option, 175 &MapStringToSharedOption); 176 converter->RegisterCustomField("lastModifiedTime", 177 &TestEntryInfo::last_modified_time, 178 &MapStringToTime); 179} 180 181// Message from JavaScript to add entries. 182struct AddEntriesMessage { 183 // Target volume to be added the |entries|. 184 TargetVolume volume; 185 186 // Entries to be added. 187 ScopedVector<TestEntryInfo> entries; 188 189 // Registers the member information to the given converter. 190 static void RegisterJSONConverter( 191 base::JSONValueConverter<AddEntriesMessage>* converter); 192}; 193 194 195// static 196void AddEntriesMessage::RegisterJSONConverter( 197 base::JSONValueConverter<AddEntriesMessage>* converter) { 198 converter->RegisterCustomField("volume", 199 &AddEntriesMessage::volume, 200 &MapStringToTargetVolume); 201 converter->RegisterRepeatedMessage<TestEntryInfo>( 202 "entries", 203 &AddEntriesMessage::entries); 204} 205 206// The local volume class for test. 207// This class provides the operations for a test volume that simulates local 208// drive. 209class LocalTestVolume { 210 public: 211 // Adds this volume to the file system as a local volume. Returns true on 212 // success. 213 bool Mount(Profile* profile) { 214 if (local_path_.empty()) { 215 if (!tmp_dir_.CreateUniqueTempDir()) 216 return false; 217 local_path_ = tmp_dir_.path().Append("Downloads"); 218 } 219 220 return VolumeManager::Get(profile)->RegisterDownloadsDirectoryForTesting( 221 local_path_) && base::CreateDirectory(local_path_); 222 } 223 224 void CreateEntry(const TestEntryInfo& entry) { 225 const base::FilePath target_path = 226 local_path_.AppendASCII(entry.target_path); 227 228 entries_.insert(std::make_pair(target_path, entry)); 229 switch (entry.type) { 230 case FILE: { 231 const base::FilePath source_path = 232 google_apis::test_util::GetTestFilePath("chromeos/file_manager"). 233 AppendASCII(entry.source_file_name); 234 ASSERT_TRUE(base::CopyFile(source_path, target_path)) 235 << "Copy from " << source_path.value() 236 << " to " << target_path.value() << " failed."; 237 break; 238 } 239 case DIRECTORY: 240 ASSERT_TRUE(base::CreateDirectory(target_path)) << 241 "Failed to create a directory: " << target_path.value(); 242 break; 243 } 244 ASSERT_TRUE(UpdateModifiedTime(entry)); 245 } 246 247 private: 248 // Updates ModifiedTime of the entry and its parents by referring 249 // TestEntryInfo. Returns true on success. 250 bool UpdateModifiedTime(const TestEntryInfo& entry) { 251 const base::FilePath path = local_path_.AppendASCII(entry.target_path); 252 if (!base::TouchFile(path, entry.last_modified_time, 253 entry.last_modified_time)) 254 return false; 255 256 // Update the modified time of parent directories because it may be also 257 // affected by the update of child items. 258 if (path.DirName() != local_path_) { 259 const std::map<base::FilePath, const TestEntryInfo>::iterator it = 260 entries_.find(path.DirName()); 261 if (it == entries_.end()) 262 return false; 263 return UpdateModifiedTime(it->second); 264 } 265 return true; 266 } 267 268 base::FilePath local_path_; 269 base::ScopedTempDir tmp_dir_; 270 std::map<base::FilePath, const TestEntryInfo> entries_; 271}; 272 273// The drive volume class for test. 274// This class provides the operations for a test volume that simulates Google 275// drive. 276class DriveTestVolume { 277 public: 278 DriveTestVolume() : integration_service_(NULL) { 279 } 280 281 // Sends request to add this volume to the file system as Google drive. 282 // This method must be called at SetUp method of FileManagerBrowserTestBase. 283 // Returns true on success. 284 bool SetUp() { 285 if (!test_cache_root_.CreateUniqueTempDir()) 286 return false; 287 create_drive_integration_service_ = 288 base::Bind(&DriveTestVolume::CreateDriveIntegrationService, 289 base::Unretained(this)); 290 service_factory_for_test_.reset( 291 new DriveIntegrationServiceFactory::ScopedFactoryForTest( 292 &create_drive_integration_service_)); 293 return true; 294 } 295 296 void CreateEntry(Profile* profile, const TestEntryInfo& entry) { 297 const base::FilePath path = 298 base::FilePath::FromUTF8Unsafe(entry.target_path); 299 const std::string target_name = path.BaseName().AsUTF8Unsafe(); 300 301 // Obtain the parent entry. 302 drive::FileError error = drive::FILE_ERROR_OK; 303 scoped_ptr<drive::ResourceEntry> parent_entry(new drive::ResourceEntry); 304 integration_service_->file_system()->GetResourceEntry( 305 drive::util::GetDriveMyDriveRootPath().Append(path).DirName(), 306 google_apis::test_util::CreateCopyResultCallback( 307 &error, &parent_entry)); 308 drive::test_util::RunBlockingPoolTask(); 309 ASSERT_EQ(drive::FILE_ERROR_OK, error); 310 ASSERT_TRUE(parent_entry); 311 312 switch (entry.type) { 313 case FILE: 314 CreateFile(profile, 315 entry.source_file_name, 316 parent_entry->resource_id(), 317 target_name, 318 entry.mime_type, 319 entry.shared_option == SHARED, 320 entry.last_modified_time); 321 break; 322 case DIRECTORY: 323 CreateDirectory(profile, 324 parent_entry->resource_id(), 325 target_name, 326 entry.last_modified_time); 327 break; 328 } 329 } 330 331 // Creates an empty directory with the given |name| and |modification_time|. 332 void CreateDirectory(Profile* profile, 333 const std::string& parent_id, 334 const std::string& target_name, 335 const base::Time& modification_time) { 336 DCHECK(fake_drive_service_.count(profile)); 337 338 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 339 scoped_ptr<google_apis::ResourceEntry> resource_entry; 340 fake_drive_service_[profile]->AddNewDirectory( 341 parent_id, 342 target_name, 343 drive::DriveServiceInterface::AddNewDirectoryOptions(), 344 google_apis::test_util::CreateCopyResultCallback(&error, 345 &resource_entry)); 346 base::MessageLoop::current()->RunUntilIdle(); 347 ASSERT_EQ(google_apis::HTTP_CREATED, error); 348 ASSERT_TRUE(resource_entry); 349 350 fake_drive_service_[profile]->SetLastModifiedTime( 351 resource_entry->resource_id(), 352 modification_time, 353 google_apis::test_util::CreateCopyResultCallback(&error, 354 &resource_entry)); 355 base::MessageLoop::current()->RunUntilIdle(); 356 ASSERT_TRUE(error == google_apis::HTTP_SUCCESS); 357 ASSERT_TRUE(resource_entry); 358 CheckForUpdates(); 359 } 360 361 // Creates a test file with the given spec. 362 // Serves |test_file_name| file. Pass an empty string for an empty file. 363 void CreateFile(Profile* profile, 364 const std::string& source_file_name, 365 const std::string& parent_id, 366 const std::string& target_name, 367 const std::string& mime_type, 368 bool shared_with_me, 369 const base::Time& modification_time) { 370 DCHECK(fake_drive_service_.count(profile)); 371 372 google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR; 373 374 std::string content_data; 375 if (!source_file_name.empty()) { 376 base::FilePath source_file_path = 377 google_apis::test_util::GetTestFilePath("chromeos/file_manager"). 378 AppendASCII(source_file_name); 379 ASSERT_TRUE(base::ReadFileToString(source_file_path, &content_data)); 380 } 381 382 scoped_ptr<google_apis::ResourceEntry> resource_entry; 383 fake_drive_service_[profile]->AddNewFile( 384 mime_type, 385 content_data, 386 parent_id, 387 target_name, 388 shared_with_me, 389 google_apis::test_util::CreateCopyResultCallback(&error, 390 &resource_entry)); 391 base::MessageLoop::current()->RunUntilIdle(); 392 ASSERT_EQ(google_apis::HTTP_CREATED, error); 393 ASSERT_TRUE(resource_entry); 394 395 fake_drive_service_[profile]->SetLastModifiedTime( 396 resource_entry->resource_id(), 397 modification_time, 398 google_apis::test_util::CreateCopyResultCallback(&error, 399 &resource_entry)); 400 base::MessageLoop::current()->RunUntilIdle(); 401 ASSERT_EQ(google_apis::HTTP_SUCCESS, error); 402 ASSERT_TRUE(resource_entry); 403 404 CheckForUpdates(); 405 } 406 407 // Notifies FileSystem that the contents in FakeDriveService are 408 // changed, hence the new contents should be fetched. 409 void CheckForUpdates() { 410 if (integration_service_ && integration_service_->file_system()) { 411 integration_service_->file_system()->CheckForUpdates(); 412 } 413 } 414 415 // Sets the url base for the test server to be used to generate share urls 416 // on the files and directories. 417 void ConfigureShareUrlBase(Profile* profile, const GURL& share_url_base) { 418 DCHECK(fake_drive_service_.count(profile)); 419 fake_drive_service_[profile]->set_share_url_base(share_url_base); 420 } 421 422 drive::DriveIntegrationService* CreateDriveIntegrationService( 423 Profile* profile) { 424 base::FilePath subdir; 425 if (!base::CreateTemporaryDirInDir(test_cache_root_.path(), 426 base::FilePath::StringType(), 427 &subdir)) { 428 return NULL; 429 } 430 431 drive::FakeDriveService* const fake_drive_service = 432 new drive::FakeDriveService; 433 fake_drive_service->LoadResourceListForWapi( 434 "gdata/empty_feed.json"); 435 fake_drive_service->LoadAccountMetadataForWapi( 436 "gdata/account_metadata.json"); 437 fake_drive_service->LoadAppListForDriveApi("drive/applist.json"); 438 439 integration_service_ = new drive::DriveIntegrationService( 440 profile, NULL, fake_drive_service, std::string(), subdir, NULL); 441 fake_drive_service_[profile] = fake_drive_service; 442 return integration_service_; 443 } 444 445 private: 446 base::ScopedTempDir test_cache_root_; 447 std::map<Profile*, drive::FakeDriveService*> fake_drive_service_; 448 drive::DriveIntegrationService* integration_service_; 449 DriveIntegrationServiceFactory::FactoryCallback 450 create_drive_integration_service_; 451 scoped_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest> 452 service_factory_for_test_; 453}; 454 455// Listener to obtain the test relative messages synchronously. 456class FileManagerTestListener : public content::NotificationObserver { 457 public: 458 struct Message { 459 int type; 460 std::string message; 461 scoped_refptr<extensions::TestSendMessageFunction> function; 462 }; 463 464 FileManagerTestListener() { 465 registrar_.Add(this, 466 chrome::NOTIFICATION_EXTENSION_TEST_PASSED, 467 content::NotificationService::AllSources()); 468 registrar_.Add(this, 469 chrome::NOTIFICATION_EXTENSION_TEST_FAILED, 470 content::NotificationService::AllSources()); 471 registrar_.Add(this, 472 chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE, 473 content::NotificationService::AllSources()); 474 } 475 476 Message GetNextMessage() { 477 if (messages_.empty()) 478 content::RunMessageLoop(); 479 const Message entry = messages_.front(); 480 messages_.pop_front(); 481 return entry; 482 } 483 484 virtual void Observe(int type, 485 const content::NotificationSource& source, 486 const content::NotificationDetails& details) OVERRIDE { 487 Message entry; 488 entry.type = type; 489 entry.message = type != chrome::NOTIFICATION_EXTENSION_TEST_PASSED ? 490 *content::Details<std::string>(details).ptr() : 491 std::string(); 492 entry.function = type == chrome::NOTIFICATION_EXTENSION_TEST_MESSAGE ? 493 content::Source<extensions::TestSendMessageFunction>(source).ptr() : 494 NULL; 495 messages_.push_back(entry); 496 base::MessageLoopForUI::current()->Quit(); 497 } 498 499 private: 500 std::deque<Message> messages_; 501 content::NotificationRegistrar registrar_; 502}; 503 504// The base test class. 505class FileManagerBrowserTestBase : public ExtensionApiTest { 506 protected: 507 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE; 508 509 virtual void SetUpOnMainThread() OVERRIDE; 510 511 // Adds an incognito and guest-mode flags for tests in the guest mode. 512 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE; 513 514 // Loads our testing extension and sends it a string identifying the current 515 // test. 516 void StartTest(); 517 518 // Overriding point for test configurations. 519 virtual GuestMode GetGuestModeParam() const = 0; 520 virtual const char* GetTestCaseNameParam() const = 0; 521 virtual std::string OnMessage(const std::string& name, 522 const base::Value* value); 523 524 scoped_ptr<LocalTestVolume> local_volume_; 525 scoped_ptr<DriveTestVolume> drive_volume_; 526}; 527 528void FileManagerBrowserTestBase::SetUpInProcessBrowserTestFixture() { 529 ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 530 extensions::ComponentLoader::EnableBackgroundExtensionsForTesting(); 531 532 local_volume_.reset(new LocalTestVolume); 533 if (GetGuestModeParam() != IN_GUEST_MODE) { 534 drive_volume_.reset(new DriveTestVolume); 535 ASSERT_TRUE(drive_volume_->SetUp()); 536 } 537} 538 539void FileManagerBrowserTestBase::SetUpOnMainThread() { 540 ExtensionApiTest::SetUpOnMainThread(); 541 ASSERT_TRUE(local_volume_->Mount(profile())); 542 543 if (drive_volume_) { 544 // Install the web server to serve the mocked share dialog. 545 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 546 const GURL share_url_base(embedded_test_server()->GetURL( 547 "/chromeos/file_manager/share_dialog_mock/index.html")); 548 drive_volume_->ConfigureShareUrlBase(profile(), share_url_base); 549 test_util::WaitUntilDriveMountPointIsAdded(profile()); 550 } 551} 552 553void FileManagerBrowserTestBase::SetUpCommandLine(CommandLine* command_line) { 554 if (GetGuestModeParam() == IN_GUEST_MODE) { 555 command_line->AppendSwitch(chromeos::switches::kGuestSession); 556 command_line->AppendSwitchNative(chromeos::switches::kLoginUser, ""); 557 command_line->AppendSwitch(switches::kIncognito); 558 } 559 ExtensionApiTest::SetUpCommandLine(command_line); 560} 561 562void FileManagerBrowserTestBase::StartTest() { 563 // Launch the extension. 564 base::FilePath path = test_data_dir_.AppendASCII("file_manager_browsertest"); 565 const extensions::Extension* extension = LoadExtensionAsComponent(path); 566 ASSERT_TRUE(extension); 567 568 // Handle the messages from JavaScript. 569 // The while loop is break when the test is passed or failed. 570 FileManagerTestListener listener; 571 while (true) { 572 FileManagerTestListener::Message entry = listener.GetNextMessage(); 573 if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_PASSED) { 574 // Test succeed. 575 break; 576 } else if (entry.type == chrome::NOTIFICATION_EXTENSION_TEST_FAILED) { 577 // Test failed. 578 ADD_FAILURE() << entry.message; 579 break; 580 } 581 582 // Parse the message value as JSON. 583 const scoped_ptr<const base::Value> value( 584 base::JSONReader::Read(entry.message)); 585 586 // If the message is not the expected format, just ignore it. 587 const base::DictionaryValue* message_dictionary = NULL; 588 std::string name; 589 if (!value || !value->GetAsDictionary(&message_dictionary) || 590 !message_dictionary->GetString("name", &name)) 591 continue; 592 593 entry.function->Reply(OnMessage(name, value.get())); 594 } 595} 596 597std::string FileManagerBrowserTestBase::OnMessage(const std::string& name, 598 const base::Value* value) { 599 if (name == "getTestName") { 600 // Pass the test case name. 601 return GetTestCaseNameParam(); 602 } else if (name == "getRootPaths") { 603 // Pass the root paths. 604 const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 605 res->SetString("downloads", 606 "/" + util::GetDownloadsMountPointName(profile())); 607 res->SetString("drive", 608 "/" + drive::util::GetDriveMountPointPath(profile() 609 ).BaseName().AsUTF8Unsafe() + "/root"); 610 std::string jsonString; 611 base::JSONWriter::Write(res.get(), &jsonString); 612 return jsonString; 613 } else if (name == "isInGuestMode") { 614 // Obtain whether the test is in guest mode or not. 615 return GetGuestModeParam() ? "true" : "false"; 616 } else if (name == "getCwsWidgetContainerMockUrl") { 617 // Obtain whether the test is in guest mode or not. 618 const GURL url = embedded_test_server()->GetURL( 619 "/chromeos/file_manager/cws_container_mock/index.html"); 620 std::string origin = url.GetOrigin().spec(); 621 622 // Removes trailing a slash. 623 if (*origin.rbegin() == '/') 624 origin.resize(origin.length() - 1); 625 626 const scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 627 res->SetString("url", url.spec()); 628 res->SetString("origin", origin); 629 std::string jsonString; 630 base::JSONWriter::Write(res.get(), &jsonString); 631 return jsonString; 632 } else if (name == "addEntries") { 633 // Add entries to the specified volume. 634 base::JSONValueConverter<AddEntriesMessage> add_entries_message_converter; 635 AddEntriesMessage message; 636 if (!add_entries_message_converter.Convert(*value, &message)) 637 return "onError"; 638 for (size_t i = 0; i < message.entries.size(); ++i) { 639 switch (message.volume) { 640 case LOCAL_VOLUME: 641 local_volume_->CreateEntry(*message.entries[i]); 642 break; 643 case DRIVE_VOLUME: 644 if (drive_volume_) 645 drive_volume_->CreateEntry(profile(), *message.entries[i]); 646 break; 647 default: 648 NOTREACHED(); 649 break; 650 } 651 } 652 return "onEntryAdded"; 653 } 654 return "unknownMessage"; 655} 656 657// Parameter of FileManagerBrowserTest. 658// The second value is the case name of JavaScript. 659typedef std::tr1::tuple<GuestMode, const char*> TestParameter; 660 661// Test fixture class for normal (not multi-profile related) tests. 662class FileManagerBrowserTest : 663 public FileManagerBrowserTestBase, 664 public ::testing::WithParamInterface<TestParameter> { 665 virtual GuestMode GetGuestModeParam() const OVERRIDE { 666 return std::tr1::get<0>(GetParam()); 667 } 668 virtual const char* GetTestCaseNameParam() const OVERRIDE { 669 return std::tr1::get<1>(GetParam()); 670 } 671}; 672 673IN_PROC_BROWSER_TEST_P(FileManagerBrowserTest, Test) { 674 StartTest(); 675} 676 677INSTANTIATE_TEST_CASE_P( 678 FileDisplay, 679 FileManagerBrowserTest, 680 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDownloads"), 681 TestParameter(IN_GUEST_MODE, "fileDisplayDownloads"), 682 TestParameter(NOT_IN_GUEST_MODE, "fileDisplayDrive"))); 683 684INSTANTIATE_TEST_CASE_P( 685 OpenSpecialTypes, 686 FileManagerBrowserTest, 687 ::testing::Values(TestParameter(IN_GUEST_MODE, "videoOpenDownloads"), 688 TestParameter(NOT_IN_GUEST_MODE, "videoOpenDownloads"), 689 TestParameter(NOT_IN_GUEST_MODE, "videoOpenDrive"), 690// Audio player tests are temporary disabled. 691// TODO(yoshiki): Re-enable them: crbug.com/340955. 692// TestParameter(IN_GUEST_MODE, "audioOpenDownloads"), 693// TestParameter(NOT_IN_GUEST_MODE, "audioOpenDownloads"), 694// TestParameter(NOT_IN_GUEST_MODE, "audioOpenDrive"), 695 TestParameter(IN_GUEST_MODE, "galleryOpenDownloads"), 696 TestParameter(NOT_IN_GUEST_MODE, 697 "galleryOpenDownloads"), 698 TestParameter(NOT_IN_GUEST_MODE, "galleryOpenDrive"))); 699 700INSTANTIATE_TEST_CASE_P( 701 KeyboardOperations, 702 FileManagerBrowserTest, 703 ::testing::Values(TestParameter(IN_GUEST_MODE, "keyboardDeleteDownloads"), 704 TestParameter(NOT_IN_GUEST_MODE, 705 "keyboardDeleteDownloads"), 706 TestParameter(NOT_IN_GUEST_MODE, "keyboardDeleteDrive"), 707 TestParameter(IN_GUEST_MODE, "keyboardCopyDownloads"), 708 TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDownloads"), 709 TestParameter(NOT_IN_GUEST_MODE, "keyboardCopyDrive"))); 710 711INSTANTIATE_TEST_CASE_P( 712 DriveSpecific, 713 FileManagerBrowserTest, 714 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openSidebarRecent"), 715 TestParameter(NOT_IN_GUEST_MODE, "openSidebarOffline"), 716 TestParameter(NOT_IN_GUEST_MODE, 717 "openSidebarSharedWithMe"), 718 TestParameter(NOT_IN_GUEST_MODE, "autocomplete"))); 719 720INSTANTIATE_TEST_CASE_P( 721 Transfer, 722 FileManagerBrowserTest, 723 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, 724 "transferFromDriveToDownloads"), 725 TestParameter(NOT_IN_GUEST_MODE, 726 "transferFromDownloadsToDrive"), 727 TestParameter(NOT_IN_GUEST_MODE, 728 "transferFromSharedToDownloads"), 729 TestParameter(NOT_IN_GUEST_MODE, 730 "transferFromSharedToDrive"), 731 TestParameter(NOT_IN_GUEST_MODE, 732 "transferFromRecentToDownloads"), 733 TestParameter(NOT_IN_GUEST_MODE, 734 "transferFromRecentToDrive"), 735 TestParameter(NOT_IN_GUEST_MODE, 736 "transferFromOfflineToDownloads"), 737 TestParameter(NOT_IN_GUEST_MODE, 738 "transferFromOfflineToDrive"))); 739 740INSTANTIATE_TEST_CASE_P( 741 HideSearchBox, 742 FileManagerBrowserTest, 743 ::testing::Values(TestParameter(IN_GUEST_MODE, "hideSearchBox"), 744 TestParameter(NOT_IN_GUEST_MODE, "hideSearchBox"))); 745 746INSTANTIATE_TEST_CASE_P( 747 RestorePrefs, 748 FileManagerBrowserTest, 749 ::testing::Values(TestParameter(IN_GUEST_MODE, "restoreSortColumn"), 750 TestParameter(NOT_IN_GUEST_MODE, "restoreSortColumn"), 751 TestParameter(IN_GUEST_MODE, "restoreCurrentView"), 752 TestParameter(NOT_IN_GUEST_MODE, "restoreCurrentView"))); 753 754INSTANTIATE_TEST_CASE_P( 755 ShareDialog, 756 FileManagerBrowserTest, 757 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "shareFile"), 758 TestParameter(NOT_IN_GUEST_MODE, "shareDirectory"))); 759 760INSTANTIATE_TEST_CASE_P( 761 RestoreGeometry, 762 FileManagerBrowserTest, 763 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "restoreGeometry"), 764 TestParameter(IN_GUEST_MODE, "restoreGeometry"))); 765 766INSTANTIATE_TEST_CASE_P( 767 Traverse, 768 FileManagerBrowserTest, 769 ::testing::Values(TestParameter(IN_GUEST_MODE, "traverseDownloads"), 770 TestParameter(NOT_IN_GUEST_MODE, "traverseDownloads"), 771 TestParameter(NOT_IN_GUEST_MODE, "traverseDrive"))); 772 773INSTANTIATE_TEST_CASE_P( 774 SuggestAppDialog, 775 FileManagerBrowserTest, 776 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "suggestAppDialog"))); 777 778INSTANTIATE_TEST_CASE_P( 779 ExecuteDefaultTaskOnDownloads, 780 FileManagerBrowserTest, 781 ::testing::Values( 782 TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskOnDownloads"), 783 TestParameter(IN_GUEST_MODE, "executeDefaultTaskOnDownloads"))); 784 785INSTANTIATE_TEST_CASE_P( 786 ExecuteDefaultTaskOnDrive, 787 FileManagerBrowserTest, 788 ::testing::Values( 789 TestParameter(NOT_IN_GUEST_MODE, "executeDefaultTaskOnDrive"))); 790 791INSTANTIATE_TEST_CASE_P( 792 NavigationList, 793 FileManagerBrowserTest, 794 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, 795 "traverseNavigationList"))); 796 797INSTANTIATE_TEST_CASE_P( 798 TabIndex, 799 FileManagerBrowserTest, 800 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "searchBoxFocus"))); 801 802INSTANTIATE_TEST_CASE_P( 803 Thumbnails, 804 FileManagerBrowserTest, 805 ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "thumbnailsDownloads"), 806 TestParameter(IN_GUEST_MODE, "thumbnailsDownloads"))); 807 808// Structure to describe an account info. 809struct TestAccountInfo { 810 const char* const email; 811 const char* const hash; 812 const char* const display_name; 813}; 814 815enum { 816 DUMMY_ACCOUNT_INDEX = 0, 817 PRIMARY_ACCOUNT_INDEX = 1, 818 SECONDARY_ACCOUNT_INDEX_START = 2, 819}; 820 821static const TestAccountInfo kTestAccounts[] = { 822 {"__dummy__@invalid.domain", "hashdummy", "Dummy Account"}, 823 {"alice@invalid.domain", "hashalice", "Alice"}, 824 {"bob@invalid.domain", "hashbob", "Bob"}, 825 {"charlie@invalid.domain", "hashcharlie", "Charlie"}, 826}; 827 828// Test fixture class for testing multi-profile features. 829class MultiProfileFileManagerBrowserTest : public FileManagerBrowserTestBase { 830 protected: 831 // Enables multi-profiles. 832 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 833 FileManagerBrowserTestBase::SetUpCommandLine(command_line); 834 command_line->AppendSwitch(switches::kMultiProfiles); 835 // Logs in to a dummy profile (For making MultiProfileWindowManager happy; 836 // browser test creates a default window and the manager tries to assign a 837 // user for it, and we need a profile connected to a user.) 838 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser, 839 kTestAccounts[DUMMY_ACCOUNT_INDEX].email); 840 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, 841 kTestAccounts[DUMMY_ACCOUNT_INDEX].hash); 842 } 843 844 // Logs in to the primary profile of this test. 845 virtual void SetUpOnMainThread() OVERRIDE { 846 const TestAccountInfo& info = kTestAccounts[PRIMARY_ACCOUNT_INDEX]; 847 848 AddUser(info, true); 849 chromeos::UserManager* const user_manager = chromeos::UserManager::Get(); 850 if (user_manager->GetActiveUser() != user_manager->FindUser(info.email)) 851 chromeos::UserManager::Get()->SwitchActiveUser(info.email); 852 FileManagerBrowserTestBase::SetUpOnMainThread(); 853 } 854 855 // Loads all users to the current session and sets up necessary fields. 856 // This is used for preparing all accounts in PRE_ test setup, and for testing 857 // actual login behavior. 858 void AddAllUsers() { 859 for (size_t i = 0; i < arraysize(kTestAccounts); ++i) 860 AddUser(kTestAccounts[i], i >= SECONDARY_ACCOUNT_INDEX_START); 861 } 862 863 // Add as many as users 864 void AddExtraUsersForStressTesting() { 865 ash::Shell* const shell = ash::Shell::GetInstance(); 866 const size_t maxLogin = 867 shell->session_state_delegate()->GetMaximumNumberOfLoggedInUsers(); 868 869 for (int i = 0; i + arraysize(kTestAccounts) < maxLogin; ++i) { 870 const std::string email = base::StringPrintf("user%d@invalid.domain", i); 871 const std::string hash = base::StringPrintf("hashuser%d", i); 872 const std::string name = base::StringPrintf("Additional User %d", i); 873 const TestAccountInfo info = {email.c_str(), hash.c_str(), name.c_str()}; 874 AddUser(info, true); 875 } 876 } 877 878 // Returns primary profile (if it is already created.) 879 virtual Profile* profile() OVERRIDE { 880 Profile* const profile = chromeos::ProfileHelper::GetProfileByUserIdHash( 881 kTestAccounts[PRIMARY_ACCOUNT_INDEX].hash); 882 return profile ? profile : FileManagerBrowserTestBase::profile(); 883 } 884 885 // Sets the test case name (used as a function name in test_cases.js to call.) 886 void set_test_case_name(const std::string& name) { test_case_name_ = name; } 887 888 // Adds a new user for testing to the current session. 889 void AddUser(const TestAccountInfo& info, bool log_in) { 890 chromeos::UserManager* const user_manager = chromeos::UserManager::Get(); 891 if (log_in) 892 user_manager->UserLoggedIn(info.email, info.hash, false); 893 user_manager->SaveUserDisplayName(info.email, 894 base::UTF8ToUTF16(info.display_name)); 895 chromeos::ProfileHelper::GetProfileByUserIdHash(info.hash)->GetPrefs()-> 896 SetString(prefs::kGoogleServicesUsername, info.email); 897 } 898 899 private: 900 virtual GuestMode GetGuestModeParam() const OVERRIDE { 901 return NOT_IN_GUEST_MODE; 902 } 903 904 virtual const char* GetTestCaseNameParam() const OVERRIDE { 905 return test_case_name_.c_str(); 906 } 907 908 virtual std::string OnMessage(const std::string& name, 909 const base::Value* value) OVERRIDE { 910 if (name == "addAllUsers") { 911 AddAllUsers(); 912 return "true"; 913 } else if (name == "getWindowOwnerId") { 914 chrome::MultiUserWindowManager* const window_manager = 915 chrome::MultiUserWindowManager::GetInstance(); 916 apps::AppWindowRegistry* const app_window_registry = 917 apps::AppWindowRegistry::Get(profile()); 918 DCHECK(window_manager); 919 DCHECK(app_window_registry); 920 921 const apps::AppWindowRegistry::AppWindowList& list = 922 app_window_registry->GetAppWindowsForApp( 923 file_manager::kFileManagerAppId); 924 return list.size() == 1u ? 925 window_manager->GetUserPresentingWindow( 926 list.front()->GetNativeWindow()) : ""; 927 } 928 return FileManagerBrowserTestBase::OnMessage(name, value); 929 } 930 931 std::string test_case_name_; 932}; 933 934IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, PRE_BasicDownloads) { 935 AddAllUsers(); 936} 937 938IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, BasicDownloads) { 939 AddAllUsers(); 940 941 // Sanity check that normal operations work in multi-profile setting as well. 942 set_test_case_name("keyboardCopyDownloads"); 943 StartTest(); 944} 945 946IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, PRE_BasicDrive) { 947 AddAllUsers(); 948} 949 950IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, BasicDrive) { 951 AddAllUsers(); 952 953 // Sanity check that normal operations work in multi-profile setting as well. 954 set_test_case_name("keyboardCopyDrive"); 955 StartTest(); 956} 957 958IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, PRE_Badge) { 959 AddAllUsers(); 960} 961 962IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, Badge) { 963 // Test the profile badge to be correctly shown and hidden. 964 set_test_case_name("multiProfileBadge"); 965 StartTest(); 966} 967 968IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, 969 PRE_VisitDesktopMenu) { 970 AddAllUsers(); 971} 972 973IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, VisitDesktopMenu) { 974 // Test for the menu item for visiting other profile's desktop. 975 set_test_case_name("multiProfileVisitDesktopMenu"); 976 StartTest(); 977} 978 979IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, PRE_MaxUser) { 980 AddAllUsers(); 981 AddExtraUsersForStressTesting(); 982} 983 984IN_PROC_BROWSER_TEST_F(MultiProfileFileManagerBrowserTest, MaxUser) { 985 // Run the same test as VisitDesktopMenu with maximum number of users logged 986 // in and checks that nothing goes wrong. Here, the primary user (alice) logs 987 // in first, then the "extra" users follow, and then lastly the other users 988 // (bob and charlie) are added in the test. Thus the existing test verifies 989 // that the feature is effectively working with lastly logged in users. 990 AddExtraUsersForStressTesting(); 991 992 set_test_case_name("multiProfileVisitDesktopMenu"); 993 StartTest(); 994} 995 996} // namespace 997} // namespace file_manager 998