1 // Copyright (c) 2012 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/extensions/echo_private_api.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "chrome/browser/chromeos/settings/cros_settings.h"
12 #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
13 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
14 #include "chrome/browser/chromeos/ui/echo_dialog_view.h"
15 #include "chrome/browser/extensions/extension_apitest.h"
16 #include "chrome/browser/extensions/extension_function_test_utils.h"
17 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chromeos/constants/chromeos_switches.h"
21 #include "content/public/test/browser_test.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace utils = extension_function_test_utils;
25
26 namespace chromeos {
27
28 class ExtensionEchoPrivateApiTest : public extensions::ExtensionApiTest {
29 public:
30 enum DialogTestAction {
31 DIALOG_TEST_ACTION_NONE,
32 DIALOG_TEST_ACTION_ACCEPT,
33 DIALOG_TEST_ACTION_CANCEL,
34 };
35
ExtensionEchoPrivateApiTest()36 ExtensionEchoPrivateApiTest()
37 : expected_dialog_buttons_(ui::DIALOG_BUTTON_NONE),
38 dialog_action_(DIALOG_TEST_ACTION_NONE),
39 dialog_invocation_count_(0) {
40 }
41
~ExtensionEchoPrivateApiTest()42 ~ExtensionEchoPrivateApiTest() override {}
43
RunDefaultGetUserFunctionAndExpectResultEquals(int tab_id,bool expected_result)44 void RunDefaultGetUserFunctionAndExpectResultEquals(int tab_id,
45 bool expected_result) {
46 scoped_refptr<EchoPrivateGetUserConsentFunction> function(
47 EchoPrivateGetUserConsentFunction::CreateForTest(
48 base::BindRepeating(&ExtensionEchoPrivateApiTest::OnDialogShown,
49 base::Unretained(this))));
50 function->set_has_callback(true);
51
52 const std::string arguments = base::StringPrintf(
53 R"([{"serviceName": "name", "origin": "https://test.com", "tabId": %d}])",
54 tab_id);
55 std::unique_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult(
56 function.get(), arguments, browser()));
57
58 ASSERT_TRUE(result.get());
59 ASSERT_EQ(base::Value::Type::BOOLEAN, result->type());
60
61 bool result_as_boolean = false;
62 ASSERT_TRUE(result->GetAsBoolean(&result_as_boolean));
63
64 EXPECT_EQ(expected_result, result_as_boolean);
65 }
66
OnDialogShown(chromeos::EchoDialogView * dialog)67 void OnDialogShown(chromeos::EchoDialogView* dialog) {
68 dialog_invocation_count_++;
69 ASSERT_LE(dialog_invocation_count_, 1);
70
71 EXPECT_EQ(expected_dialog_buttons_, dialog->GetDialogButtons());
72
73 // Don't accept the dialog if the dialog buttons don't match expectation.
74 // Accepting a dialog which should not have accept option may crash the
75 // test. The test already failed, so it's ok to cancel the dialog.
76 DialogTestAction dialog_action = dialog_action_;
77 if (dialog_action == DIALOG_TEST_ACTION_ACCEPT &&
78 expected_dialog_buttons_ != dialog->GetDialogButtons()) {
79 dialog_action = DIALOG_TEST_ACTION_CANCEL;
80 }
81
82 // Perform test action on the dialog.
83 // The dialog should stay around until AcceptWindow or CancelWindow is
84 // called, so base::Unretained is safe.
85 if (dialog_action == DIALOG_TEST_ACTION_ACCEPT) {
86 base::ThreadTaskRunnerHandle::Get()->PostTask(
87 FROM_HERE,
88 base::BindOnce(base::IgnoreResult(&chromeos::EchoDialogView::Accept),
89 base::Unretained(dialog)));
90 } else if (dialog_action == DIALOG_TEST_ACTION_CANCEL) {
91 base::ThreadTaskRunnerHandle::Get()->PostTask(
92 FROM_HERE,
93 base::BindOnce(base::IgnoreResult(&chromeos::EchoDialogView::Cancel),
94 base::Unretained(dialog)));
95 }
96 }
97
dialog_invocation_count() const98 int dialog_invocation_count() const {
99 return dialog_invocation_count_;
100 }
101
102 // Open and activates tab in the test browser. Returns the ID of the opened
103 // tab.
OpenAndActivateTab()104 int OpenAndActivateTab() {
105 AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
106 browser()->tab_strip_model()->ActivateTabAt(
107 0, {TabStripModel::GestureType::kOther});
108 return extensions::ExtensionTabUtil::GetTabId(
109 browser()->tab_strip_model()->GetActiveWebContents());
110 }
111
CloseTabWithId(int tab_id)112 bool CloseTabWithId(int tab_id) {
113 TabStripModel* tab_strip = nullptr;
114 int tab_index = -1;
115 if (!extensions::ExtensionTabUtil::GetTabById(tab_id, profile(), false,
116 nullptr, &tab_strip, nullptr,
117 &tab_index)) {
118 ADD_FAILURE() << "Tab not found " << tab_id;
119 return false;
120 }
121
122 return tab_strip->CloseWebContentsAt(tab_index, 0);
123 }
124
125 protected:
126 int expected_dialog_buttons_;
127 DialogTestAction dialog_action_;
128 ScopedTestingCrosSettings scoped_testing_cros_settings_;
129
130 private:
131 int dialog_invocation_count_;
132 };
133
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,EchoTest)134 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest, EchoTest) {
135 EXPECT_TRUE(RunComponentExtensionTest("echo/component_extension"))
136 << message_;
137 }
138
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_InvalidOrigin)139 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
140 GetUserConsent_InvalidOrigin) {
141 const int tab_id = OpenAndActivateTab();
142
143 expected_dialog_buttons_ = ui::DIALOG_BUTTON_NONE;
144 dialog_action_ = DIALOG_TEST_ACTION_NONE;
145
146 scoped_refptr<EchoPrivateGetUserConsentFunction> function(
147 EchoPrivateGetUserConsentFunction::CreateForTest(
148 base::BindRepeating(&ExtensionEchoPrivateApiTest::OnDialogShown,
149 base::Unretained(this))));
150
151 std::string error = utils::RunFunctionAndReturnError(
152 function.get(),
153 base::StringPrintf(
154 R"([{"serviceName": "name", "origin": "invalid", "tabId": %d}])",
155 tab_id),
156 browser());
157
158 EXPECT_EQ("Invalid origin.", error);
159 EXPECT_EQ(0, dialog_invocation_count());
160 }
161
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_NoTabIdSet)162 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest, GetUserConsent_NoTabIdSet) {
163 expected_dialog_buttons_ = ui::DIALOG_BUTTON_NONE;
164 dialog_action_ = DIALOG_TEST_ACTION_NONE;
165
166 scoped_refptr<EchoPrivateGetUserConsentFunction> function(
167 EchoPrivateGetUserConsentFunction::CreateForTest(
168 base::BindRepeating(&ExtensionEchoPrivateApiTest::OnDialogShown,
169 base::Unretained(this))));
170
171 std::string error = utils::RunFunctionAndReturnError(
172 function.get(),
173 R"([{"serviceName": "name", "origin": "https://test.com"}])", browser());
174
175 EXPECT_EQ("Not called from an app window - the tabId is required.", error);
176 EXPECT_EQ(0, dialog_invocation_count());
177 }
178
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_InactiveTab)179 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
180 GetUserConsent_InactiveTab) {
181 const int tab_id = OpenAndActivateTab();
182 // Open and activate another tab.
183 OpenAndActivateTab();
184
185 expected_dialog_buttons_ = ui::DIALOG_BUTTON_NONE;
186 dialog_action_ = DIALOG_TEST_ACTION_NONE;
187
188 scoped_refptr<EchoPrivateGetUserConsentFunction> function(
189 EchoPrivateGetUserConsentFunction::CreateForTest(
190 base::BindRepeating(&ExtensionEchoPrivateApiTest::OnDialogShown,
191 base::Unretained(this))));
192
193 const std::string arguments = base::StringPrintf(
194 R"([{"serviceName": "name", "origin": "https://test.com", "tabId": %d}])",
195 tab_id);
196 std::string error =
197 utils::RunFunctionAndReturnError(function.get(), arguments, browser());
198
199 EXPECT_EQ("Consent requested from an inactive tab.", error);
200 EXPECT_EQ(0, dialog_invocation_count());
201 }
202
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_ClosedTab)203 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest, GetUserConsent_ClosedTab) {
204 const int tab_id = OpenAndActivateTab();
205 ASSERT_TRUE(CloseTabWithId(tab_id));
206
207 expected_dialog_buttons_ = ui::DIALOG_BUTTON_NONE;
208 dialog_action_ = DIALOG_TEST_ACTION_NONE;
209
210 scoped_refptr<EchoPrivateGetUserConsentFunction> function(
211 EchoPrivateGetUserConsentFunction::CreateForTest(
212 base::BindRepeating(&ExtensionEchoPrivateApiTest::OnDialogShown,
213 base::Unretained(this))));
214
215 const std::string arguments = base::StringPrintf(
216 R"([{"serviceName": "name", "origin": "https://test.com", "tabId": %d}])",
217 tab_id);
218 std::string error =
219 utils::RunFunctionAndReturnError(function.get(), arguments, browser());
220
221 EXPECT_EQ("Tab not found.", error);
222 EXPECT_EQ(0, dialog_invocation_count());
223 }
224
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_AllowRedeemPrefNotSet)225 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
226 GetUserConsent_AllowRedeemPrefNotSet) {
227 const int tab_id = OpenAndActivateTab();
228 expected_dialog_buttons_ = ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
229 dialog_action_ = DIALOG_TEST_ACTION_ACCEPT;
230
231 RunDefaultGetUserFunctionAndExpectResultEquals(tab_id, true);
232
233 EXPECT_EQ(1, dialog_invocation_count());
234 }
235
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_AllowRedeemPrefTrue)236 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
237 GetUserConsent_AllowRedeemPrefTrue) {
238 const int tab_id = OpenAndActivateTab();
239 scoped_testing_cros_settings_.device_settings()->Set(
240 kAllowRedeemChromeOsRegistrationOffers, base::Value(true));
241
242 expected_dialog_buttons_ = ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
243 dialog_action_ = DIALOG_TEST_ACTION_ACCEPT;
244
245 RunDefaultGetUserFunctionAndExpectResultEquals(tab_id, true);
246
247 EXPECT_EQ(1, dialog_invocation_count());
248 }
249
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_ConsentDenied)250 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
251 GetUserConsent_ConsentDenied) {
252 const int tab_id = OpenAndActivateTab();
253 scoped_testing_cros_settings_.device_settings()->Set(
254 kAllowRedeemChromeOsRegistrationOffers, base::Value(true));
255
256 expected_dialog_buttons_ = ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
257 dialog_action_ = DIALOG_TEST_ACTION_CANCEL;
258
259 RunDefaultGetUserFunctionAndExpectResultEquals(tab_id, false);
260
261 EXPECT_EQ(1, dialog_invocation_count());
262 }
263
IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,GetUserConsent_AllowRedeemPrefFalse)264 IN_PROC_BROWSER_TEST_F(ExtensionEchoPrivateApiTest,
265 GetUserConsent_AllowRedeemPrefFalse) {
266 const int tab_id = OpenAndActivateTab();
267 scoped_testing_cros_settings_.device_settings()->Set(
268 kAllowRedeemChromeOsRegistrationOffers, base::Value(false));
269
270 expected_dialog_buttons_ = ui::DIALOG_BUTTON_CANCEL;
271 dialog_action_ = DIALOG_TEST_ACTION_CANCEL;
272
273 RunDefaultGetUserFunctionAndExpectResultEquals(tab_id, false);
274
275 EXPECT_EQ(1, dialog_invocation_count());
276 }
277
278 } // namespace chromeos
279