Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: extensions/browser/api/runtime/restart_after_delay_api_unittest.cc

Issue 1970613003: Add a new app API to enable watchdog behavior restarts in kiosk apps (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add a new app API to enable watchdog behavior restarts in kiosk apps Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "base/callback_helpers.h"
6 #include "base/run_loop.h"
7 #include "components/pref_registry/pref_registry_syncable.h"
8 #include "components/pref_registry/testing_pref_service_syncable.h"
9 #include "extensions/browser/api/runtime/runtime_api.h"
10 #include "extensions/browser/api_test_utils.h"
11 #include "extensions/browser/api_unittest.h"
12 #include "extensions/browser/test_extensions_browser_client.h"
13 #include "extensions/browser/test_runtime_api_delegate.h"
14 #include "extensions/common/manifest.h"
15
16 namespace extensions {
17
18 namespace {
19
20 // A RuntimeAPIDelegate that simulates a successful restart request every time.
21 class DelayedRestartTestApiDelegate : public TestRuntimeAPIDelegate {
22 public:
23 // Takes ownership of the |real_api_delegate|.
Devlin 2016/06/14 16:27:21 comment out of date
afakhry 2016/06/14 18:00:04 Done.
24 DelayedRestartTestApiDelegate() {}
25 ~DelayedRestartTestApiDelegate() override {}
26
27 // TestRuntimeAPIDelegate:
28 bool RestartDevice(std::string* error_message) override {
29 if (!quit_closure_.is_null())
30 base::ResetAndReturn(&quit_closure_).Run();
31
32 *error_message = "Success.";
33 restart_done_ = true;
34
35 return true;
36 }
37
38 base::TimeTicks WaitForSuccessfulRestart() {
39 if (!restart_done_) {
40 base::RunLoop run_loop;
41 quit_closure_ = run_loop.QuitClosure();
42 run_loop.Run();
43 }
44 restart_done_ = false;
45 return base::TimeTicks::Now();
46 }
47
48 private:
49 base::Closure quit_closure_;
50
51 bool restart_done_ = false;
52
53 DISALLOW_COPY_AND_ASSIGN(DelayedRestartTestApiDelegate);
54 };
55
56 class DelayedRestartExtensionsBrowserClient
57 : public TestExtensionsBrowserClient {
58 public:
59 DelayedRestartExtensionsBrowserClient(content::BrowserContext* context)
60 : TestExtensionsBrowserClient(context) {}
61 ~DelayedRestartExtensionsBrowserClient() override {}
62
63 // TestExtensionsBrowserClient:
64 PrefService* GetPrefServiceForContext(
65 content::BrowserContext* context) override {
66 return &testing_pref_service_;
67 }
68
69 std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(
70 content::BrowserContext* context) const override {
71 const_cast<DelayedRestartExtensionsBrowserClient*>(this)->api_delegate_ =
72 new DelayedRestartTestApiDelegate();
73 return base::WrapUnique(api_delegate_);
74 }
75
76 user_prefs::TestingPrefServiceSyncable* testing_pref_service() {
77 return &testing_pref_service_;
78 }
79
80 DelayedRestartTestApiDelegate* api_delegate() const {
81 CHECK(api_delegate_);
82 return api_delegate_;
83 }
84
85 private:
86 DelayedRestartTestApiDelegate* api_delegate_ = nullptr; // Not owned.
87
88 user_prefs::TestingPrefServiceSyncable testing_pref_service_;
89
90 DISALLOW_COPY_AND_ASSIGN(DelayedRestartExtensionsBrowserClient);
91 };
92
93 } // namespace
94
95 class RestartAfterDelayApiTest : public ApiUnitTest {
96 public:
97 RestartAfterDelayApiTest() {}
98 ~RestartAfterDelayApiTest() override {}
99
100 void SetUp() override {
101 ApiUnitTest::SetUp();
102
103 // Use our ExtensionsBrowserClient that returns our RuntimeAPIDelegate.
104 test_browser_client_.reset(
105 new DelayedRestartExtensionsBrowserClient(browser_context()));
106 test_browser_client_->set_extension_system_factory(
107 extensions_browser_client()->extension_system_factory());
108 ExtensionsBrowserClient::Set(test_browser_client_.get());
109
110 // The RuntimeAPI should only be accessed (i.e. constructed) only after the
111 // above ExtensionsBrowserClient has been setup.
112 RuntimeAPI* runtime_api =
113 RuntimeAPI::GetFactoryInstance()->Get(browser_context());
114 runtime_api->set_min_duration_between_restarts_for_testing(
115 base::TimeDelta::FromSeconds(2));
116 runtime_api->AllowNonKioskAppsInRestartAfterDelayForTesting();
117
118 RuntimeAPI::RegisterPrefs(
119 test_browser_client_->testing_pref_service()->registry());
120 }
121
122 base::TimeTicks WaitForSuccessfulRestart() {
123 return test_browser_client_->api_delegate()->WaitForSuccessfulRestart();
124 }
125
126 bool IsDelayedRestartTimerRunning() {
127 return RuntimeAPI::GetFactoryInstance()
128 ->Get(browser_context())
129 ->restart_after_delay_timer_.IsRunning();
130 }
131
132 base::TimeTicks desired_restart_time() {
133 return RuntimeAPI::GetFactoryInstance()
134 ->Get(browser_context())
135 ->restart_after_delay_timer_.desired_run_time();
136 }
137
138 std::string RunFunctionGetError(UIThreadExtensionFunction* function,
Devlin 2016/06/14 16:27:21 It looks like all occurrences of RunFunctionGetErr
afakhry 2016/06/14 18:00:04 Not all calls though, we have one that passes Runt
139 const Extension* extension,
140 const std::string& args) {
Devlin 2016/06/14 16:27:21 can we also just pass in the expected error here,
afakhry 2016/06/14 18:00:04 Done.
141 scoped_refptr<ExtensionFunction> function_owner(function);
142 function->set_extension(extension);
143 function->set_has_callback(true);
144 api_test_utils::RunFunction(function, args, browser_context());
145 return function->GetError();
146 }
147
148 void RunFunctionAssertNoError(UIThreadExtensionFunction* function,
149 const std::string& args) {
150 std::string error = RunFunctionGetError(function, extension(), args);
151 ASSERT_TRUE(error.empty()) << error;
152 }
153
154 private:
155 std::unique_ptr<DelayedRestartExtensionsBrowserClient> test_browser_client_;
156
157 DISALLOW_COPY_AND_ASSIGN(RestartAfterDelayApiTest);
158 };
159
160 TEST_F(RestartAfterDelayApiTest, RestartAfterDelayTest) {
161 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[-1]");
162 ASSERT_FALSE(IsDelayedRestartTimerRunning());
163
164 std::string error = RunFunctionGetError(
165 new RuntimeRestartAfterDelayFunction(), extension(), "[-2]");
166 ASSERT_EQ(error, "Invalid argument: -2.");
167
168 // Request a restart after 3 seconds.
169 base::TimeTicks now = base::TimeTicks::Now();
170 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[3]");
171 ASSERT_TRUE(IsDelayedRestartTimerRunning());
172 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(3));
173
174 // Request another restart after 4 seconds. It should reschedule the previous
175 // request.
176 now = base::TimeTicks::Now();
177 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[4]");
178 ASSERT_TRUE(IsDelayedRestartTimerRunning());
179 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(4));
180
181 // Create another extension and make it attempt to use the api, and expect a
182 // failure.
183 std::unique_ptr<base::DictionaryValue> test_extension_value(
184 api_test_utils::ParseDictionary("{\n"
185 " \"name\": \"Test\",\n"
186 " \"version\": \"2.0\",\n"
187 " \"app\": {\n"
188 " \"background\": {\n"
189 " \"scripts\": [\"background.js\"]\n"
190 " }\n"
191 " }\n"
192 "}"));
193 scoped_refptr<Extension> test_extension(api_test_utils::CreateExtension(
194 Manifest::INTERNAL, test_extension_value.get(), "id2"));
195 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
196 test_extension.get(), "[5]");
197 ASSERT_EQ(error, "Not the first extension to call this API.");
198
199 // Cancel restart requests.
200 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[-1]");
201 ASSERT_FALSE(IsDelayedRestartTimerRunning());
202
203 // Schedule a restart and wait for it to happen.
204 now = base::TimeTicks::Now();
205 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[1]");
206 ASSERT_TRUE(IsDelayedRestartTimerRunning());
207 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(1));
208 base::TimeTicks last_restart_time = WaitForSuccessfulRestart();
209 ASSERT_FALSE(IsDelayedRestartTimerRunning());
210 ASSERT_GE(base::TimeTicks::Now() - now, base::TimeDelta::FromSeconds(1));
211
212 // This is a restart request that will be throttled, because it happens too
213 // soon after a successful restart.
214 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
215 extension(), "[1]");
216 ASSERT_EQ(error, "Restart was requested too soon. It was throttled instead.");
217 ASSERT_TRUE(IsDelayedRestartTimerRunning());
218 // Restart will happen 2 seconds later, even though the request was just one
219 // second.
220 ASSERT_NEAR((desired_restart_time() - last_restart_time).InSecondsF(),
221 base::TimeDelta::FromSeconds(2).InSecondsF(), 0.01);
222
223 // Calling chrome.runtime.restart() will not clear the throttle, and any
224 // subsequent calls to chrome.runtime.restartAfterDelay will still be
225 // throttled.
226 WaitForSuccessfulRestart();
227 RunFunctionAssertNoError(new RuntimeRestartFunction(), "[]");
228 last_restart_time = WaitForSuccessfulRestart();
229 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
230 extension(), "[1]");
231 ASSERT_EQ(error, "Restart was requested too soon. It was throttled instead.");
232 ASSERT_TRUE(IsDelayedRestartTimerRunning());
233 // Restart will happen 2 seconds later, even though the request was just one
234 // second.
235 ASSERT_NEAR((desired_restart_time() - last_restart_time).InSecondsF(),
236 base::TimeDelta::FromSeconds(2).InSecondsF(), 0.01);
237 }
238
239 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698