- add sources.
[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/extension_sorting.h"
17 #include "chrome/browser/extensions/install_tracker.h"
18 #include "chrome/browser/extensions/install_tracker_factory.h"
19 #include "chrome/common/extensions/extension_constants.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/test/base/testing_profile.h"
22 #include "extensions/common/manifest.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "ui/app_list/app_list_item_model.h"
25
26 namespace {
27
28 const char kHostedAppId[] = "dceacbkfkmllgmjmbhgkpjegnodmildf";
29 const char kPackagedApp1Id[] = "emfkafnhnpcmabnnkckkchdilgeoekbo";
30 const char kPackagedApp2Id[] = "jlklkagmeajbjiobondfhiekepofmljl";
31
32 // Get a string of all apps in |model| joined with ','.
33 std::string GetModelContent(app_list::AppListModel* model) {
34   std::string content;
35   for (size_t i = 0; i < model->item_list()->item_count(); ++i) {
36     if (i > 0)
37       content += ',';
38     content += model->item_list()->item_at(i)->title();
39   }
40   return content;
41 }
42
43 scoped_refptr<extensions::Extension> MakeApp(const std::string& name,
44                                              const std::string& version,
45                                              const std::string& url,
46                                              const std::string& id) {
47   std::string err;
48   DictionaryValue value;
49   value.SetString("name", name);
50   value.SetString("version", version);
51   value.SetString("app.launch.web_url", url);
52   scoped_refptr<extensions::Extension> app =
53       extensions::Extension::Create(
54           base::FilePath(),
55           extensions::Manifest::INTERNAL,
56           value,
57           extensions::Extension::WAS_INSTALLED_BY_DEFAULT,
58           id,
59           &err);
60   EXPECT_EQ(err, "");
61   return app;
62 }
63
64 const char kDefaultApps[] = "Packaged App 1,Packaged App 2,Hosted App";
65 const size_t kDefaultAppCount = 3u;
66
67 }  // namespace
68
69 class ExtensionAppModelBuilderTest : public ExtensionServiceTestBase {
70  public:
71   ExtensionAppModelBuilderTest() {}
72   virtual ~ExtensionAppModelBuilderTest() {}
73
74   virtual void SetUp() OVERRIDE {
75     ExtensionServiceTestBase::SetUp();
76
77     // Load "app_list" extensions test profile.
78     // The test profile has 4 extensions:
79     // 1 dummy extension, 2 packaged extension apps and 1 hosted extension app.
80     base::FilePath source_install_dir = data_dir_
81         .AppendASCII("app_list")
82         .AppendASCII("Extensions");
83     base::FilePath pref_path = source_install_dir
84         .DirName()
85         .AppendASCII("Preferences");
86     InitializeInstalledExtensionService(pref_path, source_install_dir);
87     service_->Init();
88
89     // There should be 4 extensions in the test profile.
90     const ExtensionSet* extensions = service_->extensions();
91     ASSERT_EQ(static_cast<size_t>(4),  extensions->size());
92
93     model_.reset(new app_list::AppListModel);
94   }
95
96   virtual void TearDown() OVERRIDE {
97     model_.reset();
98   }
99
100  protected:
101   scoped_ptr<app_list::AppListModel> model_;
102
103  private:
104   DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilderTest);
105 };
106
107 TEST_F(ExtensionAppModelBuilderTest, Build) {
108   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
109
110   // The apps list would have 3 extension apps in the profile.
111   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
112 }
113
114 TEST_F(ExtensionAppModelBuilderTest, HideWebStore) {
115   // Install a "web store" app.
116   scoped_refptr<extensions::Extension> store =
117       MakeApp("webstore",
118               "0.0",
119               "http://google.com",
120               std::string(extension_misc::kWebStoreAppId));
121   service_->AddExtension(store.get());
122
123   // Install an "enterprise web store" app.
124   scoped_refptr<extensions::Extension> enterprise_store =
125       MakeApp("enterprise_webstore",
126               "0.0",
127               "http://google.com",
128               std::string(extension_misc::kEnterpriseWebStoreAppId));
129   service_->AddExtension(enterprise_store.get());
130
131   // Web stores should be present in the AppListModel.
132   app_list::AppListModel model1;
133   ExtensionAppModelBuilder builder1(profile_.get(), &model1, NULL);
134   std::string content = GetModelContent(&model1);
135   EXPECT_NE(std::string::npos, content.find("webstore"));
136   EXPECT_NE(std::string::npos, content.find("enterprise_webstore"));
137
138   // Activate the HideWebStoreIcon policy.
139   profile_->GetPrefs()->SetBoolean(prefs::kHideWebStoreIcon, true);
140
141   // Web stores should NOT be in the AppListModel.
142   app_list::AppListModel model2;
143   ExtensionAppModelBuilder builder2(profile_.get(), &model2, NULL);
144   content = GetModelContent(&model2);
145   EXPECT_EQ(std::string::npos, content.find("webstore"));
146   EXPECT_EQ(std::string::npos, content.find("enterprise_webstore"));
147 }
148
149 TEST_F(ExtensionAppModelBuilderTest, DisableAndEnable) {
150   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
151
152   service_->DisableExtension(kHostedAppId,
153                              extensions::Extension::DISABLE_NONE);
154   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
155
156   service_->EnableExtension(kHostedAppId);
157   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
158 }
159
160 TEST_F(ExtensionAppModelBuilderTest, Uninstall) {
161   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
162
163   service_->UninstallExtension(kPackagedApp2Id, false, NULL);
164   EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
165             GetModelContent(model_.get()));
166
167   base::RunLoop().RunUntilIdle();
168 }
169
170 TEST_F(ExtensionAppModelBuilderTest, UninstallTerminatedApp) {
171   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
172
173   const extensions::Extension* app =
174       service_->GetInstalledExtension(kPackagedApp2Id);
175   ASSERT_TRUE(app != NULL);
176
177   // Simulate an app termination.
178   service_->TrackTerminatedExtensionForTest(app);
179
180   service_->UninstallExtension(kPackagedApp2Id, false, NULL);
181   EXPECT_EQ(std::string("Packaged App 1,Hosted App"),
182             GetModelContent(model_.get()));
183
184   base::RunLoop().RunUntilIdle();
185 }
186
187 TEST_F(ExtensionAppModelBuilderTest, Reinstall) {
188   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
189   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
190
191   // Install kPackagedApp1Id again should not create a new entry.
192   extensions::InstallTracker* tracker =
193       extensions::InstallTrackerFactory::GetForProfile(profile_.get());
194   tracker->OnBeginExtensionInstall(
195       kPackagedApp1Id, "", gfx::ImageSkia(), true, true);
196
197   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
198 }
199
200 TEST_F(ExtensionAppModelBuilderTest, OrdinalPrefsChange) {
201   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
202
203   ExtensionSorting* sorting = service_->extension_prefs()->extension_sorting();
204
205   syncer::StringOrdinal package_app_page =
206       sorting->GetPageOrdinal(kPackagedApp1Id);
207   sorting->SetPageOrdinal(kHostedAppId, package_app_page.CreateBefore());
208   // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
209   // New behavior: Sorting order doesn't change.
210   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
211
212   syncer::StringOrdinal app1_ordinal =
213       sorting->GetAppLaunchOrdinal(kPackagedApp1Id);
214   syncer::StringOrdinal app2_ordinal =
215       sorting->GetAppLaunchOrdinal(kPackagedApp2Id);
216   sorting->SetPageOrdinal(kHostedAppId, package_app_page);
217   sorting->SetAppLaunchOrdinal(kHostedAppId,
218                                app1_ordinal.CreateBetween(app2_ordinal));
219   // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
220   // New behavior: Sorting order doesn't change.
221   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
222 }
223
224 TEST_F(ExtensionAppModelBuilderTest, OnExtensionMoved) {
225   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
226
227   ExtensionSorting* sorting = service_->extension_prefs()->extension_sorting();
228   sorting->SetPageOrdinal(kHostedAppId,
229                           sorting->GetPageOrdinal(kPackagedApp1Id));
230
231   service_->OnExtensionMoved(kHostedAppId, kPackagedApp1Id, kPackagedApp2Id);
232   // Old behavior: This would be "Packaged App 1,Hosted App,Packaged App 2"
233   // New behavior: Sorting order doesn't change.
234   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
235
236   service_->OnExtensionMoved(kHostedAppId, kPackagedApp2Id, std::string());
237   // Old behavior: This would be restored to the default order.
238   // New behavior: Sorting order still doesn't change.
239   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
240
241   service_->OnExtensionMoved(kHostedAppId, std::string(), kPackagedApp1Id);
242   // Old behavior: This would be "Hosted App,Packaged App 1,Packaged App 2"
243   // New behavior: Sorting order doesn't change.
244   EXPECT_EQ(std::string(kDefaultApps), GetModelContent(model_.get()));
245 }
246
247 TEST_F(ExtensionAppModelBuilderTest, InvalidOrdinal) {
248   // Creates a no-ordinal case.
249   ExtensionSorting* sorting = service_->extension_prefs()->extension_sorting();
250   sorting->ClearOrdinals(kPackagedApp1Id);
251
252   // Creates an corrupted ordinal case.
253   ExtensionScopedPrefs* scoped_prefs = service_->extension_prefs();
254   scoped_prefs->UpdateExtensionPref(
255       kHostedAppId,
256       "page_ordinal",
257       base::Value::CreateStringValue("a corrupted ordinal"));
258
259   // This should not assert or crash.
260   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
261 }
262
263 TEST_F(ExtensionAppModelBuilderTest, OrdinalConfilicts) {
264   // Creates conflict ordinals for app1 and app2.
265   syncer::StringOrdinal conflict_ordinal =
266       syncer::StringOrdinal::CreateInitialOrdinal();
267
268   ExtensionSorting* sorting = service_->extension_prefs()->extension_sorting();
269   sorting->SetPageOrdinal(kHostedAppId, conflict_ordinal);
270   sorting->SetAppLaunchOrdinal(kHostedAppId, conflict_ordinal);
271
272   sorting->SetPageOrdinal(kPackagedApp1Id, conflict_ordinal);
273   sorting->SetAppLaunchOrdinal(kPackagedApp1Id, conflict_ordinal);
274
275   sorting->SetPageOrdinal(kPackagedApp2Id, conflict_ordinal);
276   sorting->SetAppLaunchOrdinal(kPackagedApp2Id, conflict_ordinal);
277
278   // This should not assert or crash.
279   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
280
281   // By default, conflicted items are sorted by their app ids (= order added).
282   EXPECT_EQ(std::string("Hosted App,Packaged App 1,Packaged App 2"),
283             GetModelContent(model_.get()));
284 }
285
286 TEST_F(ExtensionAppModelBuilderTest, SwitchProfile) {
287   ExtensionAppModelBuilder builder(profile_.get(), model_.get(), NULL);
288   EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
289
290   // Switch to a profile with no apps, ensure all apps are removed.
291   TestingProfile::Builder profile_builder;
292   scoped_ptr<TestingProfile> profile2(profile_builder.Build());
293   builder.SwitchProfile(profile2.get());
294   EXPECT_EQ(0u, model_->item_list()->item_count());
295
296   // Switch back to the main profile, ensure apps are restored.
297   builder.SwitchProfile(profile_.get());
298   EXPECT_EQ(kDefaultAppCount, model_->item_list()->item_count());
299 }