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
22namespace extensions {
23
24namespace {
25
26struct 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
38class FakeDesktopMediaPicker : public DesktopMediaPicker {
39 public:
40  explicit FakeDesktopMediaPicker(TestFlags* expectation)
41      : expectation_(expectation),
42        weak_factory_(this) {
43    expectation_->picker_created = true;
44  }
45  virtual ~FakeDesktopMediaPicker() {
46    expectation_->picker_deleted = true;
47  }
48
49  // DesktopMediaPicker interface.
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:
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
83class FakeDesktopMediaPickerFactory :
84    public DesktopCaptureChooseDesktopMediaFunction::PickerFactory {
85 public:
86  FakeDesktopMediaPickerFactory() {}
87  virtual ~FakeDesktopMediaPickerFactory() {}
88
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.
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
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
124class DesktopCaptureApiTest : public ExtensionApiTest {
125 public:
126  DesktopCaptureApiTest() {
127    DesktopCaptureChooseDesktopMediaFunction::
128        SetPickerFactoryForTests(&picker_factory_);
129  }
130  virtual ~DesktopCaptureApiTest() {
131    DesktopCaptureChooseDesktopMediaFunction::
132        SetPickerFactoryForTests(NULL);
133  }
134
135 protected:
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
155IN_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.
188IN_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