15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/ui/app_list/extension_app_model_builder.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
12ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/run_loop.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/extension_function_test_utils.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/install_tracker.h"
174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/browser/extensions/install_tracker_factory.h"
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/ui/app_list/app_list_test_util.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/pref_names.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/testing_profile.h"
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/app_sorting.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_prefs.h"
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/uninstall_reason.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/constants.h"
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/common/extension_set.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/app_list/app_list_item.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Get a string of all apps in |model| joined with ','.
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)std::string GetModelContent(app_list::AppListModel* model) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string content;
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (size_t i = 0; i < model->top_level_item_list()->item_count(); ++i) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i > 0)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content += ',';
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    content += model->top_level_item_list()->item_at(i)->name();
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return content;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_refptr<extensions::Extension> MakeApp(const std::string& name,
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const std::string& version,
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const std::string& url,
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const std::string& id) {
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string err;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue value;
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value.SetString("name", name);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value.SetString("version", version);
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  value.SetString("app.launch.web_url", url);
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<extensions::Extension> app =
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extensions::Extension::Create(
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          base::FilePath(),
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          extensions::Manifest::INTERNAL,
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          value,
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          id,
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &err);
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(err, "");
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return app;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class TestAppListControllerDelegate : public AppListControllerDelegate {
68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public:
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual ~TestAppListControllerDelegate() {}
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void DismissView() OVERRIDE {}
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual gfx::NativeWindow GetAppListWindow() OVERRIDE { return NULL; }
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { return gfx::ImageSkia(); }
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE {
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return false;
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void PinApp(const std::string& extension_id) OVERRIDE {}
77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void UnpinApp(const std::string& extension_id) OVERRIDE {}
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual Pinnable GetPinnable() OVERRIDE { return NO_PIN; }
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual bool CanDoCreateShortcutsFlow() OVERRIDE { return false; }
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void DoCreateShortcutsFlow(Profile* profile,
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                     const std::string& extension_id) OVERRIDE {
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual bool CanDoShowAppInfoFlow() OVERRIDE { return false; }
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void DoShowAppInfoFlow(Profile* profile,
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 const std::string& extension_id) OVERRIDE {
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE {}
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void ActivateApp(Profile* profile,
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           const extensions::Extension* extension,
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           AppListSource source,
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           int event_flags) OVERRIDE {}
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void LaunchApp(Profile* profile,
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         const extensions::Extension* extension,
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         AppListSource source,
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                         int event_flags) OVERRIDE {}
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual void ShowForProfileByPath(
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const base::FilePath& profile_path) OVERRIDE {}
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  virtual bool ShouldShowUserIcon() OVERRIDE { return false; }
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)};
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const char kDefaultApps[] = "Packaged App 1,Packaged App 2,Hosted App";
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const size_t kDefaultAppCount = 3u;
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class ExtensionAppModelBuilderTest : public AppListTestBase {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ExtensionAppModelBuilderTest() {}
1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  virtual ~ExtensionAppModelBuilderTest() {}
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    AppListTestBase::SetUp();
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CreateBuilder();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void TearDown() OVERRIDE {
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResetBuilder();
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) protected:
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Creates a new builder, destroying any existing one.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CreateBuilder() {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResetBuilder();  // Destroy any existing builder in the correct order.
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    model_.reset(new app_list::AppListModel);
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    controller_.reset(new TestAppListControllerDelegate);
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    builder_.reset(new ExtensionAppModelBuilder(controller_.get()));
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    builder_->InitializeWithProfile(profile_.get(), model_.get());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void ResetBuilder() {
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    builder_.reset();
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    controller_.reset();
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    model_.reset();
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  scoped_ptr<app_list::AppListModel> model_;
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<TestAppListControllerDelegate> controller_;
140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<ExtensionAppModelBuilder> builder_;
141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::ScopedTempDir second_profile_temp_dir_;
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private:
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilderTest);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, Build) {
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The apps list would have 3 extension apps in the profile.
150a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(kDefaultAppCount, model_->top_level_item_list()->item_count());
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Install a "web store" app.
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<extensions::Extension> store =
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MakeApp("webstore",
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              "0.0",
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              "http://google.com",
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci              std::string(extensions::kWebStoreAppId));
1617d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  service_->AddExtension(store.get());
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Install an "enterprise web store" app.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_refptr<extensions::Extension> enterprise_store =
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      MakeApp("enterprise_webstore",
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              "0.0",
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              "http://google.com",
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              std::string(extension_misc::kEnterpriseWebStoreAppId));
1697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  service_->AddExtension(enterprise_store.get());
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Web stores should be present in the AppListModel.
1724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  app_list::AppListModel model1;
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionAppModelBuilder builder1(controller_.get());
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  builder1.InitializeWithProfile(profile_.get(), &model1);
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(model1.FindItem(store->id()));
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(model1.FindItem(enterprise_store->id()));
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Activate the HideWebStoreIcon policy.
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, true);
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Now the web stores should not be present anymore.
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(model1.FindItem(store->id()));
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(model1.FindItem(enterprise_store->id()));
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Build a new AppListModel; web stores should NOT be present.
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  app_list::AppListModel model2;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionAppModelBuilder builder2(controller_.get());
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  builder2.InitializeWithProfile(profile_.get(), &model2);
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(model2.FindItem(store->id()));
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(model2.FindItem(enterprise_store->id()));
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Deactivate the HideWebStoreIcon policy again.
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, false);
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Now the web stores should have appeared.
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(model2.FindItem(store->id()));
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(model2.FindItem(enterprise_store->id()));
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, DisableAndEnable) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_->DisableExtension(kHostedAppId,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             extensions::Extension::DISABLE_NONE);
2034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  service_->EnableExtension(kHostedAppId);
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, Uninstall) {
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  service_->UninstallExtension(kPackagedApp2Id,
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               extensions::UNINSTALL_REASON_FOR_TESTING,
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               base::Bind(&base::DoNothing),
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               NULL);
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
2154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            GetModelContent(model_.get()));
2167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
217ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::RunLoop().RunUntilIdle();
2187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, UninstallTerminatedApp) {
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const extensions::Extension* app =
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      service_->GetInstalledExtension(kPackagedApp2Id);
2237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ASSERT_TRUE(app != NULL);
2247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Simulate an app termination.
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  service_->TrackTerminatedExtensionForTest(app);
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  service_->UninstallExtension(kPackagedApp2Id,
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               extensions::UNINSTALL_REASON_FOR_TESTING,
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               base::Bind(&base::DoNothing),
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               NULL);
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            GetModelContent(model_.get()));
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
235ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  base::RunLoop().RunUntilIdle();
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, Reinstall) {
2394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Install kPackagedApp1Id again should not create a new entry.
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  extensions::InstallTracker* tracker =
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      extensions::InstallTrackerFactory::GetForBrowserContext(profile_.get());
244f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  extensions::InstallObserver::ExtensionInstallParams params(
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      kPackagedApp1Id, "", gfx::ImageSkia(), true, true);
246f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  tracker->OnBeginExtensionInstall(params);
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, OrdinalPrefsChange) {
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extensions::AppSorting* sorting =
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::ExtensionPrefs::Get(profile_.get())->app_sorting();
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::StringOrdinal package_app_page =
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorting->GetPageOrdinal(kPackagedApp1Id);
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sorting->SetPageOrdinal(kHostedAppId, package_app_page.CreateBefore());
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // New behavior: Sorting order doesn't change.
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::StringOrdinal app1_ordinal =
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorting->GetAppLaunchOrdinal(kPackagedApp1Id);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  syncer::StringOrdinal app2_ordinal =
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sorting->GetAppLaunchOrdinal(kPackagedApp2Id);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sorting->SetPageOrdinal(kHostedAppId, package_app_page);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sorting->SetAppLaunchOrdinal(kHostedAppId,
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                               app1_ordinal.CreateBetween(app2_ordinal));
2694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
2704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // New behavior: Sorting order doesn't change.
2714e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, OnExtensionMoved) {
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extensions::AppSorting* sorting =
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::ExtensionPrefs::Get(profile_.get())->app_sorting();
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sorting->SetPageOrdinal(kHostedAppId,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          sorting->GetPageOrdinal(kPackagedApp1Id));
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sorting->OnExtensionMoved(kHostedAppId, kPackagedApp1Id, kPackagedApp2Id);
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // New behavior: Sorting order doesn't change.
2834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sorting->OnExtensionMoved(kHostedAppId, kPackagedApp2Id, std::string());
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Old behavior: This would be restored to the default order.
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // New behavior: Sorting order still doesn't change.
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
29023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  sorting->OnExtensionMoved(kHostedAppId, std::string(), kPackagedApp1Id);
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
2924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // New behavior: Sorting order doesn't change.
2934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, InvalidOrdinal) {
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates a no-ordinal case.
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extensions::AppSorting* sorting =
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::ExtensionPrefs::Get(profile_.get())->app_sorting();
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->ClearOrdinals(kPackagedApp1Id);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Creates a corrupted ordinal case.
303a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extensions::ExtensionScopedPrefs* scoped_prefs =
304a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::ExtensionPrefs::Get(profile_.get());
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_prefs->UpdateExtensionPref(
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      kHostedAppId,
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "page_ordinal",
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new base::StringValue("a corrupted ordinal"));
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This should not assert or crash.
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateBuilder();
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, OrdinalConfilicts) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates conflict ordinals for app1 and app2.
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  syncer::StringOrdinal conflict_ordinal =
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      syncer::StringOrdinal::CreateInitialOrdinal();
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  extensions::AppSorting* sorting =
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      extensions::ExtensionPrefs::Get(profile_.get())->app_sorting();
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetPageOrdinal(kHostedAppId, conflict_ordinal);
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetAppLaunchOrdinal(kHostedAppId, conflict_ordinal);
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetPageOrdinal(kPackagedApp1Id, conflict_ordinal);
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetAppLaunchOrdinal(kPackagedApp1Id, conflict_ordinal);
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetPageOrdinal(kPackagedApp2Id, conflict_ordinal);
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  sorting->SetAppLaunchOrdinal(kPackagedApp2Id, conflict_ordinal);
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // This should not assert or crash.
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateBuilder();
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // By default, conflicted items are sorted by their app ids (= order added).
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(std::string("Hosted App,Packaged App 1,Packaged App 2"),
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            GetModelContent(model_.get()));
3364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This test adds a bookmark app to the app list.
3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(ExtensionAppModelBuilderTest, BookmarkApp) {
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string kAppName = "Bookmark App";
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string kAppVersion = "2014.1.24.19748";
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string kAppUrl = "http://google.com";
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string kAppId = "podhdnefolignjhecmjkbimfgioanahm";
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string err;
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue value;
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  value.SetString("name", kAppName);
3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  value.SetString("version", kAppVersion);
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  value.SetString("app.launch.web_url", kAppUrl);
3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_refptr<extensions::Extension> bookmark_app =
3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      extensions::Extension::Create(
3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          base::FilePath(),
3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extensions::Manifest::INTERNAL,
3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          value,
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          extensions::Extension::WAS_INSTALLED_BY_DEFAULT |
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              extensions::Extension::FROM_BOOKMARK,
3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kAppId,
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          &err);
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(err.empty());
3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  service_->AddExtension(bookmark_app.get());
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(kDefaultAppCount + 1, model_->top_level_item_list()->item_count());
3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_NE(std::string::npos, GetModelContent(model_.get()).find(kAppName));
3635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
364