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