Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / app_list / extension_app_model_builder_unittest.cc
1 // Copyright (c) 2012 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/ui/app_list/extension_app_model_builder.h"
6
7 #include <string>
8
9 #include "base/files/file_path.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/run_loop.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/browser/extensions/extension_service_unittest.h"
16 #include "chrome/browser/extensions/install_tracker.h"
17 #include "chrome/browser/extensions/install_tracker_factory.h"
18 #include "chrome/browser/ui/app_list/app_list_controller_delegate_impl.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "extensions/browser/app_sorting.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/common/manifest.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27 #include "ui/app_list/app_list_item.h"
28
29 namespace {
30
31 const char kHostedAppId[] = "dceacbkfkmllgmjmbhgkpjegnodmildf";
32 const char kPackagedApp1Id[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
33 const char kPackagedApp2Id[] = "jlklkagmeajbjiobondfhiekepofmljl";
34
35 // Get a string of all apps in |model| joined with ','.
36 std::string GetModelContent(app_list::AppListModel* model) {
37   std::string content;
38   for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
39     if (i > 0)
40       content += ',';
41     content += model->item_list()->item_at(i)->title();
42   }
43   return content;
44 }
45
46 scoped_refptr<extensions::Extension> MakeApp(const std::string& name,
47                                              const std::string& version,
48                                              const std::string& url,
49                                              const std::string& id) {
50   std::string err;
51   base::DictionaryValue value;
52   value.SetString("name", name);
53   value.SetString("version", version);
54   value.SetString("app.launch.web_url", url);
55   scoped_refptr<extensions::Extension> app =
56       extensions::Extension::Create(
57           base::FilePath(),
58           extensions::Manifest::INTERNAL,
59           value,
60           extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
61           id,
62           &err);
63   EXPECT_EQ(err, "");
64   return app;
65 }
66
67 class TestAppListControllerDelegate : public AppListControllerDelegate {
68  public:
69   virtual ~TestAppListControllerDelegate() {}
70   virtual void DismissView() OVERRIDE {}
71   virtual gfx::NativeWindow GetAppListWindow() OVERRIDE { return NULL; }
72   virtual gfx::ImageSkia GetWindowIcon() OVERRIDE { return gfx::ImageSkia(); }
73   virtual bool IsAppPinned(const std::string& extension_id) OVERRIDE {
74     return false;
75   }
76   virtual void PinApp(const std::string& extension_id) OVERRIDE {}
77   virtual void UnpinApp(const std::string& extension_id) OVERRIDE {}
78   virtual Pinnable GetPinnable() OVERRIDE { return NO_PIN; }
79   virtual bool CanDoCreateShortcutsFlow() OVERRIDE { return false; }
80   virtual void DoCreateShortcutsFlow(Profile* profile,
81                                      const std::string& extension_id) OVERRIDE {
82   }
83   virtual bool CanDoShowAppInfoFlow() OVERRIDE { return false; }
84   virtual void DoShowAppInfoFlow(Profile* profile,
85                                  const std::string& extension_id) OVERRIDE {
86   };
87   virtual void CreateNewWindow(Profile* profile, bool incognito) OVERRIDE {}
88   virtual void ActivateApp(Profile* profile,
89                            const extensions::Extension* extension,
90                            AppListSource source,
91                            int event_flags) OVERRIDE {}
92   virtual void LaunchApp(Profile* profile,
93                          const extensions::Extension* extension,
94                          AppListSource source,
95                          int event_flags) OVERRIDE {}
96   virtual void ShowForProfileByPath(
97       const base::FilePath& profile_path) OVERRIDE {}
98   virtual bool ShouldShowUserIcon() OVERRIDE { return false; }
99 };
100
101 const char kDefaultApps[] = "Packaged App 1,Packaged App 2,Hosted App";
102 const size_t kDefaultAppCount = 3u;
103
104 }  // namespace
105
106 class ExtensionAppModelBuilderTest : public ExtensionServiceTestBase {
107  public:
108   ExtensionAppModelBuilderTest() {}
109   virtual ~ExtensionAppModelBuilderTest() {}
110
111   virtual void SetUp() OVERRIDE {
112     ExtensionServiceTestBase::SetUp();
113
114     // Load "app_list" extensions test profile.
115     // The test profile has 4 extensions:
116     // 1 dummy extension, 2 packaged extension apps and 1 hosted extension app.
117     base::FilePath source_install_dir = data_dir_
118         .AppendASCII("app_list")
119         .AppendASCII("Extensions");
120     base::FilePath pref_path = source_install_dir
121         .DirName()
122         .Append(chrome::kPreferencesFilename);
123     InitializeInstalledExtensionService(pref_path, source_install_dir);
124     service_->Init();
125
126     // There should be 4 extensions in the test profile.
127     const extensions::ExtensionSet* extensions = service_->extensions();
128     ASSERT_EQ(static_cast<size_t>(4),  extensions->size());
129
130     CreateBuilder();
131   }
132
133   virtual void TearDown() OVERRIDE {
134     ResetBuilder();
135   }
136
137  protected:
138   // Creates a new builder, destroying any existing one.
139   void CreateBuilder() {
140     ResetBuilder();  // Destroy any existing builder in the correct order.
141
142     model_.reset(new app_list::AppListModel);
143     controller_.reset(new TestAppListControllerDelegate);
144     builder_.reset(new ExtensionAppModelBuilder(controller_.get()));
145     builder_->InitializeWithProfile(profile_.get(), model_.get());
146   }
147
148   void ResetBuilder() {
149     builder_.reset();
150     controller_.reset();
151     model_.reset();
152   }
153
154   scoped_ptr<app_list::AppListModel> model_;
155   scoped_ptr<TestAppListControllerDelegate> controller_;
156   scoped_ptr<ExtensionAppModelBuilder> builder_;
157
158   base::ScopedTempDir second_profile_temp_dir_;
159
160  private:
161   DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilderTest);
162 };
163
164 TEST_F(ExtensionAppModelBuilderTest, Build) {
165   // The apps list would have 3 extension apps in the profile.
166   EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
167   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
168 }
169
170 TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
171   // Install a "web store" app.
172   scoped_refptr<extensions::Extension> store =
173       MakeApp("webstore",
174               "0.0",
175               "http://google.com",
176               std::string(extension_misc::kWebStoreAppId));
177   service_->AddExtension(store.get());
178
179   // Install an "enterprise web store" app.
180   scoped_refptr<extensions::Extension> enterprise_store =
181       MakeApp("enterprise_webstore",
182               "0.0",
183               "http://google.com",
184               std::string(extension_misc::kEnterpriseWebStoreAppId));
185   service_->AddExtension(enterprise_store.get());
186
187   // Web stores should be present in the AppListModel.
188   app_list::AppListModel model1;
189   ExtensionAppModelBuilder builder1(controller_.get());
190   builder1.InitializeWithProfile(profile_.get(), &model1);
191   std::string content = GetModelContent(&model1);
192   EXPECT_NE(std::string::npos, content.find("webstore"));
193   EXPECT_NE(std::string::npos, content.find("enterprise_webstore"));
194
195   // Activate the HideWebStoreIcon policy.
196   profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, true);
197
198   // Web stores should NOT be in the AppListModel.
199   app_list::AppListModel model2;
200   ExtensionAppModelBuilder builder2(controller_.get());
201   builder2.InitializeWithProfile(profile_.get(), &model2);
202   content = GetModelContent(&model2);
203   EXPECT_EQ(std::string::npos, content.find("webstore"));
204   EXPECT_EQ(std::string::npos, content.find("enterprise_webstore"));
205 }
206
207 TEST_F(ExtensionAppModelBuilderTest, DisableAndEnable) {
208   service_->DisableExtension(kHostedAppId,
209                              extensions::Extension::DISABLE_NONE);
210   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
211
212   service_->EnableExtension(kHostedAppId);
213   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
214 }
215
216 TEST_F(ExtensionAppModelBuilderTest, Uninstall) {
217   service_->UninstallExtension(kPackagedApp2Id, false, NULL);
218   EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
219             GetModelContent(model_.get()));
220
221   base::RunLoop().RunUntilIdle();
222 }
223
224 TEST_F(ExtensionAppModelBuilderTest, UninstallTerminatedApp) {
225   const extensions::Extension* app =
226       service_->GetInstalledExtension(kPackagedApp2Id);
227   ASSERT_TRUE(app != NULL);
228
229   // Simulate an app termination.
230   service_->TrackTerminatedExtensionForTest(app);
231
232   service_->UninstallExtension(kPackagedApp2Id, false, NULL);
233   EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
234             GetModelContent(model_.get()));
235
236   base::RunLoop().RunUntilIdle();
237 }
238
239 TEST_F(ExtensionAppModelBuilderTest, Reinstall) {
240   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
241
242   // Install kPackagedApp1Id again should not create a new entry.
243   extensions::InstallTracker* tracker =
244       extensions::InstallTrackerFactory::GetForProfile(profile_.get());
245   extensions::InstallObserver::ExtensionInstallParams params(
246       kPackagedApp1Id, "", gfx::ImageSkia(), true, true);
247   tracker->OnBeginExtensionInstall(params);
248
249   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
250 }
251
252 TEST_F(ExtensionAppModelBuilderTest, OrdinalPrefsChange) {
253   extensions::AppSorting* sorting = service_->extension_prefs()->app_sorting();
254
255   syncer::StringOrdinal package_app_page =
256       sorting->GetPageOrdinal(kPackagedApp1Id);
257   sorting->SetPageOrdinal(kHostedAppId, package_app_page.CreateBefore());
258   // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
259   // New behavior: Sorting order doesn't change.
260   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
261
262   syncer::StringOrdinal app1_ordinal =
263       sorting->GetAppLaunchOrdinal(kPackagedApp1Id);
264   syncer::StringOrdinal app2_ordinal =
265       sorting->GetAppLaunchOrdinal(kPackagedApp2Id);
266   sorting->SetPageOrdinal(kHostedAppId, package_app_page);
267   sorting->SetAppLaunchOrdinal(kHostedAppId,
268                                app1_ordinal.CreateBetween(app2_ordinal));
269   // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
270   // New behavior: Sorting order doesn't change.
271   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
272 }
273
274 TEST_F(ExtensionAppModelBuilderTest, OnExtensionMoved) {
275   extensions::AppSorting* sorting = service_->extension_prefs()->app_sorting();
276   sorting->SetPageOrdinal(kHostedAppId,
277                           sorting->GetPageOrdinal(kPackagedApp1Id));
278
279   service_->OnExtensionMoved(kHostedAppId, kPackagedApp1Id, kPackagedApp2Id);
280   // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
281   // New behavior: Sorting order doesn't change.
282   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
283
284   service_->OnExtensionMoved(kHostedAppId, kPackagedApp2Id, std::string());
285   // Old behavior: This would be restored to the default order.
286   // New behavior: Sorting order still doesn't change.
287   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
288
289   service_->OnExtensionMoved(kHostedAppId, std::string(), kPackagedApp1Id);
290   // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
291   // New behavior: Sorting order doesn't change.
292   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
293 }
294
295 TEST_F(ExtensionAppModelBuilderTest, InvalidOrdinal) {
296   // Creates a no-ordinal case.
297   extensions::AppSorting* sorting = service_->extension_prefs()->app_sorting();
298   sorting->ClearOrdinals(kPackagedApp1Id);
299
300   // Creates a corrupted ordinal case.
301   extensions::ExtensionScopedPrefs* scoped_prefs = service_->extension_prefs();
302   scoped_prefs->UpdateExtensionPref(
303       kHostedAppId,
304       "page_ordinal",
305       base::Value::CreateStringValue("a corrupted ordinal"));
306
307   // This should not assert or crash.
308   CreateBuilder();
309 }
310
311 TEST_F(ExtensionAppModelBuilderTest, OrdinalConfilicts) {
312   // Creates conflict ordinals for app1 and app2.
313   syncer::StringOrdinal conflict_ordinal =
314       syncer::StringOrdinal::CreateInitialOrdinal();
315
316   extensions::AppSorting* sorting = service_->extension_prefs()->app_sorting();
317   sorting->SetPageOrdinal(kHostedAppId, conflict_ordinal);
318   sorting->SetAppLaunchOrdinal(kHostedAppId, conflict_ordinal);
319
320   sorting->SetPageOrdinal(kPackagedApp1Id, conflict_ordinal);
321   sorting->SetAppLaunchOrdinal(kPackagedApp1Id, conflict_ordinal);
322
323   sorting->SetPageOrdinal(kPackagedApp2Id, conflict_ordinal);
324   sorting->SetAppLaunchOrdinal(kPackagedApp2Id, conflict_ordinal);
325
326   // This should not assert or crash.
327   CreateBuilder();
328
329   // By default, conflicted items are sorted by their app ids (= order added).
330   EXPECT_EQ(std::string("Hosted App,Packaged App 1,Packaged App 2"),
331             GetModelContent(model_.get()));
332 }
333
334 // This test adds a bookmark app to the app list.
335 TEST_F(ExtensionAppModelBuilderTest, BookmarkApp) {
336   const std::string kAppName = "Bookmark App";
337   const std::string kAppVersion = "2014.1.24.19748";
338   const std::string kAppUrl = "http://google.com";
339   const std::string kAppId = "podhdnefolignjhecmjkbimfgioanahm";
340   std::string err;
341   base::DictionaryValue value;
342   value.SetString("name", kAppName);
343   value.SetString("version", kAppVersion);
344   value.SetString("app.launch.web_url", kAppUrl);
345   scoped_refptr<extensions::Extension> bookmark_app =
346       extensions::Extension::Create(
347           base::FilePath(),
348           extensions::Manifest::INTERNAL,
349           value,
350           extensions::Extension::WAS_INSTALLED_BY_DEFAULT |
351               extensions::Extension::FROM_BOOKMARK,
352           kAppId,
353           &err);
354   EXPECT_TRUE(err.empty());
355
356   service_->AddExtension(bookmark_app.get());
357   EXPECT_EQ(kDefaultAppCount + 1, model_->item_list()->item_count());
358   EXPECT_NE(std::string::npos, GetModelContent(model_.get()).find(kAppName));
359 }