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