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