1 // Copyright (c) 2011 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 <string> 6 7 #include "base/basictypes.h" 8 #include "base/command_line.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/utf_string_conversions.h" 11 #include "chrome/browser/background_contents_service.h" 12 #include "chrome/browser/prefs/pref_service.h" 13 #include "chrome/browser/prefs/scoped_user_pref_update.h" 14 #include "chrome/browser/tab_contents/background_contents.h" 15 #include "chrome/browser/ui/browser_list.h" 16 #include "chrome/common/pref_names.h" 17 #include "chrome/test/testing_browser_process.h" 18 #include "chrome/test/testing_browser_process_test.h" 19 #include "chrome/test/testing_profile.h" 20 #include "googleurl/src/gurl.h" 21 #include "testing/gtest/include/gtest/gtest.h" 22 #include "testing/platform_test.h" 23 24 class BackgroundContentsServiceTest : public TestingBrowserProcessTest { 25 public: 26 BackgroundContentsServiceTest() {} 27 ~BackgroundContentsServiceTest() {} 28 void SetUp() { 29 command_line_.reset(new CommandLine(CommandLine::NO_PROGRAM)); 30 } 31 32 const DictionaryValue* GetPrefs(Profile* profile) { 33 return profile->GetPrefs()->GetDictionary( 34 prefs::kRegisteredBackgroundContents); 35 } 36 37 void ClearPrefs(Profile* profile) { 38 profile->GetPrefs()->ClearPref(prefs::kRegisteredBackgroundContents); 39 } 40 41 // Returns the stored pref URL for the passed app id. 42 std::string GetPrefURLForApp(Profile* profile, const string16& appid) { 43 const DictionaryValue* pref = GetPrefs(profile); 44 EXPECT_TRUE(pref->HasKey(UTF16ToUTF8(appid))); 45 DictionaryValue* value; 46 pref->GetDictionaryWithoutPathExpansion(UTF16ToUTF8(appid), &value); 47 std::string url; 48 value->GetString("url", &url); 49 return url; 50 } 51 52 scoped_ptr<CommandLine> command_line_; 53 }; 54 55 class MockBackgroundContents : public BackgroundContents { 56 public: 57 explicit MockBackgroundContents(Profile* profile) 58 : appid_(ASCIIToUTF16("app_id")), 59 profile_(profile) { 60 } 61 MockBackgroundContents(Profile* profile, const std::string& id) 62 : appid_(ASCIIToUTF16(id)), 63 profile_(profile) { 64 } 65 66 void SendOpenedNotification(BackgroundContentsService* service) { 67 string16 frame_name = ASCIIToUTF16("background"); 68 BackgroundContentsOpenedDetails details = { 69 this, frame_name, appid_ }; 70 service->BackgroundContentsOpened(&details); 71 } 72 73 virtual void Navigate(GURL url) { 74 url_ = url; 75 NotificationService::current()->Notify( 76 NotificationType::BACKGROUND_CONTENTS_NAVIGATED, 77 Source<Profile>(profile_), 78 Details<BackgroundContents>(this)); 79 } 80 virtual const GURL& GetURL() const { return url_; } 81 82 void MockClose(Profile* profile) { 83 NotificationService::current()->Notify( 84 NotificationType::BACKGROUND_CONTENTS_CLOSED, 85 Source<Profile>(profile), 86 Details<BackgroundContents>(this)); 87 delete this; 88 } 89 90 ~MockBackgroundContents() { 91 NotificationService::current()->Notify( 92 NotificationType::BACKGROUND_CONTENTS_DELETED, 93 Source<Profile>(profile_), 94 Details<BackgroundContents>(this)); 95 } 96 97 const string16& appid() { return appid_; } 98 99 private: 100 GURL url_; 101 102 // The ID of our parent application 103 string16 appid_; 104 105 // Parent profile 106 Profile* profile_; 107 }; 108 109 TEST_F(BackgroundContentsServiceTest, Create) { 110 // Check for creation and leaks. 111 TestingProfile profile; 112 BackgroundContentsService service(&profile, command_line_.get()); 113 } 114 115 TEST_F(BackgroundContentsServiceTest, BackgroundContentsCreateDestroy) { 116 TestingProfile profile; 117 BackgroundContentsService service(&profile, command_line_.get()); 118 MockBackgroundContents* contents = new MockBackgroundContents(&profile); 119 EXPECT_FALSE(service.IsTracked(contents)); 120 contents->SendOpenedNotification(&service); 121 EXPECT_TRUE(service.IsTracked(contents)); 122 delete contents; 123 EXPECT_FALSE(service.IsTracked(contents)); 124 } 125 126 TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAdded) { 127 TestingProfile profile; 128 ClearPrefs(&profile); 129 BackgroundContentsService service(&profile, command_line_.get()); 130 GURL orig_url; 131 GURL url("http://a/"); 132 GURL url2("http://a/"); 133 { 134 scoped_ptr<MockBackgroundContents> contents( 135 new MockBackgroundContents(&profile)); 136 EXPECT_EQ(0U, GetPrefs(&profile)->size()); 137 contents->SendOpenedNotification(&service); 138 139 contents->Navigate(url); 140 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 141 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid())); 142 143 // Navigate the contents to a new url, should not change url. 144 contents->Navigate(url2); 145 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 146 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid())); 147 } 148 // Contents are deleted, url should persist. 149 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 150 } 151 152 TEST_F(BackgroundContentsServiceTest, BackgroundContentsUrlAddedAndClosed) { 153 TestingProfile profile; 154 ClearPrefs(&profile); 155 BackgroundContentsService service(&profile, command_line_.get()); 156 GURL url("http://a/"); 157 MockBackgroundContents* contents = new MockBackgroundContents(&profile); 158 EXPECT_EQ(0U, GetPrefs(&profile)->size()); 159 contents->SendOpenedNotification(&service); 160 contents->Navigate(url); 161 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 162 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid())); 163 164 // Fake a window closed by script. 165 contents->MockClose(&profile); 166 EXPECT_EQ(0U, GetPrefs(&profile)->size()); 167 } 168 169 // Test what happens if a BackgroundContents shuts down (say, due to a renderer 170 // crash) then is restarted. Should not persist URL twice. 171 TEST_F(BackgroundContentsServiceTest, RestartBackgroundContents) { 172 TestingProfile profile; 173 ClearPrefs(&profile); 174 BackgroundContentsService service(&profile, command_line_.get()); 175 GURL url("http://a/"); 176 { 177 scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents( 178 &profile, "appid")); 179 contents->SendOpenedNotification(&service); 180 contents->Navigate(url); 181 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 182 EXPECT_EQ(url.spec(), GetPrefURLForApp(&profile, contents->appid())); 183 } 184 // Contents deleted, url should be persisted. 185 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 186 187 { 188 // Reopen the BackgroundContents to the same URL, we should not register the 189 // URL again. 190 scoped_ptr<MockBackgroundContents> contents(new MockBackgroundContents( 191 &profile, "appid")); 192 contents->SendOpenedNotification(&service); 193 contents->Navigate(url); 194 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 195 } 196 } 197 198 // Ensures that BackgroundContentsService properly tracks the association 199 // between a BackgroundContents and its parent extension, including 200 // unregistering the BC when the extension is uninstalled. 201 TEST_F(BackgroundContentsServiceTest, TestApplicationIDLinkage) { 202 TestingProfile profile; 203 BackgroundContentsService service(&profile, command_line_.get()); 204 ClearPrefs(&profile); 205 206 EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid"))); 207 MockBackgroundContents* contents = new MockBackgroundContents(&profile, 208 "appid"); 209 scoped_ptr<MockBackgroundContents> contents2( 210 new MockBackgroundContents(&profile, "appid2")); 211 contents->SendOpenedNotification(&service); 212 EXPECT_EQ(contents, service.GetAppBackgroundContents(contents->appid())); 213 contents2->SendOpenedNotification(&service); 214 EXPECT_EQ(contents2.get(), service.GetAppBackgroundContents( 215 contents2->appid())); 216 EXPECT_EQ(0U, GetPrefs(&profile)->size()); 217 218 // Navigate the contents, then make sure the one associated with the extension 219 // is unregistered. 220 GURL url("http://a/"); 221 GURL url2("http://b/"); 222 contents->Navigate(url); 223 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 224 contents2->Navigate(url2); 225 EXPECT_EQ(2U, GetPrefs(&profile)->size()); 226 service.ShutdownAssociatedBackgroundContents(ASCIIToUTF16("appid")); 227 EXPECT_FALSE(service.IsTracked(contents)); 228 EXPECT_EQ(NULL, service.GetAppBackgroundContents(ASCIIToUTF16("appid"))); 229 EXPECT_EQ(1U, GetPrefs(&profile)->size()); 230 EXPECT_EQ(url2.spec(), GetPrefURLForApp(&profile, contents2->appid())); 231 } 232