• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // TODO(rickcam): Bug 73183: Add unit tests for image loading
6 
7 #include <cstdlib>
8 #include <set>
9 
10 #include "chrome/browser/background_application_list_model.h"
11 
12 #include "base/command_line.h"
13 #include "base/file_path.h"
14 #include "base/file_util.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop.h"
17 #include "base/stl_util-inl.h"
18 #include "chrome/browser/extensions/extension_service.h"
19 #include "chrome/common/extensions/extension.h"
20 #include "chrome/test/testing_profile.h"
21 #include "content/browser/browser_thread.h"
22 #include "content/common/notification_registrar.h"
23 #include "content/common/notification_service.h"
24 #include "content/common/notification_type.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 
27 // This value is used to seed the PRNG at the beginning of a sequence of
28 // operations to produce a repeatable sequence.
29 #define RANDOM_SEED (0x33F7A7A7)
30 
31 // For ExtensionService interface when it requires a path that is not used.
bogus_file_path()32 FilePath bogus_file_path() {
33   return FilePath(FILE_PATH_LITERAL("//foobar_nonexistent"));
34 }
35 
36 class BackgroundApplicationListModelTest : public testing::Test {
37  public:
38   BackgroundApplicationListModelTest();
39   ~BackgroundApplicationListModelTest();
40 
41   virtual void InitializeEmptyExtensionService();
42 
43  protected:
44   scoped_ptr<Profile> profile_;
45   scoped_refptr<ExtensionService> service_;
46   MessageLoop loop_;
47   BrowserThread ui_thread_;
48 };
49 
50 // The message loop may be used in tests which require it to be an IO loop.
BackgroundApplicationListModelTest()51 BackgroundApplicationListModelTest::BackgroundApplicationListModelTest()
52     : loop_(MessageLoop::TYPE_IO),
53       ui_thread_(BrowserThread::UI, &loop_) {
54 }
55 
~BackgroundApplicationListModelTest()56 BackgroundApplicationListModelTest::~BackgroundApplicationListModelTest() {
57   // Drop reference to ExtensionService and TestingProfile, so that they can be
58   // destroyed while BrowserThreads and MessageLoop are still around.  They
59   // are used in the destruction process.
60   service_ = NULL;
61   profile_.reset(NULL);
62   MessageLoop::current()->RunAllPending();
63 }
64 
65 // This is modeled on a similar routine in ExtensionServiceTestBase.
InitializeEmptyExtensionService()66 void BackgroundApplicationListModelTest::InitializeEmptyExtensionService() {
67   TestingProfile* profile = new TestingProfile();
68   profile_.reset(profile);
69   service_ = profile->CreateExtensionService(
70       CommandLine::ForCurrentProcess(),
71       bogus_file_path(), false);
72   service_->set_extensions_enabled(true);
73   service_->set_show_extensions_prompts(false);
74   service_->OnLoadedInstalledExtensions(); /* Sends EXTENSIONS_READY */
75 }
76 
77 // Returns a barebones test Extension object with the specified |name|.  The
78 // returned extension will include background permission iff
79 // |background_permission| is true.
CreateExtension(const std::string & name,bool background_permission)80 static scoped_refptr<Extension> CreateExtension(const std::string& name,
81                                                 bool background_permission) {
82   DictionaryValue manifest;
83   manifest.SetString(extension_manifest_keys::kVersion, "1.0.0.0");
84   manifest.SetString(extension_manifest_keys::kName, name);
85   if (background_permission) {
86     ListValue* permissions = new ListValue();
87     manifest.Set(extension_manifest_keys::kPermissions, permissions);
88     permissions->Append(Value::CreateStringValue("background"));
89   }
90   std::string error;
91   scoped_refptr<Extension> extension = Extension::Create(
92       bogus_file_path().AppendASCII(name), Extension::INVALID, manifest,
93       Extension::STRICT_ERROR_CHECKS, &error);
94   // Cannot ASSERT_* here because that attempts an illegitimate return.
95   // Cannot EXPECT_NE here because that assumes non-pointers unlike EXPECT_EQ
96   EXPECT_TRUE(extension.get() != NULL) << error;
97   return extension;
98 }
99 
100 // With minimal test logic, verifies behavior over an explicit set of
101 // extensions, of which some are Background Apps and others are not.
TEST_F(BackgroundApplicationListModelTest,LoadExplicitExtensions)102 TEST_F(BackgroundApplicationListModelTest, LoadExplicitExtensions) {
103   InitializeEmptyExtensionService();
104   ExtensionService* service = profile_->GetExtensionService();
105   ASSERT_TRUE(service);
106   ASSERT_TRUE(service->is_ready());
107   ASSERT_TRUE(service->extensions());
108   ASSERT_TRUE(service->extensions()->empty());
109   scoped_ptr<BackgroundApplicationListModel> model(
110       new BackgroundApplicationListModel(profile_.get()));
111   ASSERT_EQ(0U, model->size());
112 
113   scoped_refptr<Extension> ext1 = CreateExtension("alpha", false);
114   scoped_refptr<Extension> ext2 = CreateExtension("bravo", false);
115   scoped_refptr<Extension> ext3 = CreateExtension("charlie", false);
116   scoped_refptr<Extension> bgapp1 = CreateExtension("delta", true);
117   scoped_refptr<Extension> bgapp2 = CreateExtension("echo", true);
118   ASSERT_TRUE(service->extensions() != NULL);
119   ASSERT_EQ(0U, service->extensions()->size());
120   ASSERT_EQ(0U, model->size());
121   // Add alternating Extensions and Background Apps
122   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext1));
123   service->AddExtension(ext1);
124   ASSERT_EQ(1U, service->extensions()->size());
125   ASSERT_EQ(0U, model->size());
126   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp1));
127   service->AddExtension(bgapp1);
128   ASSERT_EQ(2U, service->extensions()->size());
129   ASSERT_EQ(1U, model->size());
130   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext2));
131   service->AddExtension(ext2);
132   ASSERT_EQ(3U, service->extensions()->size());
133   ASSERT_EQ(1U, model->size());
134   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp2));
135   service->AddExtension(bgapp2);
136   ASSERT_EQ(4U, service->extensions()->size());
137   ASSERT_EQ(2U, model->size());
138   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext3));
139   service->AddExtension(ext3);
140   ASSERT_EQ(5U, service->extensions()->size());
141   ASSERT_EQ(2U, model->size());
142   // Remove in FIFO order.
143   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext1));
144   service->UninstallExtension(ext1->id(), false, NULL);
145   ASSERT_EQ(4U, service->extensions()->size());
146   ASSERT_EQ(2U, model->size());
147   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp1));
148   service->UninstallExtension(bgapp1->id(), false, NULL);
149   ASSERT_EQ(3U, service->extensions()->size());
150   ASSERT_EQ(1U, model->size());
151   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext2));
152   service->UninstallExtension(ext2->id(), false, NULL);
153   ASSERT_EQ(2U, service->extensions()->size());
154   ASSERT_EQ(1U, model->size());
155   ASSERT_TRUE(BackgroundApplicationListModel::IsBackgroundApp(*bgapp2));
156   service->UninstallExtension(bgapp2->id(), false, NULL);
157   ASSERT_EQ(1U, service->extensions()->size());
158   ASSERT_EQ(0U, model->size());
159   ASSERT_FALSE(BackgroundApplicationListModel::IsBackgroundApp(*ext3));
160   service->UninstallExtension(ext3->id(), false, NULL);
161   ASSERT_EQ(0U, service->extensions()->size());
162   ASSERT_EQ(0U, model->size());
163 }
164 
165 typedef std::set<scoped_refptr<Extension> > ExtensionSet;
166 
167 namespace {
GenerateUniqueExtensionName()168 std::string GenerateUniqueExtensionName() {
169   static int uniqueness = 0;
170   std::ostringstream output;
171   output << "Unique Named Extension " << uniqueness;
172   ++uniqueness;
173   return output.str();
174 }
175 }
176 
177 // Verifies behavior with a pseudo-randomly generated set of actions: Adding and
178 // removing extensions, of which some are Background Apps and others are not.
TEST_F(BackgroundApplicationListModelTest,LoadRandomExtension)179 TEST_F(BackgroundApplicationListModelTest, LoadRandomExtension) {
180   InitializeEmptyExtensionService();
181   ExtensionService* service = profile_->GetExtensionService();
182   ASSERT_TRUE(service);
183   ASSERT_TRUE(service->is_ready());
184   ASSERT_TRUE(service->extensions());
185   ASSERT_TRUE(service->extensions()->empty());
186   scoped_ptr<BackgroundApplicationListModel> model(
187       new BackgroundApplicationListModel(profile_.get()));
188   ASSERT_EQ(0U, model->size());
189 
190   static const int kIterations = 500;
191   ExtensionSet extensions;
192   size_t count = 0;
193   size_t expected = 0;
194   srand(RANDOM_SEED);
195   for (int index = 0; index < kIterations; ++index) {
196     if (rand() % 2) {  // Add an extension
197       std::string name = GenerateUniqueExtensionName();
198       bool create_background = false;
199       if (rand() % 2) {
200         create_background = true;
201         ++expected;
202       }
203       scoped_refptr<Extension> extension =
204           CreateExtension(name, create_background);
205       ASSERT_EQ(BackgroundApplicationListModel::IsBackgroundApp(*extension),
206                 create_background);
207       extensions.insert(extension);
208       ++count;
209       ASSERT_EQ(count, extensions.size());
210       service->AddExtension(extension);
211       ASSERT_EQ(count, service->extensions()->size());
212       ASSERT_EQ(expected, model->size());
213     } else {  // Maybe remove an extension.
214       ExtensionSet::iterator cursor = extensions.begin();
215       if (cursor == extensions.end()) {
216         // Nothing to remove.  Just verify accounting.
217         ASSERT_EQ(0U, count);
218         ASSERT_EQ(0U, expected);
219         ASSERT_EQ(0U, service->extensions()->size());
220         ASSERT_EQ(0U, model->size());
221       } else {
222         // Randomly select which extension to remove
223         if (extensions.size() > 1) {
224           int offset = rand() % (extensions.size() - 1);
225           for (int index = 0; index < offset; ++index)
226             ++cursor;
227         }
228         scoped_refptr<Extension> extension = cursor->get();
229         std::string id = extension->id();
230         if (BackgroundApplicationListModel::IsBackgroundApp(*extension))
231           --expected;
232         extensions.erase(cursor);
233         --count;
234         ASSERT_EQ(count, extensions.size());
235         service->UninstallExtension(extension->id(), false, NULL);
236         ASSERT_EQ(count, service->extensions()->size());
237         ASSERT_EQ(expected, model->size());
238       }
239     }
240   }
241 }
242