blob: 8e4394ed3e84e2a55c435d2f6935d2bebd7ca0a5 [file] [log] [blame]
// Copyright (c) 2010 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 "base/basictypes.h"
#include "base/command_line.h"
#include "base/scoped_ptr.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/background_contents_service.h"
#include "chrome/browser/pref_service.h"
#include "chrome/browser/tab_contents/background_contents.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/testing_browser_process.h"
#include "chrome/test/testing_profile.h"
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
class BackgroundContentsServiceTest : public testing::Test {
public:
BackgroundContentsServiceTest() {}
~BackgroundContentsServiceTest() {}
void SetUp() {
command_line_.reset(new CommandLine(CommandLine::ARGUMENTS_ONLY));
command_line_->AppendSwitch(switches::kRestoreBackgroundContents);
}
DictionaryValue* GetPrefs(Profile* profile) {
return profile->GetPrefs()->GetMutableDictionary(
prefs::kRegisteredBackgroundContents);
}
// Returns the stored pref URL for the passed app id.
std::string GetPrefURLForApp(Profile* profile, const string16& appid) {
DictionaryValue* pref = GetPrefs(profile);
EXPECT_TRUE(pref->HasKey(UTF16ToWide(appid)));
DictionaryValue* value;
pref->GetDictionaryWithoutPathExpansion(UTF16ToWide(appid), &value);
std::string url;
value->GetString(L"url", &url);
return url;
}
scoped_ptr<CommandLine> command_line_;
};
class MockBackgroundContents : public BackgroundContents {
public:
explicit MockBackgroundContents(Profile* profile)
: appid_(ASCIIToUTF16("app_id")),
profile_(profile) {
}
MockBackgroundContents(Profile* profile, const std::string& id)
: appid_(ASCIIToUTF16(id)),
profile_(profile) {
}
void SendOpenedNotification() {
string16 frame_name = ASCIIToUTF16("background");
BackgroundContentsOpenedDetails details = {
this, frame_name, appid_ };
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_OPENED,
Source<Profile>(profile_),
Details<BackgroundContentsOpenedDetails>(&details));
}
virtual const void Navigate(GURL url) {
url_ = url;
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
Source<Profile>(profile_),
Details<BackgroundContents>(this));
}
virtual const GURL& GetURL() const { return url_; }
void MockClose(Profile* profile) {
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_CLOSED,
Source<Profile>(profile),
Details<BackgroundContents>(this));
delete this;
}
~MockBackgroundContents() {
NotificationService::current()->Notify(
NotificationType::BACKGROUND_CONTENTS_DELETED,
Source<Profile>(profile_),
Details<BackgroundContents>(this));
}
const string16& appid() { return appid_; }
private:
GURL url_;
// The ID of our parent application
string16 appid_;
// Parent profile
Profile* profile_;
};
TEST_F(BackgroundContentsServiceTest, Create) {
// Check for creation and leaks.
TestingProfile profile;
BackgroundContentsService service(&profile, command_line_.get());
}
TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) {
TestingProfile profile;
BackgroundContentsService service(&profile, command_line_.get());
// TODO(atwilson): Enable the refcount part of the test once we fix the
// APP_TERMINATING notification to be sent at the proper time.
// (http://crbug.com/45275).
//
// TestingBrowserProcess* process =
// static_cast<TestingBrowserProcess*>(g_browser_process);
// unsigned int starting_ref_count = process->module_ref_count();
MockBackgroundContents* contents = new MockBackgroundContents(&profile);
EXPECT_FALSE(service.IsTracked(contents));
contents->SendOpenedNotification();
// EXPECT_EQ(starting_ref_count+1, process->module_ref_count());
EXPECT_TRUE(service.IsTracked(contents));
delete contents;
// EXPECT_EQ(starting_ref_count, process->module_ref_count());
EXPECT_FALSE(service.IsTracked(contents));
}
TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) {
TestingProfile profile;
GetPrefs(&profile)->Clear();
BackgroundContentsService service(&profile, command_line_.get());
GURL orig_url;
GURL url("http://a/");
GURL url2("http://a/");
{
scoped_ptr<MockBackgroundContents> contents(
new MockBackgroundContents(&profile));
EXPECT_EQ(0U, GetPrefs(&profile)->size());
contents->SendOpenedNotification();
contents->Navigate(url);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
// Navigate the contents to a new url, should not change url.
contents->Navigate(url2);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
}
// Contents are deleted, url should persist.
EXPECT_EQ(1U, GetPrefs(&profile)->size());
}
TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) {
TestingProfile profile;
GetPrefs(&profile)->Clear();
BackgroundContentsService service(&profile, command_line_.get());
GURL url("http://a/");
MockBackgroundContents* contents = new MockBackgroundContents(&profile);
EXPECT_EQ(0U, GetPrefs(&profile)->size());
contents->SendOpenedNotification();
contents->Navigate(url);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
// Fake a window closed by script.
contents->MockClose(&profile);
EXPECT_EQ(0U, GetPrefs(&profile)->size());
}
// Test what happens if a BackgroundContents shuts down (say, due to a renderer
// crash) then is restarted. Should not persist URL twice.
TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) {
TestingProfile profile;
GetPrefs(&profile)->Clear();
BackgroundContentsService service(&profile, command_line_.get());
GURL url("http://a/");
{
scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
&profile, "appid"));
contents->SendOpenedNotification();
contents->Navigate(url);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid()));
}
// Contents deleted, url should be persisted.
EXPECT_EQ(1U, GetPrefs(&profile)->size());
{
// Reopen the BackgroundContents to the same URL, we should not register the
// URL again.
scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents(
&profile, "appid"));
contents->SendOpenedNotification();
contents->Navigate(url);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
}
}
// Ensures that BackgroundContentsService properly tracks the association
// between a BackgroundContents and its parent extension, including
// unregistering the BC when the extension is uninstalled.
TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) {
TestingProfile profile;
BackgroundContentsService service(&profile, command_line_.get());
GetPrefs(&profile)->Clear();
EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid")));
MockBackgroundContents* contents = new MockBackgroundContents(&profile,
"appid");
scoped_ptr<MockBackgroundContents> contents2(
new MockBackgroundContents(&profile, "appid2"));
contents->SendOpenedNotification();
EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid()));
contents2->SendOpenedNotification();
EXPECT_EQ(contents2.get(), service.GetAppBackgroundContents(
contents2->appid()));
EXPECT_EQ(0U, GetPrefs(&profile)->size());
// Navigate the contents, then make sure the one associated with the extension
// is unregistered.
GURL url("http://a/");
GURL url2("http://b/");
contents->Navigate(url);
EXPECT_EQ(1U, GetPrefs(&profile)->size());
contents2->Navigate(url2);
EXPECT_EQ(2U, GetPrefs(&profile)->size());
service.ShutdownAssociatedBackgroundContents(ASCIIToUTF16("appid"));
EXPECT_FALSE(service.IsTracked(contents));
EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid")));
EXPECT_EQ(1U, GetPrefs(&profile)->size());
EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid()));
}