Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "chrome/browser/apps/drive/drive_app_provider.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/macros.h" | |
| 9 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/path_service.h" | |
| 11 #include "base/timer/timer.h" | |
| 12 #include "chrome/browser/apps/drive/drive_app_mapping.h" | |
| 13 #include "chrome/browser/apps/drive/drive_service_bridge.h" | |
| 14 #include "chrome/browser/drive/drive_app_registry.h" | |
| 15 #include "chrome/browser/drive/fake_drive_service.h" | |
| 16 #include "chrome/browser/extensions/extension_browsertest.h" | |
| 17 #include "chrome/browser/extensions/install_tracker.h" | |
| 18 #include "chrome/browser/extensions/install_tracker_factory.h" | |
| 19 #include "chrome/common/chrome_paths.h" | |
| 20 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" | |
| 21 #include "content/public/test/test_utils.h" | |
| 22 #include "extensions/browser/extension_registry.h" | |
| 23 | |
| 24 using extensions::AppLaunchInfo; | |
| 25 using extensions::Extension; | |
| 26 using extensions::ExtensionRegistry; | |
| 27 | |
| 28 namespace { | |
| 29 | |
| 30 const char kDriveAppId[] = "drive_app_id"; | |
| 31 const char kDriveAppName[] = "Fake Drive App"; | |
| 32 const char kLaunchUrl[] = "http://example.com/drive"; | |
| 33 | |
| 34 // App id of hosted_app.crx. | |
| 35 const char kChromeAppId[] = "kbmnembihfiondgfjekmnmcbddelicoi"; | |
| 36 | |
| 37 // Stub drive service bridge. | |
| 38 class TestDriveServiceBridge : public DriveServiceBridge { | |
| 39 public: | |
| 40 explicit TestDriveServiceBridge(drive::DriveAppRegistry* registry) | |
| 41 : registry_(registry) {} | |
| 42 virtual ~TestDriveServiceBridge() {} | |
| 43 | |
| 44 virtual drive::DriveAppRegistry* GetAppRegistry() OVERRIDE { | |
| 45 return registry_; | |
| 46 } | |
| 47 | |
| 48 private: | |
| 49 drive::DriveAppRegistry* registry_; | |
| 50 | |
| 51 DISALLOW_COPY_AND_ASSIGN(TestDriveServiceBridge); | |
| 52 }; | |
| 53 | |
| 54 } // namespace | |
| 55 | |
| 56 class DriveAppProviderTest : public ExtensionBrowserTest { | |
| 57 public: | |
| 58 DriveAppProviderTest() {} | |
| 59 virtual ~DriveAppProviderTest() {} | |
| 60 | |
| 61 // ExtensionBrowserTest: | |
| 62 virtual void SetUpOnMainThread() OVERRIDE { | |
| 63 ExtensionBrowserTest::SetUpOnMainThread(); | |
| 64 | |
| 65 fake_drive_service_.reset(new drive::FakeDriveService); | |
| 66 fake_drive_service_->LoadAppListForDriveApi("drive/applist_empty.json"); | |
| 67 apps_registry_.reset( | |
| 68 new drive::DriveAppRegistry(fake_drive_service_.get())); | |
| 69 | |
| 70 provider_.reset(new DriveAppProvider(profile())); | |
| 71 provider_->SetDriveServiceBridgeForTest( | |
| 72 make_scoped_ptr(new TestDriveServiceBridge(apps_registry_.get())) | |
| 73 .PassAs<DriveServiceBridge>()); | |
| 74 } | |
| 75 | |
| 76 virtual void CleanUpOnMainThread() OVERRIDE { | |
| 77 provider_.reset(); | |
| 78 apps_registry_.reset(); | |
| 79 fake_drive_service_.reset(); | |
| 80 | |
| 81 ExtensionBrowserTest::CleanUpOnMainThread(); | |
| 82 } | |
| 83 | |
| 84 const Extension* InstallChromeApp(int expected_change) { | |
| 85 base::FilePath test_data_path; | |
| 86 if (!PathService::Get(chrome::DIR_TEST_DATA, &test_data_path)) { | |
| 87 ADD_FAILURE(); | |
| 88 return NULL; | |
| 89 } | |
| 90 test_data_path = | |
| 91 test_data_path.AppendASCII("extensions").AppendASCII("hosted_app.crx"); | |
| 92 const Extension* extension = | |
| 93 InstallExtension(test_data_path, expected_change); | |
| 94 return extension; | |
| 95 } | |
| 96 | |
| 97 void RefreshDriveAppRegistry() { | |
| 98 apps_registry_->Update(); | |
| 99 content::RunAllPendingInMessageLoop(); | |
| 100 } | |
| 101 | |
| 102 void WaitForPendingDriveAppConverters() { | |
| 103 DCHECK(!runner_); | |
| 104 | |
| 105 if (provider_->pending_converters_.empty()) | |
| 106 return; | |
| 107 | |
| 108 runner_ = new content::MessageLoopRunner; | |
| 109 | |
| 110 pending_drive_app_converter_check_timer_.Start( | |
| 111 FROM_HERE, | |
| 112 base::TimeDelta::FromMilliseconds(50), | |
| 113 base::Bind(&DriveAppProviderTest::OnPendingDriveAppConverterCheckTimer, | |
| 114 base::Unretained(this))); | |
| 115 | |
| 116 runner_->Run(); | |
| 117 | |
| 118 pending_drive_app_converter_check_timer_.Stop(); | |
| 119 runner_ = NULL; | |
| 120 } | |
| 121 | |
| 122 drive::FakeDriveService* fake_drive_service() { | |
| 123 return fake_drive_service_.get(); | |
| 124 } | |
| 125 DriveAppProvider* provider() { return provider_.get(); } | |
| 126 DriveAppMapping* mapping() { return provider_->mapping_.get(); } | |
| 127 | |
| 128 private: | |
| 129 void OnPendingDriveAppConverterCheckTimer() { | |
| 130 if (provider_->pending_converters_.empty()) | |
| 131 runner_->Quit(); | |
| 132 } | |
| 133 | |
| 134 scoped_ptr<drive::FakeDriveService> fake_drive_service_; | |
| 135 scoped_ptr<drive::DriveAppRegistry> apps_registry_; | |
| 136 scoped_ptr<DriveAppProvider> provider_; | |
| 137 | |
| 138 base::RepeatingTimer<DriveAppProviderTest> | |
| 139 pending_drive_app_converter_check_timer_; | |
| 140 scoped_refptr<content::MessageLoopRunner> runner_; | |
| 141 | |
| 142 DISALLOW_COPY_AND_ASSIGN(DriveAppProviderTest); | |
| 143 }; | |
| 144 | |
| 145 // A Drive app maps to an existing Chrome app that has a matching id. | |
| 146 // Uninstalling the chrome app would also disconnect the drive app. | |
| 147 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, ExistingChromeApp) { | |
| 148 // Prepare an existing chrome app. | |
| 149 const Extension* chrome_app = InstallChromeApp(1); | |
| 150 ASSERT_TRUE(chrome_app); | |
| 151 | |
| 152 // Prepare a Drive app that matches the chrome app id. | |
| 153 fake_drive_service()->AddApp( | |
| 154 kDriveAppId, kDriveAppName, chrome_app->id(), kLaunchUrl); | |
| 155 RefreshDriveAppRegistry(); | |
| 156 WaitForPendingDriveAppConverters(); | |
|
benwells
2014/06/11 00:15:21
Why is this necessary here? Shouldn't there be no
xiyuan
2014/06/11 04:52:34
There should not be any. But it would be good to h
benwells
2014/06/12 06:28:59
OK, could we check instead that there are no pendi
xiyuan
2014/06/12 19:30:20
Done. Updated here an elsewhere it makes sense.
| |
| 157 | |
| 158 // The Drive app should use the matching chrome app. | |
| 159 EXPECT_EQ(chrome_app->id(), mapping()->GetChromeApp(kDriveAppId)); | |
| 160 | |
| 161 // Unintalling chrome app should disconnect the Drive app on server. | |
| 162 EXPECT_TRUE(fake_drive_service()->HasApp(kDriveAppId)); | |
| 163 UninstallExtension(chrome_app->id()); | |
| 164 EXPECT_FALSE(fake_drive_service()->HasApp(kDriveAppId)); | |
| 165 } | |
| 166 | |
| 167 // A Drive app creates an URL app when no matching Chrome app presents. | |
| 168 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, CreateUrlApp) { | |
| 169 // Prepare a Drive app with no underlying chrome app. | |
| 170 fake_drive_service()->AddApp(kDriveAppId, kDriveAppName, "", kLaunchUrl); | |
| 171 RefreshDriveAppRegistry(); | |
| 172 WaitForPendingDriveAppConverters(); | |
| 173 | |
| 174 // An Url app should be created. | |
| 175 const Extension* chrome_app = | |
| 176 ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 177 mapping()->GetChromeApp(kDriveAppId), ExtensionRegistry::EVERYTHING); | |
| 178 ASSERT_TRUE(chrome_app); | |
| 179 EXPECT_EQ(kDriveAppName, chrome_app->name()); | |
| 180 EXPECT_TRUE(chrome_app->is_hosted_app()); | |
| 181 EXPECT_TRUE(chrome_app->from_bookmark()); | |
| 182 EXPECT_EQ(GURL(kLaunchUrl), AppLaunchInfo::GetLaunchWebURL(chrome_app)); | |
| 183 | |
| 184 EXPECT_EQ(chrome_app->id(), mapping()->GetChromeApp(kDriveAppId)); | |
| 185 | |
| 186 // Unintalling the chrome app should disconnect the Drive app on server. | |
| 187 EXPECT_TRUE(fake_drive_service()->HasApp(kDriveAppId)); | |
| 188 UninstallExtension(chrome_app->id()); | |
| 189 EXPECT_FALSE(fake_drive_service()->HasApp(kDriveAppId)); | |
| 190 } | |
| 191 | |
| 192 // A matching Chrome app replaces the created URL app. | |
| 193 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, MatchingChromeAppInstalled) { | |
| 194 // Prepare a Drive app that matches the not-yet-installed kChromeAppId. | |
| 195 fake_drive_service()->AddApp( | |
| 196 kDriveAppId, kDriveAppName, kChromeAppId, kLaunchUrl); | |
| 197 RefreshDriveAppRegistry(); | |
| 198 WaitForPendingDriveAppConverters(); | |
| 199 | |
| 200 // An Url app should be created. | |
| 201 const Extension* url_app = | |
| 202 ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 203 mapping()->GetChromeApp(kDriveAppId), ExtensionRegistry::EVERYTHING); | |
| 204 EXPECT_TRUE(url_app->is_hosted_app()); | |
| 205 EXPECT_TRUE(url_app->from_bookmark()); | |
| 206 | |
| 207 const std::string url_app_id = url_app->id(); | |
| 208 EXPECT_NE(kChromeAppId, url_app_id); | |
| 209 EXPECT_EQ(url_app_id, mapping()->GetChromeApp(kDriveAppId)); | |
| 210 | |
| 211 // Installs a chrome app with matching id. | |
| 212 InstallChromeApp(0); | |
| 213 | |
| 214 // The Drive app should be mapped to chrome app. | |
| 215 EXPECT_EQ(kChromeAppId, mapping()->GetChromeApp(kDriveAppId)); | |
| 216 | |
| 217 // Url app should be auto uninstalled. | |
| 218 EXPECT_FALSE(ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 219 url_app_id, ExtensionRegistry::EVERYTHING)); | |
| 220 } | |
| 221 | |
| 222 // Tests that the corresponding URL app is uninstalled when a Drive app is | |
| 223 // disconnected. | |
| 224 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, | |
| 225 DisconnectDriveAppUninstallUrlApp) { | |
| 226 // Prepare a Drive app that matches the not-yet-installed kChromeAppId. | |
| 227 fake_drive_service()->AddApp( | |
| 228 kDriveAppId, kDriveAppName, kChromeAppId, kLaunchUrl); | |
| 229 RefreshDriveAppRegistry(); | |
| 230 WaitForPendingDriveAppConverters(); | |
| 231 | |
| 232 // Url app is created. | |
| 233 const std::string url_app_id = mapping()->GetChromeApp(kDriveAppId); | |
| 234 EXPECT_TRUE(ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 235 url_app_id, ExtensionRegistry::EVERYTHING)); | |
| 236 | |
| 237 fake_drive_service()->RemoveAppByProductId(kChromeAppId); | |
| 238 RefreshDriveAppRegistry(); | |
| 239 | |
| 240 // Url app is auto uninstalled. | |
| 241 EXPECT_FALSE(ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 242 url_app_id, ExtensionRegistry::EVERYTHING)); | |
| 243 } | |
| 244 | |
| 245 // Tests that the matching Chrome app is preserved when a Drive app is | |
| 246 // disconnected. | |
| 247 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, | |
| 248 DisconnectDriveAppPreserveChromeApp) { | |
| 249 // Prepare an existing chrome app. | |
| 250 const Extension* chrome_app = InstallChromeApp(1); | |
| 251 ASSERT_TRUE(chrome_app); | |
| 252 | |
| 253 // Prepare a Drive app that matches the chrome app id. | |
| 254 fake_drive_service()->AddApp( | |
| 255 kDriveAppId, kDriveAppName, kChromeAppId, kLaunchUrl); | |
| 256 RefreshDriveAppRegistry(); | |
| 257 WaitForPendingDriveAppConverters(); | |
| 258 | |
| 259 fake_drive_service()->RemoveAppByProductId(kChromeAppId); | |
| 260 RefreshDriveAppRegistry(); | |
| 261 | |
| 262 // Chrome app is still present after the Drive app is disconnected. | |
| 263 EXPECT_TRUE(ExtensionRegistry::Get(profile())->GetExtensionById( | |
| 264 kChromeAppId, ExtensionRegistry::EVERYTHING)); | |
| 265 } | |
| 266 | |
| 267 // A new URL app replaces the existing one and keeps existing// position when a | |
| 268 // Drive app changes its name or URL. | |
| 269 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, DriveAppChanged) { | |
| 270 // Prepare a Drive app with no underlying chrome app. | |
| 271 fake_drive_service()->AddApp( | |
| 272 kDriveAppId, kDriveAppName, kChromeAppId, kLaunchUrl); | |
| 273 RefreshDriveAppRegistry(); | |
| 274 WaitForPendingDriveAppConverters(); | |
| 275 | |
| 276 // An Url app should be created. | |
| 277 const std::string url_app_id = mapping()->GetChromeApp(kDriveAppId); | |
| 278 const Extension* url_app = | |
| 279 ExtensionRegistry::Get(profile()) | |
| 280 ->GetExtensionById(url_app_id, ExtensionRegistry::EVERYTHING); | |
| 281 ASSERT_TRUE(url_app); | |
| 282 EXPECT_EQ(kDriveAppName, url_app->name()); | |
| 283 EXPECT_TRUE(url_app->is_hosted_app()); | |
| 284 EXPECT_TRUE(url_app->from_bookmark()); | |
| 285 EXPECT_EQ(GURL(kLaunchUrl), AppLaunchInfo::GetLaunchWebURL(url_app)); | |
| 286 | |
| 287 // Register the Drive app with a different name and URL. | |
| 288 const char kAnotherName[] = "Another drive app name"; | |
| 289 const char kAnotherLaunchUrl[] = "http://example.com/another_end_point"; | |
| 290 fake_drive_service()->RemoveAppByProductId(kChromeAppId); | |
| 291 fake_drive_service()->AddApp( | |
| 292 kDriveAppId, kAnotherName, kChromeAppId, kAnotherLaunchUrl); | |
| 293 RefreshDriveAppRegistry(); | |
| 294 WaitForPendingDriveAppConverters(); | |
| 295 | |
| 296 // Old URL app should be auto uninstalled. | |
| 297 url_app = ExtensionRegistry::Get(profile()) | |
| 298 ->GetExtensionById(url_app_id, ExtensionRegistry::EVERYTHING); | |
| 299 EXPECT_FALSE(url_app); | |
| 300 | |
| 301 // New URL app should be used. | |
| 302 const std::string new_url_app_id = mapping()->GetChromeApp(kDriveAppId); | |
| 303 EXPECT_NE(new_url_app_id, url_app_id); | |
| 304 | |
| 305 const Extension* new_url_app = | |
| 306 ExtensionRegistry::Get(profile()) | |
| 307 ->GetExtensionById(new_url_app_id, ExtensionRegistry::EVERYTHING); | |
| 308 ASSERT_TRUE(new_url_app); | |
| 309 EXPECT_EQ(kAnotherName, new_url_app->name()); | |
| 310 EXPECT_TRUE(new_url_app->is_hosted_app()); | |
| 311 EXPECT_TRUE(new_url_app->from_bookmark()); | |
| 312 EXPECT_EQ(GURL(kAnotherLaunchUrl), | |
| 313 AppLaunchInfo::GetLaunchWebURL(new_url_app)); | |
| 314 } | |
| 315 | |
| 316 // An existing URL app is not changed when underlying drive app data (name and | |
| 317 // URL) is not changed. | |
| 318 IN_PROC_BROWSER_TEST_F(DriveAppProviderTest, NoChange) { | |
| 319 // Prepare one Drive app. | |
| 320 fake_drive_service()->AddApp( | |
| 321 kDriveAppId, kDriveAppName, kChromeAppId, kLaunchUrl); | |
| 322 RefreshDriveAppRegistry(); | |
| 323 WaitForPendingDriveAppConverters(); | |
| 324 | |
| 325 const std::string url_app_id = mapping()->GetChromeApp(kDriveAppId); | |
| 326 const Extension* url_app = | |
| 327 ExtensionRegistry::Get(profile()) | |
| 328 ->GetExtensionById(url_app_id, ExtensionRegistry::EVERYTHING); | |
| 329 | |
| 330 // Refresh with no actual change. | |
| 331 RefreshDriveAppRegistry(); | |
| 332 WaitForPendingDriveAppConverters(); | |
| 333 | |
| 334 // Url app should remain unchanged. | |
| 335 const std::string new_url_app_id = mapping()->GetChromeApp(kDriveAppId); | |
| 336 EXPECT_EQ(new_url_app_id, url_app_id); | |
| 337 | |
| 338 const Extension* new_url_app = | |
| 339 ExtensionRegistry::Get(profile()) | |
| 340 ->GetExtensionById(new_url_app_id, ExtensionRegistry::EVERYTHING); | |
| 341 EXPECT_EQ(url_app, new_url_app); | |
| 342 } | |
| OLD | NEW |