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