OLD | NEW |
| (Empty) |
1 /// Copyright 2014 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 "athena/activity/public/activity_factory.h" | |
6 #include "athena/activity/public/activity_manager.h" | |
7 #include "athena/content/app_activity.h" | |
8 #include "athena/content/app_activity_registry.h" | |
9 #include "athena/content/public/app_registry.h" | |
10 #include "athena/extensions/public/extensions_delegate.h" | |
11 #include "athena/resource_manager/public/resource_manager.h" | |
12 #include "athena/test/base/athena_test_base.h" | |
13 #include "extensions/browser/install/extension_install_ui.h" | |
14 #include "extensions/common/extension_set.h" | |
15 #include "ui/aura/window.h" | |
16 #include "ui/views/view.h" | |
17 #include "ui/views/widget/widget.h" | |
18 | |
19 namespace content { | |
20 class BrowserContext; | |
21 } | |
22 | |
23 namespace athena { | |
24 namespace test { | |
25 | |
26 namespace { | |
27 | |
28 // An identifier for the running apps. | |
29 const char kDummyApp1[] = "aaaaaaa"; | |
30 const char kDummyApp2[] = "bbbbbbb"; | |
31 | |
32 // A dummy test app activity which works without content / ShellAppWindow. | |
33 class TestAppActivity : public AppActivity { | |
34 public: | |
35 explicit TestAppActivity(const std::string& app_id) | |
36 : AppActivity(app_id), | |
37 view_(new views::View()), | |
38 current_state_(ACTIVITY_VISIBLE) { | |
39 app_activity_registry_ = | |
40 AppRegistry::Get()->GetAppActivityRegistry(app_id, nullptr); | |
41 app_activity_registry_->RegisterAppActivity(this); | |
42 } | |
43 ~TestAppActivity() override { | |
44 app_activity_registry_->UnregisterAppActivity(this); | |
45 } | |
46 | |
47 AppActivityRegistry* app_activity_registry() { | |
48 return app_activity_registry_; | |
49 } | |
50 | |
51 // Activity: | |
52 ActivityViewModel* GetActivityViewModel() override { return this; } | |
53 void SetCurrentState(Activity::ActivityState state) override { | |
54 current_state_ = state; | |
55 if (state == ACTIVITY_UNLOADED) | |
56 app_activity_registry_->Unload(); | |
57 } | |
58 ActivityState GetCurrentState() override { return current_state_; } | |
59 bool IsVisible() override { return true; } | |
60 ActivityMediaState GetMediaState() override { | |
61 return Activity::ACTIVITY_MEDIA_STATE_NONE; | |
62 } | |
63 aura::Window* GetWindow() override { | |
64 return view_->GetWidget() ? view_->GetWidget()->GetNativeWindow() : nullptr; | |
65 } | |
66 | |
67 // ActivityViewModel: | |
68 void Init() override {} | |
69 SkColor GetRepresentativeColor() const override { return 0; } | |
70 base::string16 GetTitle() const override { return title_; } | |
71 bool UsesFrame() const override { return true; } | |
72 views::View* GetContentsView() override { return view_; } | |
73 gfx::ImageSkia GetOverviewModeImage() override { return gfx::ImageSkia(); } | |
74 | |
75 private: | |
76 // If known the registry which holds all activities for the associated app. | |
77 AppActivityRegistry* app_activity_registry_; | |
78 | |
79 // The title of the activity. | |
80 base::string16 title_; | |
81 | |
82 // Our view. | |
83 views::View* view_; | |
84 | |
85 // The current state for this activity. | |
86 ActivityState current_state_; | |
87 | |
88 DISALLOW_COPY_AND_ASSIGN(TestAppActivity); | |
89 }; | |
90 | |
91 // An AppContentDelegateClass which we can query for call stats. | |
92 class TestExtensionsDelegate : public ExtensionsDelegate { | |
93 public: | |
94 TestExtensionsDelegate() : unload_called_(0), restart_called_(0) {} | |
95 ~TestExtensionsDelegate() override {} | |
96 | |
97 int unload_called() const { return unload_called_; } | |
98 int restart_called() const { return restart_called_; } | |
99 | |
100 // ExtensionsDelegate: | |
101 content::BrowserContext* GetBrowserContext() const override { | |
102 return nullptr; | |
103 } | |
104 const extensions::ExtensionSet& GetInstalledExtensions() override { | |
105 return extension_set_; | |
106 } | |
107 // Unload an application. Returns true when unloaded. | |
108 bool UnloadApp(const std::string& app_id) override { | |
109 unload_called_++; | |
110 // Since we did not close anything we let the framework clean up. | |
111 return false; | |
112 } | |
113 // Restarts an application. Returns true when the restart was initiated. | |
114 bool LaunchApp(const std::string& app_id) override { | |
115 restart_called_++; | |
116 return true; | |
117 } | |
118 scoped_ptr<extensions::ExtensionInstallUI> CreateExtensionInstallUI() | |
119 override { | |
120 return scoped_ptr<extensions::ExtensionInstallUI>(); | |
121 } | |
122 | |
123 private: | |
124 int unload_called_; | |
125 int restart_called_; | |
126 | |
127 extensions::ExtensionSet extension_set_; | |
128 | |
129 DISALLOW_COPY_AND_ASSIGN(TestExtensionsDelegate); | |
130 }; | |
131 | |
132 } // namespace | |
133 | |
134 // Our testing base. | |
135 class AppActivityTest : public AthenaTestBase { | |
136 public: | |
137 AppActivityTest() : test_extensions_delegate_(nullptr) {} | |
138 ~AppActivityTest() override {} | |
139 | |
140 // AthenaTestBase: | |
141 void SetUp() override { | |
142 AthenaTestBase::SetUp(); | |
143 // Create and install our TestAppContentDelegate with instrumentation. | |
144 ExtensionsDelegate::Shutdown(); | |
145 // The instance will be deleted by ExtensionsDelegate::Shutdown(). | |
146 test_extensions_delegate_ = new TestExtensionsDelegate(); | |
147 } | |
148 | |
149 // A function to create an Activity. | |
150 TestAppActivity* CreateAppActivity(const std::string& app_id) { | |
151 TestAppActivity* activity = new TestAppActivity(app_id); | |
152 ActivityManager::Get()->AddActivity(activity); | |
153 return activity; | |
154 } | |
155 | |
156 void DeleteActivity(Activity* activity) { | |
157 Activity::Delete(activity); | |
158 RunAllPendingInMessageLoop(); | |
159 } | |
160 | |
161 // Get the position of the activity in the navigation history. | |
162 int GetActivityPosition(Activity* activity) { | |
163 aura::Window* window = activity->GetActivityViewModel()->GetContentsView() | |
164 ->GetWidget()->GetNativeWindow(); | |
165 aura::Window::Windows windows = activity->GetWindow()->parent()->children(); | |
166 for (size_t i = 0; i < windows.size(); i++) { | |
167 if (windows[i] == window) | |
168 return i; | |
169 } | |
170 return -1; | |
171 } | |
172 | |
173 // To avoid interference of the ResourceManager in these AppActivity | |
174 // framework tests, we disable the ResourceManager for some tests. | |
175 // Every use/interference of this function gets explained. | |
176 void DisableResourceManager() { | |
177 ResourceManager::Get()->Pause(true); | |
178 } | |
179 | |
180 protected: | |
181 TestExtensionsDelegate* test_extensions_delegate() { | |
182 return test_extensions_delegate_; | |
183 } | |
184 | |
185 private: | |
186 TestExtensionsDelegate* test_extensions_delegate_; | |
187 | |
188 DISALLOW_COPY_AND_ASSIGN(AppActivityTest); | |
189 }; | |
190 | |
191 // Only creates one activity and destroys it. | |
192 TEST_F(AppActivityTest, OneAppActivity) { | |
193 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
194 { | |
195 TestAppActivity* app_activity = CreateAppActivity(kDummyApp1); | |
196 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
197 EXPECT_EQ(1, app_activity->app_activity_registry()->NumberOfActivities()); | |
198 EXPECT_EQ(AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, nullptr), | |
199 app_activity->app_activity_registry()); | |
200 DeleteActivity(app_activity); | |
201 } | |
202 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
203 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
204 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
205 } | |
206 | |
207 // Test running of two applications. | |
208 TEST_F(AppActivityTest, TwoAppsWithOneActivityEach) { | |
209 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
210 { | |
211 TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1); | |
212 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
213 EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities()); | |
214 TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp2); | |
215 EXPECT_EQ(2, AppRegistry::Get()->NumberOfApplications()); | |
216 EXPECT_EQ(1, app_activity2->app_activity_registry()->NumberOfActivities()); | |
217 EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities()); | |
218 DeleteActivity(app_activity1); | |
219 DeleteActivity(app_activity2); | |
220 } | |
221 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
222 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
223 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
224 } | |
225 | |
226 // Create and destroy two activities for the same application. | |
227 TEST_F(AppActivityTest, TwoAppActivities) { | |
228 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
229 { | |
230 TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1); | |
231 TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1); | |
232 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
233 EXPECT_EQ(2, app_activity1->app_activity_registry()->NumberOfActivities()); | |
234 EXPECT_EQ(app_activity1->app_activity_registry(), | |
235 app_activity2->app_activity_registry()); | |
236 DeleteActivity(app_activity1); | |
237 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
238 EXPECT_EQ(1, app_activity2->app_activity_registry()->NumberOfActivities()); | |
239 DeleteActivity(app_activity2); | |
240 } | |
241 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
242 { | |
243 TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1); | |
244 TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1); | |
245 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
246 EXPECT_EQ(2, app_activity1->app_activity_registry()->NumberOfActivities()); | |
247 EXPECT_EQ(app_activity1->app_activity_registry(), | |
248 app_activity2->app_activity_registry()); | |
249 DeleteActivity(app_activity2); | |
250 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
251 EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities()); | |
252 DeleteActivity(app_activity1); | |
253 } | |
254 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
255 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
256 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
257 } | |
258 | |
259 // Test unload and the creation of the proxy, then "closing the activity". | |
260 TEST_F(AppActivityTest, TestUnloadFollowedByClose) { | |
261 // We do not want the ResourceManager to interfere with this test. In this | |
262 // case it would (dependent on its current internal implementation) | |
263 // automatically re-load the unloaded activity if it is in an "active" | |
264 // position. | |
265 DisableResourceManager(); | |
266 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
267 | |
268 TestAppActivity* app_activity = CreateAppActivity(kDummyApp1); | |
269 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
270 AppActivityRegistry* app_activity_registry = | |
271 app_activity->app_activity_registry(); | |
272 EXPECT_EQ(1, app_activity_registry->NumberOfActivities()); | |
273 EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity->GetCurrentState()); | |
274 | |
275 // Calling Unload now should not do anything since at least one activity in | |
276 // the registry is still visible. | |
277 app_activity_registry->Unload(); | |
278 RunAllPendingInMessageLoop(); | |
279 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
280 | |
281 // After setting our activity to unloaded however the application should get | |
282 // unloaded as requested. | |
283 app_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
284 RunAllPendingInMessageLoop(); | |
285 EXPECT_EQ(1, test_extensions_delegate()->unload_called()); | |
286 | |
287 // Check that our created application is gone, and instead a proxy got | |
288 // created. | |
289 ASSERT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
290 ASSERT_EQ(app_activity_registry, | |
291 AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, nullptr)); | |
292 EXPECT_EQ(0, app_activity_registry->NumberOfActivities()); | |
293 Activity* activity_proxy = app_activity_registry->unloaded_activity_proxy(); | |
294 ASSERT_TRUE(activity_proxy); | |
295 EXPECT_NE(app_activity, activity_proxy); | |
296 EXPECT_EQ(Activity::ACTIVITY_UNLOADED, activity_proxy->GetCurrentState()); | |
297 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
298 | |
299 // Close the proxy object and make sure that nothing bad happens. | |
300 DeleteActivity(activity_proxy); | |
301 | |
302 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
303 EXPECT_EQ(1, test_extensions_delegate()->unload_called()); | |
304 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
305 } | |
306 | |
307 // Test that when unloading an app while multiple apps / activities are present, | |
308 // the proxy gets created in the correct location. | |
309 TEST_F(AppActivityTest, TestUnloadProxyLocation) { | |
310 // Disable the resource manager since some build bots run this test for an | |
311 // extended amount of time which allows the MemoryPressureNotifier to fire. | |
312 DisableResourceManager(); | |
313 // Set up some activities for some applications. | |
314 TestAppActivity* app_activity1a = CreateAppActivity(kDummyApp1); | |
315 TestAppActivity* app_activity2a = CreateAppActivity(kDummyApp2); | |
316 TestAppActivity* app_activity2b = CreateAppActivity(kDummyApp2); | |
317 TestAppActivity* app_activity1b = CreateAppActivity(kDummyApp1); | |
318 EXPECT_EQ(3, GetActivityPosition(app_activity1b)); | |
319 EXPECT_EQ(2, GetActivityPosition(app_activity2b)); | |
320 EXPECT_EQ(1, GetActivityPosition(app_activity2a)); | |
321 EXPECT_EQ(0, GetActivityPosition(app_activity1a)); | |
322 | |
323 // Unload an app and make sure that the proxy is in the newest activity slot. | |
324 AppActivityRegistry* app_activity_registry = | |
325 app_activity2a->app_activity_registry(); | |
326 app_activity2a->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
327 app_activity2b->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
328 RunAllPendingInMessageLoop(); | |
329 EXPECT_EQ(0, app_activity_registry->NumberOfActivities()); | |
330 Activity* activity_proxy = app_activity_registry->unloaded_activity_proxy(); | |
331 RunAllPendingInMessageLoop(); | |
332 | |
333 EXPECT_EQ(2, GetActivityPosition(app_activity1b)); | |
334 EXPECT_EQ(1, GetActivityPosition(activity_proxy)); | |
335 EXPECT_EQ(0, GetActivityPosition(app_activity1a)); | |
336 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
337 | |
338 DeleteActivity(activity_proxy); | |
339 DeleteActivity(app_activity1b); | |
340 DeleteActivity(app_activity1a); | |
341 } | |
342 | |
343 // Test that an unload with multiple activities of the same app will only unload | |
344 // when all activities were marked for unloading. | |
345 TEST_F(AppActivityTest, TestMultipleActivityUnloadLock) { | |
346 // Disable the resource manager since some build bots run this test for an | |
347 // extended amount of time which allows the MemoryPressureNotifier to fire. | |
348 DisableResourceManager(); | |
349 | |
350 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
351 | |
352 TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1); | |
353 TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1); | |
354 TestAppActivity* app_activity3 = CreateAppActivity(kDummyApp1); | |
355 | |
356 // Check that we have 3 activities of the same application. | |
357 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
358 AppActivityRegistry* app_activity_registry = | |
359 app_activity1->app_activity_registry(); | |
360 EXPECT_EQ(app_activity_registry, app_activity2->app_activity_registry()); | |
361 EXPECT_EQ(app_activity_registry, app_activity3->app_activity_registry()); | |
362 EXPECT_EQ(3, app_activity_registry->NumberOfActivities()); | |
363 EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity1->GetCurrentState()); | |
364 EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity2->GetCurrentState()); | |
365 EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity3->GetCurrentState()); | |
366 | |
367 // After setting all activities to UNLOADED the application should unload. | |
368 app_activity1->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
369 RunAllPendingInMessageLoop(); | |
370 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
371 app_activity2->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
372 RunAllPendingInMessageLoop(); | |
373 EXPECT_EQ(0, test_extensions_delegate()->unload_called()); | |
374 app_activity3->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
375 RunAllPendingInMessageLoop(); | |
376 EXPECT_EQ(1, test_extensions_delegate()->unload_called()); | |
377 | |
378 // Now there should only be the proxy activity left. | |
379 ASSERT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
380 ASSERT_EQ(app_activity_registry, | |
381 AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, nullptr)); | |
382 EXPECT_EQ(0, app_activity_registry->NumberOfActivities()); | |
383 Activity* activity_proxy = app_activity_registry->unloaded_activity_proxy(); | |
384 ASSERT_TRUE(activity_proxy); | |
385 EXPECT_NE(app_activity1, activity_proxy); | |
386 EXPECT_NE(app_activity2, activity_proxy); | |
387 EXPECT_NE(app_activity3, activity_proxy); | |
388 EXPECT_EQ(Activity::ACTIVITY_UNLOADED, activity_proxy->GetCurrentState()); | |
389 | |
390 // Close the proxy object and make sure that nothing bad happens. | |
391 DeleteActivity(activity_proxy); | |
392 | |
393 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
394 EXPECT_EQ(1, test_extensions_delegate()->unload_called()); | |
395 EXPECT_EQ(0, test_extensions_delegate()->restart_called()); | |
396 } | |
397 | |
398 // Test that activating the proxy will reload the application. | |
399 TEST_F(AppActivityTest, TestUnloadWithReload) { | |
400 // We do not want the ResourceManager to interfere with this test. In this | |
401 // case it would (dependent on its current internal implementation) | |
402 // automatically re-load the unloaded activity if it is in an "active" | |
403 // position. | |
404 DisableResourceManager(); | |
405 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
406 | |
407 TestAppActivity* app_activity = CreateAppActivity(kDummyApp1); | |
408 AppActivityRegistry* app_activity_registry = | |
409 app_activity->app_activity_registry(); | |
410 | |
411 // Unload the activity. | |
412 app_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED); | |
413 RunAllPendingInMessageLoop(); | |
414 EXPECT_EQ(1, test_extensions_delegate()->unload_called()); | |
415 | |
416 // Try to activate the activity again. This will force the application to | |
417 // reload. | |
418 Activity* activity_proxy = app_activity_registry->unloaded_activity_proxy(); | |
419 activity_proxy->SetCurrentState(Activity::ACTIVITY_VISIBLE); | |
420 EXPECT_EQ(1, test_extensions_delegate()->restart_called()); | |
421 | |
422 // However - the restart in this test framework does not really restart and | |
423 // all objects should be still there.. | |
424 EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications()); | |
425 EXPECT_TRUE(app_activity_registry->unloaded_activity_proxy()); | |
426 Activity::Delete(app_activity_registry->unloaded_activity_proxy()); | |
427 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications()); | |
428 } | |
429 | |
430 } // namespace test | |
431 } // namespace athena | |
OLD | NEW |