// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/command_line.h" #include "base/macros.h" #include "base/path_service.h" #include "base/strings/string_number_conversions.h" #include "base/thread_task_runner_handle.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/media/fake_desktop_media_list.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/test/browser_test_utils.h" #include "extensions/common/switches.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" namespace extensions { namespace { struct TestFlags { bool expect_screens; bool expect_windows; bool expect_tabs; bool expect_audio; content::DesktopMediaID selected_source; bool cancelled; // Following flags are set by FakeDesktopMediaPicker when it's created and // deleted. bool picker_created; bool picker_deleted; }; class FakeDesktopMediaPicker : public DesktopMediaPicker { public: explicit FakeDesktopMediaPicker(TestFlags* expectation) : expectation_(expectation), weak_factory_(this) { expectation_->picker_created = true; } ~FakeDesktopMediaPicker() override { expectation_->picker_deleted = true; } // DesktopMediaPicker interface. void Show(content::WebContents* web_contents, gfx::NativeWindow context, gfx::NativeWindow parent, const base::string16& app_name, const base::string16& target_name, scoped_ptr model, bool request_audio, const DoneCallback& done_callback) override { if (!expectation_->cancelled) { // Post a task to call the callback asynchronously. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind(&FakeDesktopMediaPicker::CallCallback, weak_factory_.GetWeakPtr(), done_callback)); } else { // If we expect the dialog to be cancelled then store the callback to // retain reference to the callback handler. done_callback_ = done_callback; } } private: void CallCallback(DoneCallback done_callback) { done_callback.Run(expectation_->selected_source); } TestFlags* expectation_; DoneCallback done_callback_; base::WeakPtrFactory weak_factory_; DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPicker); }; class FakeDesktopMediaPickerFactory : public DesktopCaptureChooseDesktopMediaFunction::PickerFactory { public: FakeDesktopMediaPickerFactory() {} ~FakeDesktopMediaPickerFactory() override {} void SetTestFlags(TestFlags* test_flags, int tests_count) { test_flags_ = test_flags; tests_count_ = tests_count; current_test_ = 0; } // DesktopCaptureChooseDesktopMediaFunction::PickerFactory interface. scoped_ptr CreateModel(bool show_screens, bool show_windows, bool show_tabs, bool show_audio) override { EXPECT_LE(current_test_, tests_count_); if (current_test_ >= tests_count_) return scoped_ptr(); EXPECT_EQ(test_flags_[current_test_].expect_screens, show_screens); EXPECT_EQ(test_flags_[current_test_].expect_windows, show_windows); EXPECT_EQ(test_flags_[current_test_].expect_tabs, show_tabs); EXPECT_EQ(test_flags_[current_test_].expect_audio, show_audio); return scoped_ptr(new FakeDesktopMediaList()); } scoped_ptr CreatePicker() override { EXPECT_LE(current_test_, tests_count_); if (current_test_ >= tests_count_) return scoped_ptr(); ++current_test_; return scoped_ptr( new FakeDesktopMediaPicker(test_flags_ + current_test_ - 1)); } private: TestFlags* test_flags_; int tests_count_; int current_test_; DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPickerFactory); }; class DesktopCaptureApiTest : public ExtensionApiTest { public: DesktopCaptureApiTest() { DesktopCaptureChooseDesktopMediaFunction:: SetPickerFactoryForTests(&picker_factory_); } ~DesktopCaptureApiTest() override { DesktopCaptureChooseDesktopMediaFunction:: SetPickerFactoryForTests(NULL); } protected: GURL GetURLForPath(const std::string& host, const std::string& path) { std::string port = base::UintToString(embedded_test_server()->port()); GURL::Replacements replacements; replacements.SetHostStr(host); replacements.SetPortStr(port); return embedded_test_server()->GetURL(path).ReplaceComponents(replacements); } FakeDesktopMediaPickerFactory picker_factory_; }; } // namespace // Flaky on Windows: http://crbug.com/301887 #if defined(OS_WIN) #define MAYBE_ChooseDesktopMedia DISABLED_ChooseDesktopMedia #else #define MAYBE_ChooseDesktopMedia ChooseDesktopMedia #endif IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, MAYBE_ChooseDesktopMedia) { // For tab and audio share, we need to turn on the flag, because the // functionality is currently behind the flags. base::CommandLine::ForCurrentProcess()->AppendSwitch( extensions::switches::kEnableTabForDesktopShare); base::CommandLine::ForCurrentProcess()->AppendSwitch( extensions::switches::kEnableDesktopCaptureAudio); // Each element in the following array corresponds to one test in // chrome/test/data/extensions/api_test/desktop_capture/test.js . TestFlags test_flags[] = { // pickerUiCanceled() {true, true, false, false, content::DesktopMediaID()}, // chooseMedia() {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, content::DesktopMediaID::kNullId)}, // screensOnly() {true, false, false, false, content::DesktopMediaID()}, // WindowsOnly() {false, true, false, false, content::DesktopMediaID()}, // tabOnly() {false, false, true, false, content::DesktopMediaID()}, // audioShare() {true, true, true, true, content::DesktopMediaID()}, // chooseMediaAndGetStream() {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, webrtc::kFullDesktopScreenId)}, // chooseMediaAndTryGetStreamWithInvalidId() {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, webrtc::kFullDesktopScreenId)}, // cancelDialog() {true, true, false, false, content::DesktopMediaID(), true}, // tabShareWithAudioGetStream() {false, false, true, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_WEB_CONTENTS, 0, true)}, // windowShareWithAudioGetStream() {false, true, false, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, 0, true)}, // screenShareWithAudioGetStream() {true, false, false, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, webrtc::kFullDesktopScreenId, true)}, // tabShareWithoutAudioGetStream() {false, false, true, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_WEB_CONTENTS, 0)}, // windowShareWithoutAudioGetStream() {false, true, false, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_WINDOW, 0)}, // screenShareWithoutAudioGetStream() {true, false, false, true, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, webrtc::kFullDesktopScreenId)}, }; picker_factory_.SetTestFlags(test_flags, arraysize(test_flags)); ASSERT_TRUE(RunExtensionTest("desktop_capture")) << message_; } // Test is flaky http://crbug.com/301887. IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, DISABLED_Delegation) { // Initialize test server. base::FilePath test_data; EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data)); embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII( "extensions/api_test/desktop_capture_delegate")); ASSERT_TRUE(embedded_test_server()->Start()); host_resolver()->AddRule("*", embedded_test_server()->base_url().host()); // Load extension. base::FilePath extension_path = test_data_dir_.AppendASCII("desktop_capture_delegate"); const Extension* extension = LoadExtensionWithFlags( extension_path, ExtensionBrowserTest::kFlagNone); ASSERT_TRUE(extension); ui_test_utils::NavigateToURL( browser(), GetURLForPath("example.com", "/example.com.html")); TestFlags test_flags[] = { {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, content::DesktopMediaID::kNullId)}, {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, content::DesktopMediaID::kNullId)}, {true, true, false, false, content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, content::DesktopMediaID::kNullId), true}, }; picker_factory_.SetTestFlags(test_flags, arraysize(test_flags)); bool result; content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); ASSERT_TRUE(content::ExecuteScriptAndExtractBool( web_contents, "getStream()", &result)); EXPECT_TRUE(result); ASSERT_TRUE(content::ExecuteScriptAndExtractBool( web_contents, "getStreamWithInvalidId()", &result)); EXPECT_TRUE(result); // Verify that the picker is closed once the tab is closed. content::WebContentsDestroyedWatcher destroyed_watcher(web_contents); ASSERT_TRUE(content::ExecuteScriptAndExtractBool( web_contents, "openPickerDialogAndReturn()", &result)); EXPECT_TRUE(result); EXPECT_TRUE(test_flags[2].picker_created); EXPECT_FALSE(test_flags[2].picker_deleted); web_contents->Close(); destroyed_watcher.Wait(); EXPECT_TRUE(test_flags[2].picker_deleted); } } // namespace extensions