• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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