- add sources.
[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/common/extensions/extension_file_util.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 "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 DictionaryValue* LoadManifestFile(const base::FilePath path,
82                                   std::string* error) {
83   EXPECT_TRUE(base::PathExists(path));
84   JSONFileValueSerializer serializer(path);
85   return static_cast<DictionaryValue*>(serializer.Deserialize(NULL, error));
86 }
87
88 scoped_refptr<Extension> LoadExtension(const std::string& filename,
89                                        std::string* error) {
90   base::FilePath path;
91   PathService::Get(chrome::DIR_TEST_DATA, &path);
92   path = path.
93       AppendASCII("extensions").
94       AppendASCII("manifest_tests").
95       AppendASCII(filename.c_str());
96   scoped_ptr<DictionaryValue> value(LoadManifestFile(path, error));
97   if (!value)
98     return NULL;
99   return Extension::Create(path.DirName(), Manifest::UNPACKED, *value,
100                            Extension::NO_FLAGS, error);
101 }
102
103 class SimpleTestJobProtocolHandler
104     : public net::URLRequestJobFactory::ProtocolHandler {
105  public:
106   SimpleTestJobProtocolHandler() {}
107   virtual ~SimpleTestJobProtocolHandler() {}
108
109   // net::URLRequestJobFactory::ProtocolHandler
110   virtual net::URLRequestJob* MaybeCreateJob(
111       net::URLRequest* request,
112       net::NetworkDelegate* network_delegate) const OVERRIDE {
113     return new SimpleTestJob(request, network_delegate);
114   }
115
116  private:
117   DISALLOW_COPY_AND_ASSIGN(SimpleTestJobProtocolHandler);
118 };
119
120 }  // namespace
121
122 class UserScriptListenerTest : public ExtensionServiceTestBase {
123  public:
124   UserScriptListenerTest() {
125     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
126         "http", "google.com",
127         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
128             new SimpleTestJobProtocolHandler()));
129     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
130         "http", "example.com",
131         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(
132             new SimpleTestJobProtocolHandler()));
133   }
134
135   virtual ~UserScriptListenerTest() {
136     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler("http",
137                                                                 "google.com");
138     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler("http",
139                                                                 "example.com");
140   }
141
142   virtual void SetUp() OVERRIDE {
143     ExtensionServiceTestBase::SetUp();
144
145     InitializeEmptyExtensionService();
146     service_->Init();
147     base::MessageLoop::current()->RunUntilIdle();
148
149     listener_ = new UserScriptListener();
150   }
151
152   virtual void TearDown() OVERRIDE {
153     listener_ = NULL;
154     base::MessageLoop::current()->RunUntilIdle();
155     ExtensionServiceTestBase::TearDown();
156   }
157
158  protected:
159   net::TestURLRequest* StartTestRequest(net::URLRequest::Delegate* delegate,
160                                         const std::string& url_string,
161                                         net::TestURLRequestContext* context) {
162     GURL url(url_string);
163     net::TestURLRequest* request =
164         new net::TestURLRequest(url, net::DEFAULT_PRIORITY, delegate, context);
165
166     ResourceThrottle* throttle =
167         listener_->CreateResourceThrottle(url, ResourceType::MAIN_FRAME);
168
169     bool defer = false;
170     if (throttle) {
171       request->SetUserData(NULL, new ThrottleController(request, throttle));
172
173       throttle->WillStartRequest(&defer);
174     }
175
176     if (!defer)
177       request->Start();
178
179     return request;
180   }
181
182   void LoadTestExtension() {
183     base::FilePath test_dir;
184     ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir));
185     base::FilePath extension_path = test_dir
186         .AppendASCII("extensions")
187         .AppendASCII("good")
188         .AppendASCII("Extensions")
189         .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
190         .AppendASCII("1.0.0.0");
191     UnpackedInstaller::Create(service_)->Load(extension_path);
192   }
193
194   void UnloadTestExtension() {
195     ASSERT_FALSE(service_->extensions()->is_empty());
196     service_->UnloadExtension((*service_->extensions()->begin())->id(),
197                               UnloadedExtensionInfo::REASON_DISABLE);
198   }
199
200   scoped_refptr<UserScriptListener> listener_;
201 };
202
203 namespace {
204
205 TEST_F(UserScriptListenerTest, DelayAndUpdate) {
206   LoadTestExtension();
207   base::MessageLoop::current()->RunUntilIdle();
208
209   net::TestDelegate delegate;
210   net::TestURLRequestContext context;
211   scoped_ptr<net::TestURLRequest> request(
212       StartTestRequest(&delegate, kMatchingUrl, &context));
213   ASSERT_FALSE(request->is_pending());
214
215   content::NotificationService::current()->Notify(
216       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
217       content::Source<Profile>(profile_.get()),
218       content::NotificationService::NoDetails());
219   base::MessageLoop::current()->RunUntilIdle();
220   EXPECT_EQ(kTestData, delegate.data_received());
221 }
222
223 TEST_F(UserScriptListenerTest, DelayAndUnload) {
224   LoadTestExtension();
225   base::MessageLoop::current()->RunUntilIdle();
226
227   net::TestDelegate delegate;
228   net::TestURLRequestContext context;
229   scoped_ptr<net::TestURLRequest> request(
230       StartTestRequest(&delegate, kMatchingUrl, &context));
231   ASSERT_FALSE(request->is_pending());
232
233   UnloadTestExtension();
234   base::MessageLoop::current()->RunUntilIdle();
235
236   // This is still not enough to start delayed requests. We have to notify the
237   // listener that the user scripts have been updated.
238   ASSERT_FALSE(request->is_pending());
239
240   content::NotificationService::current()->Notify(
241       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
242       content::Source<Profile>(profile_.get()),
243       content::NotificationService::NoDetails());
244   base::MessageLoop::current()->RunUntilIdle();
245   EXPECT_EQ(kTestData, delegate.data_received());
246 }
247
248 TEST_F(UserScriptListenerTest, NoDelayNoExtension) {
249   net::TestDelegate delegate;
250   net::TestURLRequestContext context;
251   scoped_ptr<net::TestURLRequest> request(
252       StartTestRequest(&delegate, kMatchingUrl, &context));
253
254   // The request should be started immediately.
255   ASSERT_TRUE(request->is_pending());
256
257   base::MessageLoop::current()->RunUntilIdle();
258   EXPECT_EQ(kTestData, delegate.data_received());
259 }
260
261 TEST_F(UserScriptListenerTest, NoDelayNotMatching) {
262   LoadTestExtension();
263   base::MessageLoop::current()->RunUntilIdle();
264
265   net::TestDelegate delegate;
266   net::TestURLRequestContext context;
267   scoped_ptr<net::TestURLRequest> request(StartTestRequest(&delegate,
268                                                            kNotMatchingUrl,
269                                                            &context));
270
271   // The request should be started immediately.
272   ASSERT_TRUE(request->is_pending());
273
274   base::MessageLoop::current()->RunUntilIdle();
275   EXPECT_EQ(kTestData, delegate.data_received());
276 }
277
278 TEST_F(UserScriptListenerTest, MultiProfile) {
279   LoadTestExtension();
280   base::MessageLoop::current()->RunUntilIdle();
281
282   // Fire up a second profile and have it load and extension with a content
283   // script.
284   TestingProfile profile2;
285   std::string error;
286   scoped_refptr<Extension> extension = LoadExtension(
287       "content_script_yahoo.json", &error);
288   ASSERT_TRUE(extension.get());
289
290   content::NotificationService::current()->Notify(
291       chrome::NOTIFICATION_EXTENSION_LOADED,
292       content::Source<Profile>(&profile2),
293       content::Details<Extension>(extension.get()));
294
295   net::TestDelegate delegate;
296   net::TestURLRequestContext context;
297   scoped_ptr<net::TestURLRequest> request(
298       StartTestRequest(&delegate, kMatchingUrl, &context));
299   ASSERT_FALSE(request->is_pending());
300
301   // When the first profile's user scripts are ready, the request should still
302   // be blocked waiting for profile2.
303   content::NotificationService::current()->Notify(
304       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
305       content::Source<Profile>(profile_.get()),
306       content::NotificationService::NoDetails());
307   base::MessageLoop::current()->RunUntilIdle();
308   ASSERT_FALSE(request->is_pending());
309   EXPECT_TRUE(delegate.data_received().empty());
310
311   // After profile2 is ready, the request should proceed.
312   content::NotificationService::current()->Notify(
313       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
314       content::Source<Profile>(&profile2),
315       content::NotificationService::NoDetails());
316   base::MessageLoop::current()->RunUntilIdle();
317   EXPECT_EQ(kTestData, delegate.data_received());
318 }
319
320 // Test when the script updated notification occurs before the throttle's
321 // WillStartRequest function is called.  This can occur when there are multiple
322 // throttles.
323 TEST_F(UserScriptListenerTest, ResumeBeforeStart) {
324   LoadTestExtension();
325   base::MessageLoop::current()->RunUntilIdle();
326   net::TestDelegate delegate;
327   net::TestURLRequestContext context;
328   GURL url(kMatchingUrl);
329   scoped_ptr<net::TestURLRequest> request(
330       new net::TestURLRequest(url, net::DEFAULT_PRIORITY, &delegate, &context));
331
332   ResourceThrottle* throttle =
333       listener_->CreateResourceThrottle(url, ResourceType::MAIN_FRAME);
334   ASSERT_TRUE(throttle);
335   request->SetUserData(NULL, new ThrottleController(request.get(), throttle));
336
337   ASSERT_FALSE(request->is_pending());
338
339   content::NotificationService::current()->Notify(
340       chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
341       content::Source<Profile>(profile_.get()),
342       content::NotificationService::NoDetails());
343   base::MessageLoop::current()->RunUntilIdle();
344
345   bool defer = false;
346   throttle->WillStartRequest(&defer);
347   ASSERT_FALSE(defer);
348 }
349
350 }  // namespace
351
352 }  // namespace extensions