1 // Copyright 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 #include <queue>
6
7 #include "base/command_line.h"
8 #include "base/path_service.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h"
11 #include "chrome/browser/extensions/extension_apitest.h"
12 #include "chrome/browser/media/fake_desktop_media_list.h"
13 #include "chrome/browser/ui/tabs/tab_strip_model.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/test/browser_test_utils.h"
18 #include "net/dns/mock_host_resolver.h"
19 #include "net/test/embedded_test_server/embedded_test_server.h"
20 #include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h"
21
22 namespace extensions {
23
24 namespace {
25
26 struct TestFlags {
27 bool expect_screens;
28 bool expect_windows;
29 content::DesktopMediaID selected_source;
30 bool cancelled;
31
32 // Following flags are set by FakeDesktopMediaPicker when it's created and
33 // deleted.
34 bool picker_created;
35 bool picker_deleted;
36 };
37
38 class FakeDesktopMediaPicker : public DesktopMediaPicker {
39 public:
FakeDesktopMediaPicker(TestFlags * expectation)40 explicit FakeDesktopMediaPicker(TestFlags* expectation)
41 : expectation_(expectation),
42 weak_factory_(this) {
43 expectation_->picker_created = true;
44 }
~FakeDesktopMediaPicker()45 virtual ~FakeDesktopMediaPicker() {
46 expectation_->picker_deleted = true;
47 }
48
49 // DesktopMediaPicker interface.
Show(content::WebContents * web_contents,gfx::NativeWindow context,gfx::NativeWindow parent,const base::string16 & app_name,const base::string16 & target_name,scoped_ptr<DesktopMediaList> model,const DoneCallback & done_callback)50 virtual void Show(content::WebContents* web_contents,
51 gfx::NativeWindow context,
52 gfx::NativeWindow parent,
53 const base::string16& app_name,
54 const base::string16& target_name,
55 scoped_ptr<DesktopMediaList> model,
56 const DoneCallback& done_callback) OVERRIDE {
57 if (!expectation_->cancelled) {
58 // Post a task to call the callback asynchronously.
59 base::ThreadTaskRunnerHandle::Get()->PostTask(
60 FROM_HERE,
61 base::Bind(&FakeDesktopMediaPicker::CallCallback,
62 weak_factory_.GetWeakPtr(), done_callback));
63 } else {
64 // If we expect the dialog to be cancelled then store the callback to
65 // retain reference to the callback handler.
66 done_callback_ = done_callback;
67 }
68 }
69
70 private:
CallCallback(DoneCallback done_callback)71 void CallCallback(DoneCallback done_callback) {
72 done_callback.Run(expectation_->selected_source);
73 }
74
75 TestFlags* expectation_;
76 DoneCallback done_callback_;
77
78 base::WeakPtrFactory<FakeDesktopMediaPicker> weak_factory_;
79
80 DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPicker);
81 };
82
83 class FakeDesktopMediaPickerFactory :
84 public DesktopCaptureChooseDesktopMediaFunction::PickerFactory {
85 public:
FakeDesktopMediaPickerFactory()86 FakeDesktopMediaPickerFactory() {}
~FakeDesktopMediaPickerFactory()87 virtual ~FakeDesktopMediaPickerFactory() {}
88
SetTestFlags(TestFlags * test_flags,int tests_count)89 void SetTestFlags(TestFlags* test_flags, int tests_count) {
90 test_flags_ = test_flags;
91 tests_count_ = tests_count;
92 current_test_ = 0;
93 }
94
95 // DesktopCaptureChooseDesktopMediaFunction::PickerFactory interface.
CreateModel(bool show_screens,bool show_windows)96 virtual scoped_ptr<DesktopMediaList> CreateModel(
97 bool show_screens,
98 bool show_windows) OVERRIDE {
99 EXPECT_LE(current_test_, tests_count_);
100 if (current_test_ >= tests_count_)
101 return scoped_ptr<DesktopMediaList>();
102 EXPECT_EQ(test_flags_[current_test_].expect_screens, show_screens);
103 EXPECT_EQ(test_flags_[current_test_].expect_windows, show_windows);
104 return scoped_ptr<DesktopMediaList>(new FakeDesktopMediaList());
105 }
106
CreatePicker()107 virtual scoped_ptr<DesktopMediaPicker> CreatePicker() OVERRIDE {
108 EXPECT_LE(current_test_, tests_count_);
109 if (current_test_ >= tests_count_)
110 return scoped_ptr<DesktopMediaPicker>();
111 ++current_test_;
112 return scoped_ptr<DesktopMediaPicker>(
113 new FakeDesktopMediaPicker(test_flags_ + current_test_ - 1));
114 }
115
116 private:
117 TestFlags* test_flags_;
118 int tests_count_;
119 int current_test_;
120
121 DISALLOW_COPY_AND_ASSIGN(FakeDesktopMediaPickerFactory);
122 };
123
124 class DesktopCaptureApiTest : public ExtensionApiTest {
125 public:
DesktopCaptureApiTest()126 DesktopCaptureApiTest() {
127 DesktopCaptureChooseDesktopMediaFunction::
128 SetPickerFactoryForTests(&picker_factory_);
129 }
~DesktopCaptureApiTest()130 virtual ~DesktopCaptureApiTest() {
131 DesktopCaptureChooseDesktopMediaFunction::
132 SetPickerFactoryForTests(NULL);
133 }
134
135 protected:
GetURLForPath(const std::string & host,const std::string & path)136 GURL GetURLForPath(const std::string& host, const std::string& path) {
137 std::string port = base::IntToString(embedded_test_server()->port());
138 GURL::Replacements replacements;
139 replacements.SetHostStr(host);
140 replacements.SetPortStr(port);
141 return embedded_test_server()->GetURL(path).ReplaceComponents(replacements);
142 }
143
144 FakeDesktopMediaPickerFactory picker_factory_;
145 };
146
147 } // namespace
148
149 // Flaky on Windows: http://crbug.com/301887
150 #if defined(OS_WIN)
151 #define MAYBE_ChooseDesktopMedia DISABLED_ChooseDesktopMedia
152 #else
153 #define MAYBE_ChooseDesktopMedia ChooseDesktopMedia
154 #endif
IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest,MAYBE_ChooseDesktopMedia)155 IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, MAYBE_ChooseDesktopMedia) {
156 // Each element in the following array corresponds to one test in
157 // chrome/test/data/extensions/api_test/desktop_capture/test.js .
158 TestFlags test_flags[] = {
159 // pickerUiCanceled()
160 { true, true,
161 content::DesktopMediaID() },
162 // chooseMedia()
163 { true, true,
164 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
165 // screensOnly()
166 { true, false,
167 content::DesktopMediaID() },
168 // WindowsOnly()
169 { false, true,
170 content::DesktopMediaID() },
171 // chooseMediaAndGetStream()
172 { true, true,
173 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
174 webrtc::kFullDesktopScreenId) },
175 // chooseMediaAndTryGetStreamWithInvalidId()
176 { true, true,
177 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN,
178 webrtc::kFullDesktopScreenId) },
179 // cancelDialog()
180 { true, true,
181 content::DesktopMediaID(), true },
182 };
183 picker_factory_.SetTestFlags(test_flags, arraysize(test_flags));
184 ASSERT_TRUE(RunExtensionTest("desktop_capture")) << message_;
185 }
186
187 // Test is flaky http://crbug.com/301887.
IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest,DISABLED_Delegation)188 IN_PROC_BROWSER_TEST_F(DesktopCaptureApiTest, DISABLED_Delegation) {
189 // Initialize test server.
190 base::FilePath test_data;
191 EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data));
192 embedded_test_server()->ServeFilesFromDirectory(test_data.AppendASCII(
193 "extensions/api_test/desktop_capture_delegate"));
194 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
195 host_resolver()->AddRule("*", embedded_test_server()->base_url().host());
196
197 // Load extension.
198 base::FilePath extension_path =
199 test_data_dir_.AppendASCII("desktop_capture_delegate");
200 const Extension* extension = LoadExtensionWithFlags(
201 extension_path, ExtensionBrowserTest::kFlagNone);
202 ASSERT_TRUE(extension);
203
204 ui_test_utils::NavigateToURL(
205 browser(), GetURLForPath("example.com", "/example.com.html"));
206
207 TestFlags test_flags[] = {
208 { true, true,
209 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
210 { true, true,
211 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0) },
212 { true, true,
213 content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0), true },
214 };
215 picker_factory_.SetTestFlags(test_flags, arraysize(test_flags));
216
217 bool result;
218
219 content::WebContents* web_contents =
220 browser()->tab_strip_model()->GetActiveWebContents();
221
222 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
223 web_contents, "getStream()", &result));
224 EXPECT_TRUE(result);
225
226 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
227 web_contents, "getStreamWithInvalidId()", &result));
228 EXPECT_TRUE(result);
229
230 // Verify that the picker is closed once the tab is closed.
231 content::WebContentsDestroyedWatcher destroyed_watcher(web_contents);
232 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
233 web_contents, "openPickerDialogAndReturn()", &result));
234 EXPECT_TRUE(result);
235 EXPECT_TRUE(test_flags[2].picker_created);
236 EXPECT_FALSE(test_flags[2].picker_deleted);
237
238 web_contents->Close();
239 destroyed_watcher.Wait();
240 EXPECT_TRUE(test_flags[2].picker_deleted);
241 }
242
243 } // namespace extensions
244