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

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: Missing include 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 // An intercepter of the real RuntimeAPIDelegate that simulates a successful
21 // restart request every time.
22 class RestartOnWatchdogApiDelegate : public TestRuntimeAPIDelegate {
23 public:
24 // Takes ownership of the |real_api_delegate|.
25 RestartOnWatchdogApiDelegate() {}
26 ~RestartOnWatchdogApiDelegate() override {}
27
28 // TestRuntimeAPIDelegate:
29 bool RestartDevice(std::string* error_message) override {
30 if (!quit_closure_.is_null())
31 base::ResetAndReturn(&quit_closure_).Run();
32
33 *error_message = "Success.";
34 restart_done_ = true;
35
36 if (!on_device_restarting_.is_null())
37 on_device_restarting_.Run();
38
39 return true;
40 }
41
42 void SetOnDeviceShutdownCallback(const base::Closure& callback) override {
43 on_device_restarting_ = callback;
44 }
45
46 base::TimeTicks WaitForSuccessfulRestart() {
47 if (!restart_done_) {
48 base::RunLoop run_loop;
49 quit_closure_ = run_loop.QuitClosure();
50 run_loop.Run();
51 }
52 restart_done_ = false;
53 return base::TimeTicks::Now();
54 }
55
56 private:
57 base::Closure on_device_restarting_;
58
59 base::Closure quit_closure_;
60
61 bool restart_done_ = false;
62
63 DISALLOW_COPY_AND_ASSIGN(RestartOnWatchdogApiDelegate);
64 };
65
66 class WatchdogApiExtensionsBrowserClient : public TestExtensionsBrowserClient {
67 public:
68 WatchdogApiExtensionsBrowserClient(content::BrowserContext* context)
69 : TestExtensionsBrowserClient(context) {}
70 ~WatchdogApiExtensionsBrowserClient() override {}
71
72 // TestExtensionsBrowserClient:
73 PrefService* GetPrefServiceForContext(
74 content::BrowserContext* context) override {
75 return &testing_pref_service_;
76 }
77
78 std::unique_ptr<RuntimeAPIDelegate> CreateRuntimeAPIDelegate(
79 content::BrowserContext* context) const override {
80 const_cast<WatchdogApiExtensionsBrowserClient*>(this)->api_delegate_ =
81 new RestartOnWatchdogApiDelegate();
82 return base::WrapUnique(api_delegate_);
83 }
84
85 user_prefs::TestingPrefServiceSyncable* testing_pref_service() {
86 return &testing_pref_service_;
87 }
88
89 RestartOnWatchdogApiDelegate* api_delegate() const {
90 CHECK(api_delegate_);
91 return api_delegate_;
92 }
93
94 private:
95 RestartOnWatchdogApiDelegate* api_delegate_ = nullptr; // Not owned.
96
97 user_prefs::TestingPrefServiceSyncable testing_pref_service_;
98
99 DISALLOW_COPY_AND_ASSIGN(WatchdogApiExtensionsBrowserClient);
100 };
101
102 } // namespace
103
104 class RestartAfterDelayApiTest : public ApiUnitTest {
105 public:
106 RestartAfterDelayApiTest() {}
107 ~RestartAfterDelayApiTest() override {}
108
109 void SetUp() override {
110 ApiUnitTest::SetUp();
111
112 // Use our ExtensionsBrowserClient that returns our RuntimeAPIDelegate.
113 test_browser_client_.reset(
114 new WatchdogApiExtensionsBrowserClient(browser_context()));
115 test_browser_client_->set_extension_system_factory(
116 extensions_browser_client()->extension_system_factory());
117 ExtensionsBrowserClient::Set(test_browser_client_.get());
118
119 // The RuntimeAPI should only be accessed (i.e. constructed) only after the
120 // above ExtensionsBrowserClient has been setup.
121 RuntimeAPI* runtime_api =
122 RuntimeAPI::GetFactoryInstance()->Get(browser_context());
123 runtime_api->set_min_duration_between_restarts_for_testing(
124 base::TimeDelta::FromSeconds(2));
125 runtime_api->AllowNonKiostAppsInRestartOnWatchdogForTesting();
126
127 RuntimeAPI::RegisterPrefs(
128 test_browser_client_->testing_pref_service()->registry());
129 }
130
131 base::TimeTicks WaitForSuccessfulRestart() {
132 return test_browser_client_->api_delegate()->WaitForSuccessfulRestart();
133 }
134
135 bool IsWatchdogTimerRunning() {
136 return RuntimeAPI::GetFactoryInstance()
137 ->Get(browser_context())
138 ->watchdog_timer_.IsRunning();
139 }
140
141 base::TimeTicks desired_restart_time() {
142 return RuntimeAPI::GetFactoryInstance()
143 ->Get(browser_context())
144 ->watchdog_timer_.desired_run_time();
145 }
146
147 std::string RunFunctionGetError(UIThreadExtensionFunction* function,
148 const Extension* extension,
149 const std::string& args) {
150 scoped_refptr<ExtensionFunction> function_owner(function);
151 function->set_extension(extension);
152 function->set_has_callback(true);
153 api_test_utils::RunFunction(function, args, browser_context());
154 return function->GetError();
155 }
156
157 void RunFunctionAssertNoError(UIThreadExtensionFunction* function,
158 const std::string& args) {
159 std::string error = RunFunctionGetError(function, extension(), args);
160 ASSERT_TRUE(error.empty()) << error;
161 }
162
163 private:
164 std::unique_ptr<WatchdogApiExtensionsBrowserClient> test_browser_client_;
165
166 DISALLOW_COPY_AND_ASSIGN(RestartAfterDelayApiTest);
167 };
168
169 TEST_F(RestartAfterDelayApiTest, RestartAfterDelayTest) {
170 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[-1]");
171 ASSERT_FALSE(IsWatchdogTimerRunning());
172
173 std::string error = RunFunctionGetError(
174 new RuntimeRestartAfterDelayFunction(), extension(), "[-2]");
175 ASSERT_EQ(error, "Invalid argument: -2.");
176
177 // Request a restart after 3 seconds.
178 base::TimeTicks now = base::TimeTicks::Now();
179 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[3]");
180 ASSERT_TRUE(IsWatchdogTimerRunning());
181 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(3));
182
183 // Request another restart after 4 seconds. It should reschedule the previous
184 // request.
185 now = base::TimeTicks::Now();
186 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[4]");
187 ASSERT_TRUE(IsWatchdogTimerRunning());
188 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(4));
189
190 // Create another extension and make it attempt to use the api, and expect a
191 // failure.
192 std::unique_ptr<base::DictionaryValue> test_extension_value(
193 api_test_utils::ParseDictionary("{\n"
194 " \"name\": \"Test\",\n"
195 " \"version\": \"2.0\",\n"
196 " \"app\": {\n"
197 " \"background\": {\n"
198 " \"scripts\": [\"background.js\"]\n"
199 " }\n"
200 " }\n"
201 "}"));
202 scoped_refptr<Extension> test_extension(api_test_utils::CreateExtension(
203 Manifest::INTERNAL, test_extension_value.get(), "id2"));
204 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
205 test_extension.get(), "[5]");
206 ASSERT_EQ(error, "Not the first extension to call this API.");
207
208 // Cancel restart requests.
209 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[-1]");
210 ASSERT_FALSE(IsWatchdogTimerRunning());
211
212 // Schedule a restart and wait for it to happen.
213 now = base::TimeTicks::Now();
214 RunFunctionAssertNoError(new RuntimeRestartAfterDelayFunction(), "[1]");
215 ASSERT_TRUE(IsWatchdogTimerRunning());
216 ASSERT_GE(desired_restart_time() - now, base::TimeDelta::FromSeconds(1));
217 base::TimeTicks last_restart_time = WaitForSuccessfulRestart();
218 ASSERT_FALSE(IsWatchdogTimerRunning());
219 ASSERT_GE(base::TimeTicks::Now() - now, base::TimeDelta::FromSeconds(1));
220
221 // This is a restart request that will be throttled, because it happens too
222 // soon after a successful restart.
223 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
224 extension(), "[1]");
225 ASSERT_EQ(error, "Restart was requested too soon. It was throttled instead.");
226 ASSERT_TRUE(IsWatchdogTimerRunning());
227 // Restart will happen 2 seconds later, even though the request was just one
228 // second.
229 ASSERT_NEAR((desired_restart_time() - last_restart_time).InSecondsF(),
230 base::TimeDelta::FromSeconds(2).InSecondsF(), 0.01);
231
232 // Calling chrome.runtime.restart() will not clear the throttle, and any
233 // subsequent calls to chrome.runtime.restartAfterDelay will still be
234 // throttled.
235 WaitForSuccessfulRestart();
236 RunFunctionAssertNoError(new RuntimeRestartFunction(), "[]");
237 last_restart_time = WaitForSuccessfulRestart();
238 error = RunFunctionGetError(new RuntimeRestartAfterDelayFunction(),
239 extension(), "[1]");
240 ASSERT_EQ(error, "Restart was requested too soon. It was throttled instead.");
241 ASSERT_TRUE(IsWatchdogTimerRunning());
242 // Restart will happen 2 seconds later, even though the request was just one
243 // second.
244 ASSERT_NEAR((desired_restart_time() - last_restart_time).InSecondsF(),
245 base::TimeDelta::FromSeconds(2).InSecondsF(), 0.01);
246 }
247
248 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698