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