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 #include "base/message_loop.h" 6 #include "base/threading/thread.h" 7 #include "chrome/browser/extensions/extension_service_unittest.h" 8 #include "chrome/browser/extensions/user_script_listener.h" 9 #include "chrome/common/chrome_paths.h" 10 #include "chrome/common/extensions/extension_file_util.h" 11 #include "content/browser/renderer_host/global_request_id.h" 12 #include "content/browser/renderer_host/resource_dispatcher_host_request_info.h" 13 #include "content/browser/renderer_host/resource_handler.h" 14 #include "content/browser/renderer_host/resource_queue.h" 15 #include "content/common/notification_service.h" 16 #include "content/common/notification_type.h" 17 #include "net/url_request/url_request.h" 18 #include "net/url_request/url_request_test_job.h" 19 #include "net/url_request/url_request_test_util.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 class Profile; 23 24 namespace { 25 26 const char kMatchingUrl[] = "http://google.com/"; 27 const char kNotMatchingUrl[] = "http://example.com/"; 28 const char kTestData[] = "Hello, World!"; 29 30 // Dummy ResourceHandler required for ResourceDispatcherHostRequestInfo. 31 class DummyResourceHandler : public ResourceHandler { 32 public: 33 DummyResourceHandler() { 34 } 35 36 virtual bool OnUploadProgress(int request_id, uint64 position, uint64 size) { 37 NOTREACHED(); 38 return true; 39 } 40 41 42 virtual bool OnRequestRedirected(int request_id, const GURL& url, 43 ResourceResponse* response, 44 bool* defer) { 45 NOTREACHED(); 46 return true; 47 } 48 49 virtual bool OnResponseStarted(int request_id, 50 ResourceResponse* response) { 51 NOTREACHED(); 52 return true; 53 } 54 55 virtual bool OnWillStart(int request_id, 56 const GURL& url, 57 bool* defer) { 58 NOTREACHED(); 59 return true; 60 } 61 62 virtual bool OnWillRead(int request_id, 63 net::IOBuffer** buf, 64 int* buf_size, 65 int min_size) { 66 NOTREACHED(); 67 return true; 68 } 69 70 virtual bool OnReadCompleted(int request_id, int* bytes_read) { 71 NOTREACHED(); 72 return true; 73 } 74 75 virtual bool OnResponseCompleted(int request_id, 76 const net::URLRequestStatus& status, 77 const std::string& security_info) { 78 NOTREACHED(); 79 return true; 80 } 81 82 virtual void OnRequestClosed() { 83 } 84 85 private: 86 DISALLOW_COPY_AND_ASSIGN(DummyResourceHandler); 87 }; 88 89 ResourceDispatcherHostRequestInfo* CreateRequestInfo(int request_id) { 90 return new ResourceDispatcherHostRequestInfo( 91 new DummyResourceHandler(), ChildProcessInfo::RENDER_PROCESS, 0, 0, 92 request_id, ResourceType::MAIN_FRAME, 0, false, false, false); 93 } 94 95 // A simple test net::URLRequestJob. We don't care what it does, only that 96 // whether it starts and finishes. 97 class SimpleTestJob : public net::URLRequestTestJob { 98 public: 99 explicit SimpleTestJob(net::URLRequest* request) 100 : net::URLRequestTestJob(request, test_headers(), kTestData, true) {} 101 private: 102 ~SimpleTestJob() {} 103 }; 104 105 class UserScriptListenerTest 106 : public ExtensionServiceTestBase, 107 public net::URLRequest::Interceptor { 108 public: 109 UserScriptListenerTest() { 110 net::URLRequest::RegisterRequestInterceptor(this); 111 } 112 113 ~UserScriptListenerTest() { 114 net::URLRequest::UnregisterRequestInterceptor(this); 115 } 116 117 virtual void SetUp() { 118 ExtensionServiceTestBase::SetUp(); 119 120 InitializeEmptyExtensionService(); 121 service_->Init(); 122 MessageLoop::current()->RunAllPending(); 123 124 listener_ = new UserScriptListener(); 125 126 ResourceQueue::DelegateSet delegates; 127 delegates.insert(listener_.get()); 128 resource_queue_.Initialize(delegates); 129 } 130 131 virtual void TearDown() { 132 resource_queue_.Shutdown(); 133 listener_ = NULL; 134 MessageLoop::current()->RunAllPending(); 135 } 136 137 // net::URLRequest::Interceptor 138 virtual net::URLRequestJob* MaybeIntercept(net::URLRequest* request) { 139 return new SimpleTestJob(request); 140 } 141 142 protected: 143 TestURLRequest* StartTestRequest(net::URLRequest::Delegate* delegate, 144 const std::string& url) { 145 TestURLRequest* request = new TestURLRequest(GURL(url), delegate); 146 scoped_ptr<ResourceDispatcherHostRequestInfo> rdh_info( 147 CreateRequestInfo(0)); 148 resource_queue_.AddRequest(request, *rdh_info.get()); 149 return request; 150 } 151 152 void LoadTestExtension() { 153 FilePath test_dir; 154 ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_dir)); 155 FilePath extension_path = test_dir 156 .AppendASCII("extensions") 157 .AppendASCII("good") 158 .AppendASCII("Extensions") 159 .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj") 160 .AppendASCII("1.0.0.0"); 161 service_->LoadExtension(extension_path); 162 } 163 164 void UnloadTestExtension() { 165 ASSERT_FALSE(service_->extensions()->empty()); 166 service_->UnloadExtension(service_->extensions()->at(0)->id(), 167 UnloadedExtensionInfo::DISABLE); 168 } 169 170 scoped_refptr<UserScriptListener> listener_; 171 172 private: 173 ResourceQueue resource_queue_; 174 }; 175 176 TEST_F(UserScriptListenerTest, DelayAndUpdate) { 177 LoadTestExtension(); 178 MessageLoop::current()->RunAllPending(); 179 180 TestDelegate delegate; 181 scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate, kMatchingUrl)); 182 ASSERT_FALSE(request->is_pending()); 183 184 NotificationService::current()->Notify( 185 NotificationType::USER_SCRIPTS_UPDATED, 186 Source<Profile>(profile_.get()), 187 NotificationService::NoDetails()); 188 MessageLoop::current()->RunAllPending(); 189 EXPECT_EQ(kTestData, delegate.data_received()); 190 } 191 192 TEST_F(UserScriptListenerTest, DelayAndUnload) { 193 LoadTestExtension(); 194 MessageLoop::current()->RunAllPending(); 195 196 TestDelegate delegate; 197 scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate, kMatchingUrl)); 198 ASSERT_FALSE(request->is_pending()); 199 200 UnloadTestExtension(); 201 MessageLoop::current()->RunAllPending(); 202 203 // This is still not enough to start delayed requests. We have to notify the 204 // listener that the user scripts have been updated. 205 ASSERT_FALSE(request->is_pending()); 206 207 NotificationService::current()->Notify( 208 NotificationType::USER_SCRIPTS_UPDATED, 209 Source<Profile>(profile_.get()), 210 NotificationService::NoDetails()); 211 MessageLoop::current()->RunAllPending(); 212 EXPECT_EQ(kTestData, delegate.data_received()); 213 } 214 215 TEST_F(UserScriptListenerTest, NoDelayNoExtension) { 216 TestDelegate delegate; 217 scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate, kMatchingUrl)); 218 219 // The request should be started immediately. 220 ASSERT_TRUE(request->is_pending()); 221 222 MessageLoop::current()->RunAllPending(); 223 EXPECT_EQ(kTestData, delegate.data_received()); 224 } 225 226 TEST_F(UserScriptListenerTest, NoDelayNotMatching) { 227 LoadTestExtension(); 228 MessageLoop::current()->RunAllPending(); 229 230 TestDelegate delegate; 231 scoped_ptr<TestURLRequest> request(StartTestRequest(&delegate, 232 kNotMatchingUrl)); 233 234 // The request should be started immediately. 235 ASSERT_TRUE(request->is_pending()); 236 237 MessageLoop::current()->RunAllPending(); 238 EXPECT_EQ(kTestData, delegate.data_received()); 239 } 240 241 } // namespace 242