| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/files/file_path.h" | 5 #include "base/files/file_path.h" |
| 6 #include "base/scoped_observer.h" | 6 #include "base/scoped_observer.h" |
| 7 #include "base/strings/string_number_conversions.h" | 7 #include "base/strings/string_number_conversions.h" |
| 8 #include "base/strings/string_util.h" |
| 8 #include "base/strings/stringprintf.h" | 9 #include "base/strings/stringprintf.h" |
| 9 #include "chrome/browser/extensions/activity_log/activity_actions.h" | 10 #include "chrome/browser/extensions/activity_log/activity_actions.h" |
| 10 #include "chrome/browser/extensions/activity_log/activity_log.h" | 11 #include "chrome/browser/extensions/activity_log/activity_log.h" |
| 11 #include "chrome/browser/extensions/activity_log/ad_network_database.h" | 12 #include "chrome/browser/extensions/activity_log/ad_network_database.h" |
| 12 #include "chrome/browser/extensions/extension_browsertest.h" | 13 #include "chrome/browser/extensions/extension_browsertest.h" |
| 13 #include "chrome/browser/extensions/extension_test_message_listener.h" | 14 #include "chrome/browser/extensions/extension_test_message_listener.h" |
| 14 #include "chrome/test/base/ui_test_utils.h" | 15 #include "chrome/test/base/ui_test_utils.h" |
| 15 #include "extensions/common/extension.h" | 16 #include "extensions/common/extension.h" |
| 16 #include "net/test/embedded_test_server/embedded_test_server.h" | 17 #include "net/test/embedded_test_server/embedded_test_server.h" |
| 17 #include "net/test/embedded_test_server/http_response.h" | 18 #include "net/test/embedded_test_server/http_response.h" |
| 18 #include "url/gurl.h" | 19 #include "url/gurl.h" |
| 19 | 20 |
| 20 namespace net { | 21 namespace net { |
| 21 namespace test_server { | 22 namespace test_server { |
| 22 struct HttpRequest; | 23 struct HttpRequest; |
| 23 } | 24 } |
| 24 } | 25 } |
| 25 | 26 |
| 26 namespace extensions { | 27 namespace extensions { |
| 27 | 28 |
| 28 namespace { | 29 namespace { |
| 29 | 30 |
| 30 // The "ad network" that we are using. Any src or href equal to this should be | 31 // The "ad network" that we are using. Any src or href equal to this should be |
| 31 // considered an ad network. | 32 // considered an ad network. |
| 32 const char kAdNetwork[] = "http://www.known-ads.adnetwork"; | 33 const char kAdNetwork1[] = "http://www.known-ads.adnetwork"; |
| 34 const char kAdNetwork2[] = "http://www.also-known-ads.adnetwork"; |
| 33 | 35 |
| 34 // The current stage of the test. | 36 // The current stage of the test. |
| 35 enum Stage { | 37 enum Stage { |
| 36 BEFORE_RESET, // We are about to reset the page. | 38 BEFORE_RESET, // We are about to reset the page. |
| 37 RESETTING, // We are resetting the page. | 39 RESETTING, // We are resetting the page. |
| 38 TESTING // The reset is complete, and we are testing. | 40 TESTING // The reset is complete, and we are testing. |
| 39 }; | 41 }; |
| 40 | 42 |
| 41 // The string sent by the test to indicate that the page reset will begin. | 43 // The string sent by the test to indicate that the page reset will begin. |
| 42 const char kResetBeginString[] = "Page Reset Begin"; | 44 const char kResetBeginString[] = "Page Reset Begin"; |
| 43 // The string sent by the test to indicate that page reset is complete. | 45 // The string sent by the test to indicate that page reset is complete. |
| 44 const char kResetEndString[] = "Page Reset End"; | 46 const char kResetEndString[] = "Page Reset End"; |
| 45 // The string sent by the test to indicate a JS error was caught in the test. | 47 // The string sent by the test to indicate a JS error was caught in the test. |
| 46 const char kJavascriptErrorString[] = "Testing Error"; | 48 const char kJavascriptErrorString[] = "Testing Error"; |
| 47 // The string sent by the test to indicate that we have concluded the full test. | 49 // The string sent by the test to indicate that we have concluded the full test. |
| 48 const char kTestCompleteString[] = "Test Complete"; | 50 const char kTestCompleteString[] = "Test Complete"; |
| 49 | 51 |
| 52 std::string InjectionTypeToString(Action::InjectionType type) { |
| 53 switch (type) { |
| 54 case Action::NO_AD_INJECTION: |
| 55 return "No Ad Injection"; |
| 56 case Action::INJECTION_NEW_AD: |
| 57 return "Injection New Ad"; |
| 58 case Action::INJECTION_REMOVED_AD: |
| 59 return "Injection Removed Ad"; |
| 60 case Action::INJECTION_REPLACED_AD: |
| 61 return "Injection Replaced Ad"; |
| 62 case Action::INJECTION_LIKELY_NEW_AD: |
| 63 return "Injection Likely New Ad"; |
| 64 case Action::INJECTION_LIKELY_REPLACED_AD: |
| 65 return "Injection Likely Replaced Ad"; |
| 66 case Action::NUM_INJECTION_TYPES: |
| 67 return "Num Injection Types"; |
| 68 } |
| 69 return std::string(); |
| 70 } |
| 71 |
| 50 // An implementation of ActivityLog::Observer that, for every action, sends it | 72 // An implementation of ActivityLog::Observer that, for every action, sends it |
| 51 // through Action::DidInjectAd(). This will keep track of the observed | 73 // through Action::DidInjectAd(). This will keep track of the observed |
| 52 // injections, and can be enabled or disabled as needed (for instance, this | 74 // injections, and can be enabled or disabled as needed (for instance, this |
| 53 // should be disabled while we are resetting the page). | 75 // should be disabled while we are resetting the page). |
| 54 class ActivityLogObserver : public ActivityLog::Observer { | 76 class ActivityLogObserver : public ActivityLog::Observer { |
| 55 public: | 77 public: |
| 56 explicit ActivityLogObserver(content::BrowserContext* context); | 78 explicit ActivityLogObserver(content::BrowserContext* context); |
| 57 virtual ~ActivityLogObserver(); | 79 virtual ~ActivityLogObserver(); |
| 58 | 80 |
| 59 void set_enabled(bool enabled) { enabled_ = enabled; } | 81 // Disable the observer (e.g., to reset the page). |
| 60 size_t injection_count() const { return injection_count_; } | 82 void disable() { enabled_ = false; } |
| 83 |
| 84 // Enable the observer, resetting the state. |
| 85 void enable() { |
| 86 injection_type_ = Action::NO_AD_INJECTION; |
| 87 found_multiple_injections_ = false; |
| 88 enabled_ = true; |
| 89 } |
| 90 |
| 91 Action::InjectionType injection_type() const { return injection_type_; } |
| 92 |
| 93 bool found_multiple_injections() const { return found_multiple_injections_; } |
| 61 | 94 |
| 62 private: | 95 private: |
| 63 virtual void OnExtensionActivity(scoped_refptr<Action> action) OVERRIDE; | 96 virtual void OnExtensionActivity(scoped_refptr<Action> action) OVERRIDE; |
| 64 | 97 |
| 65 ScopedObserver<ActivityLog, ActivityLog::Observer> scoped_observer_; | 98 ScopedObserver<ActivityLog, ActivityLog::Observer> scoped_observer_; |
| 99 |
| 100 // The associated BrowserContext. |
| 66 content::BrowserContext* context_; | 101 content::BrowserContext* context_; |
| 67 size_t injection_count_; | 102 |
| 103 // The type of the last injection. |
| 104 Action::InjectionType injection_type_; |
| 105 |
| 106 // Whether or not we found multiple injection types (which shouldn't happen). |
| 107 bool found_multiple_injections_; |
| 108 |
| 109 // Whether or not the observer is enabled. |
| 68 bool enabled_; | 110 bool enabled_; |
| 69 }; | 111 }; |
| 70 | 112 |
| 71 ActivityLogObserver::ActivityLogObserver(content::BrowserContext* context) | 113 ActivityLogObserver::ActivityLogObserver(content::BrowserContext* context) |
| 72 : scoped_observer_(this), | 114 : scoped_observer_(this), |
| 73 context_(context), | 115 context_(context), |
| 74 injection_count_(0u), | 116 injection_type_(Action::NO_AD_INJECTION), |
| 117 found_multiple_injections_(false), |
| 75 enabled_(false) { | 118 enabled_(false) { |
| 76 ActivityLog::GetInstance(context_)->AddObserver(this); | 119 ActivityLog::GetInstance(context_)->AddObserver(this); |
| 77 } | 120 } |
| 78 | 121 |
| 79 ActivityLogObserver::~ActivityLogObserver() {} | 122 ActivityLogObserver::~ActivityLogObserver() {} |
| 80 | 123 |
| 81 void ActivityLogObserver::OnExtensionActivity(scoped_refptr<Action> action) { | 124 void ActivityLogObserver::OnExtensionActivity(scoped_refptr<Action> action) { |
| 82 if (enabled_ && action->DidInjectAd(NULL /* no rappor service */) != | 125 if (!enabled_) |
| 83 Action::NO_AD_INJECTION) { | 126 return; |
| 84 ++injection_count_; | 127 |
| 128 Action::InjectionType type = |
| 129 action->DidInjectAd(NULL /* no rappor service */); |
| 130 if (type != Action::NO_AD_INJECTION) { |
| 131 if (injection_type_ != Action::NO_AD_INJECTION) |
| 132 found_multiple_injections_ = true; |
| 133 injection_type_ = type; |
| 85 } | 134 } |
| 86 } | 135 } |
| 87 | 136 |
| 88 // A mock for the AdNetworkDatabase. This simply says that the URL | 137 // A mock for the AdNetworkDatabase. This simply says that the URL |
| 89 // http://www.known-ads.adnetwork is an ad network, and nothing else is. | 138 // http://www.known-ads.adnetwork is an ad network, and nothing else is. |
| 90 class TestAdNetworkDatabase : public AdNetworkDatabase { | 139 class TestAdNetworkDatabase : public AdNetworkDatabase { |
| 91 public: | 140 public: |
| 92 TestAdNetworkDatabase(); | 141 TestAdNetworkDatabase(); |
| 93 virtual ~TestAdNetworkDatabase(); | 142 virtual ~TestAdNetworkDatabase(); |
| 94 | 143 |
| 95 private: | 144 private: |
| 96 virtual bool IsAdNetwork(const GURL& url) const OVERRIDE; | 145 virtual bool IsAdNetwork(const GURL& url) const OVERRIDE; |
| 97 | 146 |
| 98 GURL ad_network_url_; | 147 GURL ad_network_url1_; |
| 148 GURL ad_network_url2_; |
| 99 }; | 149 }; |
| 100 | 150 |
| 101 TestAdNetworkDatabase::TestAdNetworkDatabase() : ad_network_url_(kAdNetwork) {} | 151 TestAdNetworkDatabase::TestAdNetworkDatabase() : ad_network_url1_(kAdNetwork1), |
| 152 ad_network_url2_(kAdNetwork2) { |
| 153 } |
| 154 |
| 102 TestAdNetworkDatabase::~TestAdNetworkDatabase() {} | 155 TestAdNetworkDatabase::~TestAdNetworkDatabase() {} |
| 103 | 156 |
| 104 bool TestAdNetworkDatabase::IsAdNetwork(const GURL& url) const { | 157 bool TestAdNetworkDatabase::IsAdNetwork(const GURL& url) const { |
| 105 return url == ad_network_url_; | 158 return url == ad_network_url1_ || url == ad_network_url2_; |
| 106 } | 159 } |
| 107 | 160 |
| 108 scoped_ptr<net::test_server::HttpResponse> HandleRequest( | 161 scoped_ptr<net::test_server::HttpResponse> HandleRequest( |
| 109 const net::test_server::HttpRequest& request) { | 162 const net::test_server::HttpRequest& request) { |
| 110 scoped_ptr<net::test_server::BasicHttpResponse> response( | 163 scoped_ptr<net::test_server::BasicHttpResponse> response( |
| 111 new net::test_server::BasicHttpResponse()); | 164 new net::test_server::BasicHttpResponse()); |
| 112 response->set_code(net::HTTP_OK); | 165 response->set_code(net::HTTP_OK); |
| 113 return response.PassAs<net::test_server::HttpResponse>(); | 166 return response.PassAs<net::test_server::HttpResponse>(); |
| 114 } | 167 } |
| 115 | 168 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 134 | 187 |
| 135 // Handle a JS error encountered in a test. | 188 // Handle a JS error encountered in a test. |
| 136 testing::AssertionResult HandleJSError(const std::string& message); | 189 testing::AssertionResult HandleJSError(const std::string& message); |
| 137 | 190 |
| 138 const base::FilePath& test_data_dir() { return test_data_dir_; } | 191 const base::FilePath& test_data_dir() { return test_data_dir_; } |
| 139 | 192 |
| 140 ExtensionTestMessageListener* listener() { return listener_.get(); } | 193 ExtensionTestMessageListener* listener() { return listener_.get(); } |
| 141 | 194 |
| 142 ActivityLogObserver* observer() { return observer_.get(); } | 195 ActivityLogObserver* observer() { return observer_.get(); } |
| 143 | 196 |
| 144 void set_expected_injections(size_t expected_injections) { | |
| 145 expected_injections_ = expected_injections; | |
| 146 } | |
| 147 | |
| 148 private: | 197 private: |
| 149 // The name of the last completed test; used in case of unexpected failure for | 198 // The name of the last completed test; used in case of unexpected failure for |
| 150 // debugging. | 199 // debugging. |
| 151 std::string last_test_; | 200 std::string last_test_; |
| 152 | 201 |
| 153 // The number of expected injections. | |
| 154 size_t expected_injections_; | |
| 155 | |
| 156 // A listener for any messages from our ad-injecting extension. | 202 // A listener for any messages from our ad-injecting extension. |
| 157 scoped_ptr<ExtensionTestMessageListener> listener_; | 203 scoped_ptr<ExtensionTestMessageListener> listener_; |
| 158 | 204 |
| 159 // An observer to be alerted when we detect ad injection. | 205 // An observer to be alerted when we detect ad injection. |
| 160 scoped_ptr<ActivityLogObserver> observer_; | 206 scoped_ptr<ActivityLogObserver> observer_; |
| 161 | 207 |
| 162 // The current stage of the test. | 208 // The current stage of the test. |
| 163 Stage stage_; | 209 Stage stage_; |
| 164 }; | 210 }; |
| 165 | 211 |
| 166 AdInjectionBrowserTest::AdInjectionBrowserTest() | 212 AdInjectionBrowserTest::AdInjectionBrowserTest() : stage_(BEFORE_RESET) { |
| 167 : expected_injections_(0u), stage_(BEFORE_RESET) {} | 213 } |
| 168 | 214 |
| 169 AdInjectionBrowserTest::~AdInjectionBrowserTest() {} | 215 AdInjectionBrowserTest::~AdInjectionBrowserTest() { |
| 216 } |
| 170 | 217 |
| 171 void AdInjectionBrowserTest::SetUpOnMainThread() { | 218 void AdInjectionBrowserTest::SetUpOnMainThread() { |
| 172 ExtensionBrowserTest::SetUpOnMainThread(); | 219 ExtensionBrowserTest::SetUpOnMainThread(); |
| 173 | 220 |
| 174 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | 221 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 175 embedded_test_server()->RegisterRequestHandler(base::Bind(&HandleRequest)); | 222 embedded_test_server()->RegisterRequestHandler(base::Bind(&HandleRequest)); |
| 176 | 223 |
| 177 test_data_dir_ = | 224 test_data_dir_ = |
| 178 test_data_dir_.AppendASCII("activity_log").AppendASCII("ad_injection"); | 225 test_data_dir_.AppendASCII("activity_log").AppendASCII("ad_injection"); |
| 179 observer_.reset(new ActivityLogObserver(profile())); | 226 observer_.reset(new ActivityLogObserver(profile())); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 201 } | 248 } |
| 202 | 249 |
| 203 testing::AssertionResult AdInjectionBrowserTest::HandleResetBeginStage() { | 250 testing::AssertionResult AdInjectionBrowserTest::HandleResetBeginStage() { |
| 204 if (stage_ != BEFORE_RESET) { | 251 if (stage_ != BEFORE_RESET) { |
| 205 return testing::AssertionFailure() | 252 return testing::AssertionFailure() |
| 206 << "In incorrect stage. Last Test: " << last_test_; | 253 << "In incorrect stage. Last Test: " << last_test_; |
| 207 } | 254 } |
| 208 | 255 |
| 209 // Stop looking for ad injection, since some of the reset could be considered | 256 // Stop looking for ad injection, since some of the reset could be considered |
| 210 // ad injection. | 257 // ad injection. |
| 211 observer()->set_enabled(false); | 258 observer()->disable(); |
| 212 stage_ = RESETTING; | 259 stage_ = RESETTING; |
| 213 return testing::AssertionSuccess(); | 260 return testing::AssertionSuccess(); |
| 214 } | 261 } |
| 215 | 262 |
| 216 testing::AssertionResult AdInjectionBrowserTest::HandleResetEndStage() { | 263 testing::AssertionResult AdInjectionBrowserTest::HandleResetEndStage() { |
| 217 if (stage_ != RESETTING) { | 264 if (stage_ != RESETTING) { |
| 218 return testing::AssertionFailure() | 265 return testing::AssertionFailure() |
| 219 << "In incorrect stage. Last test: " << last_test_; | 266 << "In incorrect stage. Last test: " << last_test_; |
| 220 } | 267 } |
| 221 | 268 |
| 222 // Look for ad injection again, now that the reset is over. | 269 // Look for ad injection again, now that the reset is over. |
| 223 observer()->set_enabled(true); | 270 observer()->enable(); |
| 224 stage_ = TESTING; | 271 stage_ = TESTING; |
| 225 return testing::AssertionSuccess(); | 272 return testing::AssertionSuccess(); |
| 226 } | 273 } |
| 227 | 274 |
| 228 testing::AssertionResult AdInjectionBrowserTest::HandleTestingStage( | 275 testing::AssertionResult AdInjectionBrowserTest::HandleTestingStage( |
| 229 const std::string& message) { | 276 const std::string& message) { |
| 230 if (stage_ != TESTING) { | 277 if (stage_ != TESTING) { |
| 231 return testing::AssertionFailure() | 278 return testing::AssertionFailure() |
| 232 << "In incorrect stage. Last test: " << last_test_; | 279 << "In incorrect stage. Last test: " << last_test_; |
| 233 } | 280 } |
| 234 | 281 |
| 235 // The format for a testing message is: | 282 // The format for a testing message is: |
| 236 // "<test_name>:<expected_change>" | 283 // "<test_name>:<expected_change>" |
| 237 // where <test_name> is the name of the test and <expected_change> is | 284 // where <test_name> is the name of the test and <expected_change> is |
| 238 // either -1 for no ad injection (to test against false positives) or the | 285 // either -1 for no ad injection (to test against false positives) or the |
| 239 // number corresponding to ad_detection::InjectionType. | 286 // number corresponding to ad_detection::InjectionType. |
| 240 size_t sep = message.find(':'); | 287 size_t sep = message.find(':'); |
| 241 int expected_change = -1; | 288 int expected_change = -1; |
| 242 if (sep == std::string::npos || | 289 if (sep == std::string::npos || |
| 243 !base::StringToInt(message.substr(sep + 1), &expected_change) || | 290 !base::StringToInt(message.substr(sep + 1), &expected_change) || |
| 244 (expected_change < Action::NO_AD_INJECTION || | 291 (expected_change < Action::NO_AD_INJECTION || |
| 245 expected_change >= Action::NUM_INJECTION_TYPES)) { | 292 expected_change >= Action::NUM_INJECTION_TYPES)) { |
| 246 return testing::AssertionFailure() | 293 return testing::AssertionFailure() |
| 247 << "Invalid message received for testing stage: " << message; | 294 << "Invalid message received for testing stage: " << message; |
| 248 } | 295 } |
| 249 | 296 |
| 250 last_test_ = message.substr(0, sep); | 297 last_test_ = message.substr(0, sep); |
| 251 | 298 |
| 252 // TODO(rdevlin.cronin): Currently, we lump all kinds of ad injection into | 299 Action::InjectionType expected_injection = |
| 253 // one counter, because we can't differentiate (or catch all of them). Change | 300 static_cast<Action::InjectionType>(expected_change); |
| 254 // this when we can. | |
| 255 // Increment the expected change, and compare. | |
| 256 if (expected_change != Action::NO_AD_INJECTION) | |
| 257 ++expected_injections_; | |
| 258 std::string error; | 301 std::string error; |
| 259 if (expected_injections_ != observer()->injection_count()) { | 302 if (observer()->found_multiple_injections()) { |
| 303 error = "Found multiple injection types. " |
| 304 "Only one injection is expected per test."; |
| 305 } else if (expected_injection != observer()->injection_type()) { |
| 260 // We need these static casts, because size_t is different on different | 306 // We need these static casts, because size_t is different on different |
| 261 // architectures, and printf becomes unhappy. | 307 // architectures, and printf becomes unhappy. |
| 262 error = | 308 error = base::StringPrintf( |
| 263 base::StringPrintf("Injection Count Mismatch: Expected %u, Actual %u", | 309 "Incorrect Injection Found: Expected: %s, Actual: %s", |
| 264 static_cast<unsigned int>(expected_injections_), | 310 InjectionTypeToString(expected_injection).c_str(), |
| 265 static_cast<unsigned int>( | 311 InjectionTypeToString(observer()->injection_type()).c_str()); |
| 266 observer()->injection_count())); | |
| 267 } | 312 } |
| 268 | 313 |
| 269 stage_ = BEFORE_RESET; | 314 stage_ = BEFORE_RESET; |
| 270 | 315 |
| 271 if (!error.empty()) | 316 if (!error.empty()) { |
| 272 return testing::AssertionFailure() << error; | 317 return testing::AssertionFailure() |
| 318 << "Error in Test '" << last_test_ << "': " << error; |
| 319 } |
| 273 | 320 |
| 274 return testing::AssertionSuccess(); | 321 return testing::AssertionSuccess(); |
| 275 } | 322 } |
| 276 | 323 |
| 277 testing::AssertionResult AdInjectionBrowserTest::HandleJSError( | 324 testing::AssertionResult AdInjectionBrowserTest::HandleJSError( |
| 278 const std::string& message) { | 325 const std::string& message) { |
| 279 // The format for a testing message is: | 326 // The format for a testing message is: |
| 280 // "Testing Error:<test_name>:<error>" | 327 // "Testing Error:<test_name>:<error>" |
| 281 // where <test_name> is the name of the test and <error> is the error which | 328 // where <test_name> is the name of the test and <error> is the error which |
| 282 // was encountered. | 329 // was encountered. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 ASSERT_TRUE(HandleResetEndStage()); | 368 ASSERT_TRUE(HandleResetEndStage()); |
| 322 } else if (!message.compare( | 369 } else if (!message.compare( |
| 323 0, strlen(kJavascriptErrorString), kJavascriptErrorString)) { | 370 0, strlen(kJavascriptErrorString), kJavascriptErrorString)) { |
| 324 EXPECT_TRUE(HandleJSError(message)); | 371 EXPECT_TRUE(HandleJSError(message)); |
| 325 } else if (message == kTestCompleteString) { | 372 } else if (message == kTestCompleteString) { |
| 326 break; // We're done! | 373 break; // We're done! |
| 327 } else { // We're in some kind of test. | 374 } else { // We're in some kind of test. |
| 328 EXPECT_TRUE(HandleTestingStage(message)); | 375 EXPECT_TRUE(HandleTestingStage(message)); |
| 329 } | 376 } |
| 330 | 377 |
| 331 // We set the expected injections to be whatever they actually are so that | |
| 332 // we only fail one test, instead of all subsequent tests. | |
| 333 set_expected_injections(observer()->injection_count()); | |
| 334 | |
| 335 // In all cases (except for "Test Complete", in which case we already | 378 // In all cases (except for "Test Complete", in which case we already |
| 336 // break'ed), we reply with a continue message. | 379 // break'ed), we reply with a continue message. |
| 337 listener()->Reply("Continue"); | 380 listener()->Reply("Continue"); |
| 338 listener()->Reset(); | 381 listener()->Reset(); |
| 339 } | 382 } |
| 340 } | 383 } |
| 341 | 384 |
| 342 // TODO(rdevlin.cronin): We test a good amount of ways of injecting ads with | 385 // TODO(rdevlin.cronin): We test a good amount of ways of injecting ads with |
| 343 // the above test, but more is better in testing. | 386 // the above test, but more is better in testing. |
| 344 // See crbug.com/357204. | 387 // See crbug.com/357204. |
| 345 | 388 |
| 346 } // namespace extensions | 389 } // namespace extensions |
| OLD | NEW |