| Index: athena/content/app_activity_unittest.cc
|
| diff --git a/athena/content/app_activity_unittest.cc b/athena/content/app_activity_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f94cc85f1626f6f104dd15cf0f3bce7d155fa99e
|
| --- /dev/null
|
| +++ b/athena/content/app_activity_unittest.cc
|
| @@ -0,0 +1,412 @@
|
| +/// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "athena/activity/public/activity_factory.h"
|
| +#include "athena/activity/public/activity_manager.h"
|
| +#include "athena/content/app_activity.h"
|
| +#include "athena/content/app_activity_registry.h"
|
| +#include "athena/content/public/app_content_control_delegate.h"
|
| +#include "athena/content/public/app_registry.h"
|
| +#include "athena/test/athena_test_base.h"
|
| +#include "extensions/shell/browser/shell_app_window.h"
|
| +#include "ui/aura/window.h"
|
| +#include "ui/views/view.h"
|
| +#include "ui/views/widget/widget.h"
|
| +
|
| +
|
| +namespace content {
|
| +class BrowserContext;
|
| +}
|
| +
|
| +namespace athena {
|
| +namespace test {
|
| +
|
| +namespace {
|
| +
|
| +// An identifier for the running apps.
|
| +const char kDummyApp1[] = "aaaaaaa";
|
| +const char kDummyApp2[] = "bbbbbbb";
|
| +
|
| +// A dummy test app activity which works without content / ShellAppWindow.
|
| +class TestAppActivity : public AppActivity {
|
| + public:
|
| + explicit TestAppActivity(const std::string& app_id) :
|
| + AppActivity(NULL),
|
| + app_id_(app_id),
|
| + view_(new views::View()),
|
| + current_state_(ACTIVITY_VISIBLE) {
|
| + app_activity_registry_ =
|
| + AppRegistry::Get()->GetAppActivityRegistry(app_id, NULL);
|
| + app_activity_registry_->RegisterAppActivity(this);
|
| + }
|
| + virtual ~TestAppActivity() {
|
| + app_activity_registry_->UnregisterAppActivity(this);
|
| + }
|
| +
|
| + AppActivityRegistry* app_activity_registry() {
|
| + return app_activity_registry_;
|
| + }
|
| +
|
| + // Activity:
|
| + virtual ActivityViewModel* GetActivityViewModel() OVERRIDE {
|
| + return this;
|
| + }
|
| + virtual void SetCurrentState(Activity::ActivityState state) OVERRIDE {
|
| + current_state_ = state;
|
| + }
|
| + virtual ActivityState GetCurrentState() OVERRIDE {
|
| + return current_state_;
|
| + }
|
| + virtual bool IsVisible() OVERRIDE {
|
| + return true;
|
| + }
|
| + virtual ActivityMediaState GetMediaState() OVERRIDE {
|
| + return Activity::ACTIVITY_MEDIA_STATE_NONE;
|
| + }
|
| + virtual aura::Window* GetWindow() OVERRIDE {
|
| + return view_->GetWidget()->GetNativeWindow();
|
| + }
|
| +
|
| + // ActivityViewModel:
|
| + virtual void Init() OVERRIDE {}
|
| + virtual SkColor GetRepresentativeColor() const OVERRIDE { return 0; }
|
| + virtual base::string16 GetTitle() const OVERRIDE { return title_; }
|
| + virtual bool UsesFrame() const OVERRIDE { return true; }
|
| + virtual views::View* GetContentsView() OVERRIDE { return view_; }
|
| + virtual void CreateOverviewModeImage() OVERRIDE {}
|
| +
|
| + private:
|
| + // If known the registry which holds all activities for the associated app.
|
| + AppActivityRegistry* app_activity_registry_;
|
| +
|
| + // The application ID.
|
| + const std::string& app_id_;
|
| +
|
| + // The title of the activity.
|
| + base::string16 title_;
|
| +
|
| + // Our view.
|
| + views::View* view_;
|
| +
|
| + // The current state for this activity.
|
| + ActivityState current_state_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestAppActivity);
|
| +};
|
| +
|
| +// An AppContentDelegateClass which we can query for call stats.
|
| +class TestAppContentControlDelegate : public AppContentControlDelegate {
|
| + public:
|
| + TestAppContentControlDelegate() : unload_called_(0),
|
| + restart_called_(0) {}
|
| + virtual ~TestAppContentControlDelegate() {}
|
| +
|
| + int unload_called() { return unload_called_; }
|
| + int restart_called() { return restart_called_; }
|
| + void SetExtensionID(const std::string& extension_id) {
|
| + extension_id_to_return_ = extension_id;
|
| + }
|
| +
|
| + // Unload an application. Returns true when unloaded.
|
| + virtual bool UnloadApplication(
|
| + const std::string& app_id,
|
| + content::BrowserContext* browser_context) OVERRIDE {
|
| + unload_called_++;
|
| + // Since we did not close anything we let the framework clean up.
|
| + return false;
|
| + }
|
| + // Restarts an application. Returns true when the restart was initiated.
|
| + virtual bool RestartApplication(
|
| + const std::string& app_id,
|
| + content::BrowserContext* browser_context) OVERRIDE {
|
| + restart_called_++;
|
| + return true;
|
| + }
|
| + // Returns the application ID (or an empty string) for a given web content.
|
| + virtual std::string GetApplicationID(
|
| + content::WebContents* web_contents) OVERRIDE {
|
| + return extension_id_to_return_;
|
| + }
|
| +
|
| + private:
|
| + int unload_called_;
|
| + int restart_called_;
|
| + std::string extension_id_to_return_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestAppContentControlDelegate);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +// Our testing base.
|
| +class AppActivityTest : public AthenaTestBase {
|
| + public:
|
| + AppActivityTest() : test_app_content_control_delegate_(NULL) {}
|
| + virtual ~AppActivityTest() {}
|
| +
|
| + // AthenaTestBase:
|
| + virtual void SetUp() OVERRIDE {
|
| + AthenaTestBase::SetUp();
|
| + // Create and install our TestAppContentDelegate with instrumentation.
|
| + test_app_content_control_delegate_ = new TestAppContentControlDelegate();
|
| + AppRegistry::Get()->SetDelegate(test_app_content_control_delegate_);
|
| + }
|
| +
|
| + // A function to create an Activity.
|
| + TestAppActivity* CreateAppActivity(const std::string& app_id) {
|
| + TestAppActivity* activity = new TestAppActivity(app_id);
|
| + ActivityManager::Get()->AddActivity(activity);
|
| + return activity;
|
| + }
|
| +
|
| + void CloseActivity(Activity* activity) {
|
| + delete activity;
|
| + RunAllPendingInMessageLoop();
|
| + }
|
| +
|
| + // Get the position of the activity in the navigation history.
|
| + int GetActivityPosition(Activity* activity) {
|
| + aura::Window* window = activity->GetActivityViewModel()->GetContentsView()
|
| + ->GetWidget()->GetNativeWindow();
|
| + aura::Window::Windows windows = activity->GetWindow()->parent()->children();
|
| + for (size_t i = 0; i < windows.size(); i++) {
|
| + if (windows[i] == window)
|
| + return i;
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + protected:
|
| + TestAppContentControlDelegate* test_app_content_control_delegate() {
|
| + return test_app_content_control_delegate_;
|
| + }
|
| +
|
| + private:
|
| + TestAppContentControlDelegate* test_app_content_control_delegate_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AppActivityTest);
|
| +};
|
| +
|
| +// Only creates one activity and destroys it.
|
| +TEST_F(AppActivityTest, OneAppActivity) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + {
|
| + TestAppActivity* app_activity = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, app_activity->app_activity_registry()->NumberOfActivities());
|
| + EXPECT_EQ(AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, NULL),
|
| + app_activity->app_activity_registry());
|
| + CloseActivity(app_activity);
|
| + }
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->restart_called());
|
| +}
|
| +
|
| +// Test running of two applications.
|
| +TEST_F(AppActivityTest, TwoAppsWithOneActivityEach) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + {
|
| + TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities());
|
| + TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp2);
|
| + EXPECT_EQ(2, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, app_activity2->app_activity_registry()->NumberOfActivities());
|
| + EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities());
|
| + CloseActivity(app_activity1);
|
| + CloseActivity(app_activity2);
|
| + }
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->restart_called());
|
| +}
|
| +
|
| +// Create and destroy two activities for the same application.
|
| +TEST_F(AppActivityTest, TwoAppActivities) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + {
|
| + TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1);
|
| + TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(2, app_activity1->app_activity_registry()->NumberOfActivities());
|
| + EXPECT_EQ(app_activity1->app_activity_registry(),
|
| + app_activity2->app_activity_registry());
|
| + CloseActivity(app_activity1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, app_activity2->app_activity_registry()->NumberOfActivities());
|
| + CloseActivity(app_activity2);
|
| + }
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + {
|
| + TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1);
|
| + TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(2, app_activity1->app_activity_registry()->NumberOfActivities());
|
| + EXPECT_EQ(app_activity1->app_activity_registry(),
|
| + app_activity2->app_activity_registry());
|
| + CloseActivity(app_activity2);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, app_activity1->app_activity_registry()->NumberOfActivities());
|
| + CloseActivity(app_activity1);
|
| + }
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->restart_called());
|
| +}
|
| +
|
| +// Test unload and the creation of the proxy, then "closing the activity".
|
| +TEST_F(AppActivityTest, TestUnloadFollowedByClose) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| +
|
| + TestAppActivity* app_activity = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + AppActivityRegistry* app_activity_registry =
|
| + app_activity->app_activity_registry();
|
| + EXPECT_EQ(1, app_activity_registry->NumberOfActivities());
|
| + EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity->GetCurrentState());
|
| +
|
| + // Calling Unload now should not do anything since at least one activity in
|
| + // the registry is still visible.
|
| + app_activity_registry->Unload();
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| +
|
| + // After setting our activity to unloaded however the application should get
|
| + // unloaded as requested.
|
| + app_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity_registry->Unload();
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->unload_called());
|
| +
|
| + // Check that our created application is gone, and instead a proxy got
|
| + // created.
|
| + ASSERT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + ASSERT_EQ(app_activity_registry,
|
| + AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, NULL));
|
| + EXPECT_EQ(0, app_activity_registry->NumberOfActivities());
|
| + Activity* activity_proxy =
|
| + app_activity_registry->unloaded_activity_proxy_for_test();
|
| + ASSERT_TRUE(activity_proxy);
|
| + EXPECT_NE(app_activity, activity_proxy);
|
| + EXPECT_EQ(Activity::ACTIVITY_UNLOADED, activity_proxy->GetCurrentState());
|
| +
|
| + // Close the proxy object and make sure that nothing bad happens.
|
| + CloseActivity(activity_proxy);
|
| +
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->unload_called());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->restart_called());
|
| +}
|
| +
|
| +// Test that when unloading an app while multiple apps / activities are present,
|
| +// the proxy gets created in the correct location.
|
| +TEST_F(AppActivityTest, TestUnloadProxyLocation) {
|
| + // Set up some activities for some applications.
|
| + TestAppActivity* app_activity1a = CreateAppActivity(kDummyApp1);
|
| + TestAppActivity* app_activity2a = CreateAppActivity(kDummyApp2);
|
| + TestAppActivity* app_activity2b = CreateAppActivity(kDummyApp2);
|
| + TestAppActivity* app_activity1b = CreateAppActivity(kDummyApp1);
|
| + EXPECT_EQ(3, GetActivityPosition(app_activity1b));
|
| + EXPECT_EQ(2, GetActivityPosition(app_activity2b));
|
| + EXPECT_EQ(1, GetActivityPosition(app_activity2a));
|
| + EXPECT_EQ(0, GetActivityPosition(app_activity1a));
|
| +
|
| + // Unload an app and make sure that the proxy is in the newest activity slot.
|
| + AppActivityRegistry* app_activity_registry =
|
| + app_activity2a->app_activity_registry();
|
| + app_activity2a->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity2b->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity2a->app_activity_registry()->Unload();
|
| + EXPECT_EQ(0, app_activity_registry->NumberOfActivities());
|
| + Activity* activity_proxy =
|
| + app_activity_registry->unloaded_activity_proxy_for_test();
|
| + RunAllPendingInMessageLoop();
|
| +
|
| + EXPECT_EQ(2, GetActivityPosition(app_activity1b));
|
| + EXPECT_EQ(1, GetActivityPosition(activity_proxy));
|
| + EXPECT_EQ(0, GetActivityPosition(app_activity1a));
|
| +
|
| + CloseActivity(activity_proxy);
|
| + CloseActivity(app_activity1b);
|
| + CloseActivity(app_activity1a);
|
| +}
|
| +
|
| +// Test that an unload with multiple activities of the same app will only unload
|
| +// when all activities were marked for unloading.
|
| +TEST_F(AppActivityTest, TestMultipleActivityUnloadLock) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| +
|
| + TestAppActivity* app_activity1 = CreateAppActivity(kDummyApp1);
|
| + TestAppActivity* app_activity2 = CreateAppActivity(kDummyApp1);
|
| + TestAppActivity* app_activity3 = CreateAppActivity(kDummyApp1);
|
| +
|
| + // Check that we have 3 activities of the same application.
|
| + EXPECT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + AppActivityRegistry* app_activity_registry =
|
| + app_activity1->app_activity_registry();
|
| + EXPECT_EQ(app_activity_registry, app_activity2->app_activity_registry());
|
| + EXPECT_EQ(app_activity_registry, app_activity3->app_activity_registry());
|
| + EXPECT_EQ(3, app_activity_registry->NumberOfActivities());
|
| + EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity1->GetCurrentState());
|
| + EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity2->GetCurrentState());
|
| + EXPECT_EQ(Activity::ACTIVITY_VISIBLE, app_activity3->GetCurrentState());
|
| +
|
| + // After setting all activities to UNLOADED the application should unload.
|
| + app_activity1->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity1->app_activity_registry()->Unload();
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| + app_activity2->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity2->app_activity_registry()->Unload();
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->unload_called());
|
| + app_activity3->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity3->app_activity_registry()->Unload();
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->unload_called());
|
| +
|
| + // Now there should only be the proxy activity left.
|
| + ASSERT_EQ(1, AppRegistry::Get()->NumberOfApplications());
|
| + ASSERT_EQ(app_activity_registry,
|
| + AppRegistry::Get()->GetAppActivityRegistry(kDummyApp1, NULL));
|
| + EXPECT_EQ(0, app_activity_registry->NumberOfActivities());
|
| + Activity* activity_proxy =
|
| + app_activity_registry->unloaded_activity_proxy_for_test();
|
| + ASSERT_TRUE(activity_proxy);
|
| + EXPECT_NE(app_activity1, activity_proxy);
|
| + EXPECT_NE(app_activity2, activity_proxy);
|
| + EXPECT_NE(app_activity3, activity_proxy);
|
| + EXPECT_EQ(Activity::ACTIVITY_UNLOADED, activity_proxy->GetCurrentState());
|
| +
|
| + // Close the proxy object and make sure that nothing bad happens.
|
| + CloseActivity(activity_proxy);
|
| +
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->unload_called());
|
| + EXPECT_EQ(0, test_app_content_control_delegate()->restart_called());
|
| +}
|
| +
|
| +// Test that activating the proxy will reload the application.
|
| +TEST_F(AppActivityTest, TestUnloadWithReload) {
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| +
|
| + TestAppActivity* app_activity = CreateAppActivity(kDummyApp1);
|
| + AppActivityRegistry* app_activity_registry =
|
| + app_activity->app_activity_registry();
|
| +
|
| + // Unload the activity.
|
| + app_activity->SetCurrentState(Activity::ACTIVITY_UNLOADED);
|
| + app_activity_registry->Unload();
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->unload_called());
|
| +
|
| + // Try to activate the activity again. This will force the application to
|
| + // reload.
|
| + Activity* activity_proxy =
|
| + app_activity_registry->unloaded_activity_proxy_for_test();
|
| + activity_proxy->SetCurrentState(Activity::ACTIVITY_VISIBLE);
|
| + EXPECT_EQ(1, test_app_content_control_delegate()->restart_called());
|
| +
|
| + // However - the restart in this test framework does not really restart and
|
| + // all objects should be gone now.
|
| + EXPECT_EQ(0, AppRegistry::Get()->NumberOfApplications());
|
| +}
|
| +
|
| +} // namespace test
|
| +} // namespace athena
|
|
|