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.
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"
28 // An identifier for the running apps.
29 const char kDummyApp1
[] = "aaaaaaa";
30 const char kDummyApp2
[] = "bbbbbbb";
32 // A dummy test app activity which works without content / ShellAppWindow.
33 class TestAppActivity
: public AppActivity
{
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);
43 ~TestAppActivity() override
{
44 app_activity_registry_
->UnregisterAppActivity(this);
47 AppActivityRegistry
* app_activity_registry() {
48 return app_activity_registry_
;
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();
58 ActivityState
GetCurrentState() override
{ return current_state_
; }
59 bool IsVisible() override
{ return true; }
60 ActivityMediaState
GetMediaState() override
{
61 return Activity::ACTIVITY_MEDIA_STATE_NONE
;
63 aura::Window
* GetWindow() override
{
64 return view_
->GetWidget() ? view_
->GetWidget()->GetNativeWindow() : nullptr;
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(); }
76 // If known the registry which holds all activities for the associated app.
77 AppActivityRegistry
* app_activity_registry_
;
79 // The title of the activity.
80 base::string16 title_
;
85 // The current state for this activity.
86 ActivityState current_state_
;
88 DISALLOW_COPY_AND_ASSIGN(TestAppActivity
);
91 // An AppContentDelegateClass which we can query for call stats.
92 class TestExtensionsDelegate
: public ExtensionsDelegate
{
94 TestExtensionsDelegate() : unload_called_(0), restart_called_(0) {}
95 ~TestExtensionsDelegate() override
{}
97 int unload_called() const { return unload_called_
; }
98 int restart_called() const { return restart_called_
; }
100 // ExtensionsDelegate:
101 content::BrowserContext
* GetBrowserContext() const override
{
104 const extensions::ExtensionSet
& GetInstalledExtensions() override
{
105 return extension_set_
;
107 // Unload an application. Returns true when unloaded.
108 bool UnloadApp(const std::string
& app_id
) override
{
110 // Since we did not close anything we let the framework clean up.
113 // Restarts an application. Returns true when the restart was initiated.
114 bool LaunchApp(const std::string
& app_id
) override
{
118 scoped_ptr
<extensions::ExtensionInstallUI
> CreateExtensionInstallUI()
120 return scoped_ptr
<extensions::ExtensionInstallUI
>();
127 extensions::ExtensionSet extension_set_
;
129 DISALLOW_COPY_AND_ASSIGN(TestExtensionsDelegate
);
135 class AppActivityTest
: public AthenaTestBase
{
137 AppActivityTest() : test_extensions_delegate_(nullptr) {}
138 ~AppActivityTest() override
{}
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();
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
);
156 void DeleteActivity(Activity
* activity
) {
157 Activity::Delete(activity
);
158 RunAllPendingInMessageLoop();
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
)
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);
181 TestExtensionsDelegate
* test_extensions_delegate() {
182 return test_extensions_delegate_
;
186 TestExtensionsDelegate
* test_extensions_delegate_
;
188 DISALLOW_COPY_AND_ASSIGN(AppActivityTest
);
191 // Only creates one activity and destroys it.
192 TEST_F(AppActivityTest
, OneAppActivity
) {
193 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
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
);
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());
207 // Test running of two applications.
208 TEST_F(AppActivityTest
, TwoAppsWithOneActivityEach
) {
209 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
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
);
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());
226 // Create and destroy two activities for the same application.
227 TEST_F(AppActivityTest
, TwoAppActivities
) {
228 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
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
);
241 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
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
);
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());
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"
265 DisableResourceManager();
266 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
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());
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());
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());
287 // Check that our created application is gone, and instead a proxy got
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());
299 // Close the proxy object and make sure that nothing bad happens.
300 DeleteActivity(activity_proxy
);
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());
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
));
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();
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());
338 DeleteActivity(activity_proxy
);
339 DeleteActivity(app_activity1b
);
340 DeleteActivity(app_activity1a
);
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();
350 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
352 TestAppActivity
* app_activity1
= CreateAppActivity(kDummyApp1
);
353 TestAppActivity
* app_activity2
= CreateAppActivity(kDummyApp1
);
354 TestAppActivity
* app_activity3
= CreateAppActivity(kDummyApp1
);
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());
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());
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());
390 // Close the proxy object and make sure that nothing bad happens.
391 DeleteActivity(activity_proxy
);
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());
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"
404 DisableResourceManager();
405 EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
407 TestAppActivity
* app_activity
= CreateAppActivity(kDummyApp1
);
408 AppActivityRegistry
* app_activity_registry
=
409 app_activity
->app_activity_registry();
411 // Unload the activity.
412 app_activity
->SetCurrentState(Activity::ACTIVITY_UNLOADED
);
413 RunAllPendingInMessageLoop();
414 EXPECT_EQ(1, test_extensions_delegate()->unload_called());
416 // Try to activate the activity again. This will force the application to
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());
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());
431 } // namespace athena