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