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
18namespace content {
19class BrowserContext;
20}
21
22namespace athena {
23namespace test {
24
25namespace {
26
27// An identifier for the running apps.
28const char kDummyApp1[] = "aaaaaaa";
29const char kDummyApp2[] = "bbbbbbb";
30
31// A dummy test app activity which works without content / ShellAppWindow.
32class TestAppActivity : public AppActivity {
33 public:
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  }
42  virtual ~TestAppActivity() {
43    app_activity_registry_->UnregisterAppActivity(this);
44  }
45
46  AppActivityRegistry* app_activity_registry() {
47    return app_activity_registry_;
48  }
49
50  // Activity:
51  virtual ActivityViewModel* GetActivityViewModel() OVERRIDE {
52    return this;
53  }
54  virtual void SetCurrentState(Activity::ActivityState state) OVERRIDE {
55    current_state_ = state;
56    if (state == ACTIVITY_UNLOADED)
57      app_activity_registry_->Unload();
58  }
59  virtual ActivityState GetCurrentState() OVERRIDE {
60    return current_state_;
61  }
62  virtual bool IsVisible() OVERRIDE {
63    return true;
64  }
65  virtual ActivityMediaState GetMediaState() OVERRIDE {
66    return Activity::ACTIVITY_MEDIA_STATE_NONE;
67  }
68  virtual aura::Window* GetWindow() OVERRIDE {
69    return view_->GetWidget()->GetNativeWindow();
70  }
71
72  // ActivityViewModel:
73  virtual void Init() OVERRIDE {}
74  virtual SkColor GetRepresentativeColor() const OVERRIDE { return 0; }
75  virtual base::string16 GetTitle() const OVERRIDE { return title_; }
76  virtual bool UsesFrame() const OVERRIDE { return true; }
77  virtual views::View* GetContentsView() OVERRIDE { return view_; }
78  virtual views::Widget* CreateWidget() OVERRIDE { return NULL; }
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.
100class TestExtensionsDelegate : public ExtensionsDelegate {
101 public:
102  TestExtensionsDelegate() : unload_called_(0), restart_called_(0) {}
103  virtual ~TestExtensionsDelegate() {}
104
105  int unload_called() const { return unload_called_; }
106  int restart_called() const { return restart_called_; }
107
108  // ExtensionsDelegate:
109  virtual content::BrowserContext* GetBrowserContext() const OVERRIDE {
110    return NULL;
111  }
112  virtual const extensions::ExtensionSet& GetInstalledExtensions() OVERRIDE {
113    return extension_set_;
114  }
115  // Unload an application. Returns true when unloaded.
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.
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.
139class AppActivityTest : public AthenaTestBase {
140 public:
141  AppActivityTest() : test_extensions_delegate_(NULL) {}
142  virtual ~AppActivityTest() {}
143
144  // AthenaTestBase:
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.
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
160  void DeleteActivity(Activity* activity) {
161    Activity::Delete(activity);
162    RunAllPendingInMessageLoop();
163  }
164
165  // Get the position of the activity in the navigation history.
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.
180  void DisableResourceManager() {
181    ResourceManager::Get()->Pause(true);
182  }
183
184 protected:
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.
196TEST_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.
212TEST_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.
231TEST_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".
264TEST_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.
313TEST_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.
349TEST_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.
403TEST_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