Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / user_script_listener_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 "base/file_util.h"
6 #include "base/json/json_file_value_serializer.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/threading/thread.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/extension_service_unittest.h"
11 #include "chrome/browser/extensions/unpacked_installer.h"
12 #include "chrome/browser/extensions/user_script_listener.h"
13 #include "chrome/common/chrome_paths.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "content/public/browser/notification_service.h"
16 #include "content/public/browser/resource_controller.h"
17 #include "content/public/browser/resource_throttle.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "net/base/request_priority.h"
20 #include "net/url_request/url_request.h"
21 #include "net/url_request/url_request_filter.h"
22 #include "net/url_request/url_request_test_job.h"
23 #include "net/url_request/url_request_test_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using content::ResourceController;
27 using content::ResourceThrottle;
28
29 namespace extensions {
30
31 namespace {
32
33 const char kMatchingUrl[] = "http://google.com/";
34 const char kNotMatchingUrl[] = "http://example.com/";
35 const char kTestData[] = "Hello, World!";
36
37 class ThrottleController : public base::SupportsUserData::Data,
38                            public ResourceController {
39  public:
40   ThrottleController(net::URLRequest* request, ResourceThrottle* throttle)
41       : request_(request),
42         throttle_(throttle) {
43     throttle_->set_controller_for_testing(this);
44   }
45
46   // ResourceController implementation:
47   virtual void Resume() OVERRIDE {
48     request_->Start();
49   }
50   virtual void Cancel() OVERRIDE {
51     NOTREACHED();
52   }
53   virtual void CancelAndIgnore() OVERRIDE {
54     NOTREACHED();
55   }
56   virtual void CancelWithError(int error_code) OVERRIDE {
57     NOTREACHED();
58   }
59
60  private:
61   net::URLRequest* request_;
62   scoped_ptr<ResourceThrottle> throttle_;
63 };
64
65 // A simple test net::URLRequestJob. We don't care what it does, only that
66 // whether it starts and finishes.
67 class SimpleTestJob : public net::URLRequestTestJob {
68  public:
69   SimpleTestJob(net::URLRequest* request,
70                 net::NetworkDelegate* network_delegate)
71       : net::URLRequestTestJob(request,
72                                network_delegate,
73                                test_headers(),
74                                kTestData,
75                                true) {}
76  private:
77   virtual ~SimpleTestJob() {}
78 };
79
80 // Yoinked from extension_manifest_unittest.cc.
81 base::DictionaryValue* LoadManifestFile(const base::FilePath path,
82                                         std::string* error) {
83   EXPECT_TRUE(base::PathExists(path));
84   JSONFileValueSerializer serializer(path);
85   return static_cast<base::DictionaryValue*>(
86       serializer.Deserialize(NULL, error));
87 }
88
89 scoped_refptr<Extension> LoadExtension(const std::string& filename,
90                                        std::string* error) {
91   base::FilePath path;
92   PathService::Get(chrome::DIR_TEST_DATA, &path);
93   path = path.
94       AppendASCII("extensions").
95       AppendASCII("manifest_tests").
96       AppendASCII(filename.c_str());
97   scoped_ptr<base::DictionaryValue> value(LoadManifestFile(path, error));
98   if (!value)
99     return NULL;
100   return Extension::Create(path.DirName(), Manifest::UNPACKED, *value,
101                            Extension::NO_FLAGS, error);
102 }
103
104 class SimpleTestJobProtocolHandler
105     : public net::URLRequestJobFactory::ProtocolHandler {
106  public:
107   SimpleTestJobProtocolHandler() {}
108   virtual ~SimpleTestJobProtocolHandler() {}
109
110   // net::URLRequestJobFactory::ProtocolHandler
111   virtual net::URLRequestJob* MaybeCreateJob(
112       net::URLRequest* request,
113       net::NetworkDelegate* network_delegate) const OVERRIDE {
114     return new SimpleTestJob(request, network_delegate);
115   }
116
117  private:
118   DISALLOW_COPY_AND_ASSIGN(SimpleTestJobProtocolHandler);
119 };
120
121 }  // namespace
122
123 class UserScriptListenerTest : public ExtensionServiceTestBase {
124  public:
125   UserScriptListenerTest() {
126     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
127         "http", "google.com",
128         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
129             new SimpleTestJobProtocolHandler()));
130     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
131         "http", "example.com",
132         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
133             new SimpleTestJobProtocolHandler()));
134   }
135
136   virtual ~UserScriptListenerTest() {
137     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler("http",
138                                                                 "google.com");
139     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler("http",
140                                                                 "example.com");
141   }
142
143   virtual void SetUp() OVERRIDE {
144     ExtensionServiceTestBase::SetUp();
145
146     InitializeEmptyExtensionService();
147     service_->Init();
148     base::MessageLoop::current()->RunUntilIdle();
149
150     listener_ = new UserScriptListener();
151   }
152
153   virtual void TearDown() OVERRIDE {
154     listener_ = NULL;
155     base::MessageLoop::current()->RunUntilIdle();
156     ExtensionServiceTestBase::TearDown();
157   }
158
159  protected:
160   net::TestURLRequest* StartTestRequest(net::URLRequest::Delegate* delegate,
161                                         const std::string& url_string,
162                                         net::TestURLRequestContext* context) {
163     GURL url(url_string);
164     net::TestURLRequest* request =
165         new net::TestURLRequest(url, net::DEFAULT_PRIORITY, delegate, context);
166
167     ResourceThrottle* throttle =
168         listener_->CreateResourceThrottle(url, ResourceType::MAIN_FRAME);
169
170     bool defer = false;
171     if (throttle) {
172       request->SetUserData(NULL, new ThrottleController(request, throttle));
173
174       throttle->WillStartRequest(&defer);
175     }
176
177     if (!defer)
178       request->Start();
179
180     return request;
181   }
182
183   void LoadTestExtension() {
184     base::FilePath test_dir;
185     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
186     base::FilePath extension_path = test_dir
187         .AppendASCII("extensions")
188         .AppendASCII("good")
189         .AppendASCII("Extensions")
190         .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
191         .AppendASCII("1.0.0.0");
192     UnpackedInstaller::Create(service_)->Load(extension_path);
193   }
194
195   void UnloadTestExtension() {
196     ASSERT_FALSE(service_->extensions()->is_empty());
197     service_->UnloadExtension((*service_->extensions()->begin())->id(),
198                               UnloadedExtensionInfo::REASON_DISABLE);
199   }
200
201   scoped_refptr<UserScriptListener> listener_;
202 };
203
204 namespace {
205
206 TEST_F(UserScriptListenerTest, DelayAndUpdate) {
207   LoadTestExtension();
208   base::MessageLoop::current()->RunUntilIdle();
209
210   net::TestDelegate delegate;
211   net::TestURLRequestContext context;
212   scoped_ptr<net::TestURLRequest> request(
213       StartTestRequest(&delegate, kMatchingUrl, &context));
214   ASSERT_FALSE(request->is_pending());
215
216   content::NotificationService::current()->Notify(
217       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
218       content::Source<Profile>(profile_.get()),
219       content::NotificationService::NoDetails());
220   base::MessageLoop::current()->RunUntilIdle();
221   EXPECT_EQ(kTestData, delegate.data_received());
222 }
223
224 TEST_F(UserScriptListenerTest, DelayAndUnload) {
225   LoadTestExtension();
226   base::MessageLoop::current()->RunUntilIdle();
227
228   net::TestDelegate delegate;
229   net::TestURLRequestContext context;
230   scoped_ptr<net::TestURLRequest> request(
231       StartTestRequest(&delegate, kMatchingUrl, &context));
232   ASSERT_FALSE(request->is_pending());
233
234   UnloadTestExtension();
235   base::MessageLoop::current()->RunUntilIdle();
236
237   // This is still not enough to start delayed requests. We have to notify the
238   // listener that the user scripts have been updated.
239   ASSERT_FALSE(request->is_pending());
240
241   content::NotificationService::current()->Notify(
242       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
243       content::Source<Profile>(profile_.get()),
244       content::NotificationService::NoDetails());
245   base::MessageLoop::current()->RunUntilIdle();
246   EXPECT_EQ(kTestData, delegate.data_received());
247 }
248
249 TEST_F(UserScriptListenerTest, NoDelayNoExtension) {
250   net::TestDelegate delegate;
251   net::TestURLRequestContext context;
252   scoped_ptr<net::TestURLRequest> request(
253       StartTestRequest(&delegate, kMatchingUrl, &context));
254
255   // The request should be started immediately.
256   ASSERT_TRUE(request->is_pending());
257
258   base::MessageLoop::current()->RunUntilIdle();
259   EXPECT_EQ(kTestData, delegate.data_received());
260 }
261
262 TEST_F(UserScriptListenerTest, NoDelayNotMatching) {
263   LoadTestExtension();
264   base::MessageLoop::current()->RunUntilIdle();
265
266   net::TestDelegate delegate;
267   net::TestURLRequestContext context;
268   scoped_ptr<net::TestURLRequest> request(StartTestRequest(&delegate,
269                                                            kNotMatchingUrl,
270                                                            &context));
271
272   // The request should be started immediately.
273   ASSERT_TRUE(request->is_pending());
274
275   base::MessageLoop::current()->RunUntilIdle();
276   EXPECT_EQ(kTestData, delegate.data_received());
277 }
278
279 TEST_F(UserScriptListenerTest, MultiProfile) {
280   LoadTestExtension();
281   base::MessageLoop::current()->RunUntilIdle();
282
283   // Fire up a second profile and have it load an extension with a content
284   // script.
285   TestingProfile profile2;
286   std::string error;
287   scoped_refptr<Extension> extension = LoadExtension(
288       "content_script_yahoo.json", &error);
289   ASSERT_TRUE(extension.get());
290
291   extensions::ExtensionRegistry::Get(&profile2)->AddEnabled(extension);
292
293   content::NotificationService::current()->Notify(
294       chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
295       content::Source<Profile>(&profile2),
296       content::Details<Extension>(extension.get()));
297
298   net::TestDelegate delegate;
299   net::TestURLRequestContext context;
300   scoped_ptr<net::TestURLRequest> request(
301       StartTestRequest(&delegate, kMatchingUrl, &context));
302   ASSERT_FALSE(request->is_pending());
303
304   // When the first profile's user scripts are ready, the request should still
305   // be blocked waiting for profile2.
306   content::NotificationService::current()->Notify(
307       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
308       content::Source<Profile>(profile_.get()),
309       content::NotificationService::NoDetails());
310   base::MessageLoop::current()->RunUntilIdle();
311   ASSERT_FALSE(request->is_pending());
312   EXPECT_TRUE(delegate.data_received().empty());
313
314   // After profile2 is ready, the request should proceed.
315   content::NotificationService::current()->Notify(
316       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
317       content::Source<Profile>(&profile2),
318       content::NotificationService::NoDetails());
319   base::MessageLoop::current()->RunUntilIdle();
320   EXPECT_EQ(kTestData, delegate.data_received());
321 }
322
323 // Test when the script updated notification occurs before the throttle's
324 // WillStartRequest function is called.  This can occur when there are multiple
325 // throttles.
326 TEST_F(UserScriptListenerTest, ResumeBeforeStart) {
327   LoadTestExtension();
328   base::MessageLoop::current()->RunUntilIdle();
329   net::TestDelegate delegate;
330   net::TestURLRequestContext context;
331   GURL url(kMatchingUrl);
332   scoped_ptr<net::TestURLRequest> request(
333       new net::TestURLRequest(url, net::DEFAULT_PRIORITY, &delegate, &context));
334
335   ResourceThrottle* throttle =
336       listener_->CreateResourceThrottle(url, ResourceType::MAIN_FRAME);
337   ASSERT_TRUE(throttle);
338   request->SetUserData(NULL, new ThrottleController(request.get(), throttle));
339
340   ASSERT_FALSE(request->is_pending());
341
342   content::NotificationService::current()->Notify(
343       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
344       content::Source<Profile>(profile_.get()),
345       content::NotificationService::NoDetails());
346   base::MessageLoop::current()->RunUntilIdle();
347
348   bool defer = false;
349   throttle->WillStartRequest(&defer);
350   ASSERT_FALSE(defer);
351 }
352
353 }  // namespace
354
355 }  // namespace extensions