1// Copyright (c) 2013 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 <algorithm>
6#include <vector>
7
8#include "base/command_line.h"
9#include "base/compiler_specific.h"
10#include "base/logging.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/metrics/histogram_base.h"
13#include "base/metrics/histogram_samples.h"
14#include "base/metrics/statistics_recorder.h"
15#include "base/run_loop.h"
16#include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
17#include "chrome/browser/chromeos/net/network_portal_detector_test_utils.h"
18#include "chrome/test/base/testing_profile.h"
19#include "chromeos/chromeos_switches.h"
20#include "chromeos/dbus/dbus_thread_manager.h"
21#include "chromeos/dbus/shill_device_client.h"
22#include "chromeos/dbus/shill_service_client.h"
23#include "chromeos/network/network_state.h"
24#include "chromeos/network/network_state_handler.h"
25#include "chromeos/network/portal_detector/network_portal_detector_strategy.h"
26#include "components/captive_portal/captive_portal_detector.h"
27#include "components/captive_portal/captive_portal_testing_utils.h"
28#include "content/public/test/test_browser_thread_bundle.h"
29#include "dbus/object_path.h"
30#include "net/base/net_errors.h"
31#include "testing/gmock/include/gmock/gmock.h"
32#include "testing/gtest/include/gtest/gtest.h"
33#include "third_party/cros_system_api/dbus/service_constants.h"
34
35using testing::AnyNumber;
36using testing::Mock;
37using testing::_;
38
39namespace chromeos {
40
41namespace {
42
43// Service path / guid for stub networks.
44const char kStubEthernet[] = "stub_ethernet";
45const char kStubWireless1[] = "stub_wifi1";
46const char kStubWireless2[] = "stub_wifi2";
47const char kStubCellular[] = "stub_cellular";
48
49void ErrorCallbackFunction(const std::string& error_name,
50                           const std::string& error_message) {
51  LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
52}
53
54class MockObserver : public NetworkPortalDetector::Observer {
55 public:
56  virtual ~MockObserver() {}
57
58  MOCK_METHOD2(OnPortalDetectionCompleted,
59               void(const NetworkState* network,
60                    const NetworkPortalDetector::CaptivePortalState& state));
61};
62
63}  // namespace
64
65class NetworkPortalDetectorImplTest
66    : public testing::Test,
67      public captive_portal::CaptivePortalDetectorTestBase {
68 protected:
69  virtual void SetUp() {
70    CommandLine* cl = CommandLine::ForCurrentProcess();
71    cl->AppendSwitch(switches::kDisableNetworkPortalNotification);
72
73    DBusThreadManager::Initialize();
74    base::StatisticsRecorder::Initialize();
75    SetupNetworkHandler();
76
77    profile_.reset(new TestingProfile());
78    network_portal_detector_.reset(
79        new NetworkPortalDetectorImpl(profile_->GetRequestContext()));
80    network_portal_detector_->Enable(false);
81
82    set_detector(network_portal_detector_->captive_portal_detector_.get());
83
84    // Prevents flakiness due to message loop delays.
85    set_time_ticks(base::TimeTicks::Now());
86
87    if (base::HistogramBase* histogram =
88            base::StatisticsRecorder::FindHistogram(
89                "CaptivePortal.OOBE.DetectionResult")) {
90      original_samples_.reset(histogram->SnapshotSamples().release());
91    }
92  }
93
94  virtual void TearDown() {
95    network_portal_detector_.reset();
96    profile_.reset();
97    NetworkHandler::Shutdown();
98    DBusThreadManager::Shutdown();
99    PortalDetectorStrategy::reset_fields_for_testing();
100  }
101
102  void CheckPortalState(NetworkPortalDetector::CaptivePortalStatus status,
103                        int response_code,
104                        const std::string& guid) {
105    NetworkPortalDetector::CaptivePortalState state =
106        network_portal_detector()->GetCaptivePortalState(guid);
107    ASSERT_EQ(status, state.status);
108    ASSERT_EQ(response_code, state.response_code);
109  }
110
111  void CheckRequestTimeoutAndCompleteAttempt(
112      int expected_same_detection_result_count,
113      int expected_no_response_result_count,
114      int expected_request_timeout_sec,
115      int net_error,
116      int status_code) {
117    ASSERT_TRUE(is_state_checking_for_portal());
118    ASSERT_EQ(expected_same_detection_result_count,
119              same_detection_result_count());
120    ASSERT_EQ(expected_no_response_result_count, no_response_result_count());
121    ASSERT_EQ(base::TimeDelta::FromSeconds(expected_request_timeout_sec),
122              get_next_attempt_timeout());
123    CompleteURLFetch(net_error, status_code, NULL);
124  }
125
126  Profile* profile() { return profile_.get(); }
127
128  NetworkPortalDetectorImpl* network_portal_detector() {
129    return network_portal_detector_.get();
130  }
131
132  NetworkPortalDetectorImpl::State state() {
133    return network_portal_detector()->state();
134  }
135
136  bool start_detection_if_idle() {
137    return network_portal_detector()->StartDetectionIfIdle();
138  }
139
140  void enable_error_screen_strategy() {
141    network_portal_detector()->SetStrategy(
142        PortalDetectorStrategy::STRATEGY_ID_ERROR_SCREEN);
143  }
144
145  void disable_error_screen_strategy() {
146    network_portal_detector()->SetStrategy(
147        PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN);
148  }
149
150  void stop_detection() { network_portal_detector()->StopDetection(); }
151
152  bool attempt_timeout_is_cancelled() {
153    return network_portal_detector()->AttemptTimeoutIsCancelledForTesting();
154  }
155
156  base::TimeDelta get_next_attempt_timeout() {
157    return network_portal_detector()->strategy_->GetNextAttemptTimeout();
158  }
159
160  void set_next_attempt_timeout(const base::TimeDelta& timeout) {
161    PortalDetectorStrategy::set_next_attempt_timeout_for_testing(timeout);
162  }
163
164  bool is_state_idle() {
165    return (NetworkPortalDetectorImpl::STATE_IDLE == state());
166  }
167
168  bool is_state_portal_detection_pending() {
169    return (NetworkPortalDetectorImpl::STATE_PORTAL_CHECK_PENDING == state());
170  }
171
172  bool is_state_checking_for_portal() {
173    return (NetworkPortalDetectorImpl::STATE_CHECKING_FOR_PORTAL == state());
174  }
175
176  const base::TimeDelta& next_attempt_delay() {
177    return network_portal_detector()->next_attempt_delay_for_testing();
178  }
179
180  int same_detection_result_count() {
181    return network_portal_detector()->same_detection_result_count_for_testing();
182  }
183
184  int no_response_result_count() {
185    return network_portal_detector()->no_response_result_count_for_testing();
186  }
187
188  void set_no_response_result_count(int count) {
189    network_portal_detector()->set_no_response_result_count_for_testing(count);
190  }
191
192  void set_delay_till_next_attempt(const base::TimeDelta& delta) {
193    PortalDetectorStrategy::set_delay_till_next_attempt_for_testing(delta);
194  }
195
196  void set_time_ticks(const base::TimeTicks& time_ticks) {
197    network_portal_detector()->set_time_ticks_for_testing(time_ticks);
198  }
199
200  void SetBehindPortal(const std::string& service_path) {
201    DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
202        dbus::ObjectPath(service_path),
203        shill::kStateProperty,
204        base::StringValue(shill::kStatePortal),
205        base::Bind(&base::DoNothing),
206        base::Bind(&ErrorCallbackFunction));
207    base::RunLoop().RunUntilIdle();
208  }
209
210  void SetNetworkDeviceEnabled(const std::string& type, bool enabled) {
211    NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled(
212        NetworkTypePattern::Primitive(type),
213        enabled,
214        network_handler::ErrorCallback());
215    base::RunLoop().RunUntilIdle();
216  }
217
218  void SetConnected(const std::string& service_path) {
219    DBusThreadManager::Get()->GetShillServiceClient()->Connect(
220        dbus::ObjectPath(service_path),
221        base::Bind(&base::DoNothing),
222        base::Bind(&ErrorCallbackFunction));
223    base::RunLoop().RunUntilIdle();
224  }
225
226  void SetDisconnected(const std::string& service_path) {
227    DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
228        dbus::ObjectPath(service_path),
229        base::Bind(&*base::DoNothing),
230        base::Bind(&ErrorCallbackFunction));
231    base::RunLoop().RunUntilIdle();
232  }
233
234  scoped_ptr<EnumHistogramChecker> MakeResultHistogramChecker() {
235    return scoped_ptr<EnumHistogramChecker>(
236               new EnumHistogramChecker(
237                   "CaptivePortal.OOBE.DetectionResult",
238                   NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT,
239                   original_samples_.get()));
240  }
241
242 private:
243  void AddService(const std::string& network_id,
244                  const std::string& type) {
245    DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
246        AddService(network_id /* service_path */,
247                   network_id /* guid */,
248                   network_id /* name */,
249                   type,
250                   shill::kStateIdle,
251                   true /* add_to_visible */);
252  }
253
254  void SetupDefaultShillState() {
255    base::RunLoop().RunUntilIdle();
256    DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
257        ClearServices();
258    AddService(kStubEthernet, shill::kTypeEthernet);
259    AddService(kStubWireless1, shill::kTypeWifi);
260    AddService(kStubWireless2, shill::kTypeWifi);
261    AddService(kStubCellular, shill::kTypeCellular);
262  }
263
264  void SetupNetworkHandler() {
265    SetupDefaultShillState();
266    NetworkHandler::Initialize();
267  }
268
269  content::TestBrowserThreadBundle thread_bundle_;
270  scoped_ptr<TestingProfile> profile_;
271  scoped_ptr<NetworkPortalDetectorImpl> network_portal_detector_;
272  scoped_ptr<base::HistogramSamples> original_samples_;
273};
274
275TEST_F(NetworkPortalDetectorImplTest, NoPortal) {
276  ASSERT_TRUE(is_state_idle());
277
278  SetConnected(kStubWireless1);
279
280  ASSERT_TRUE(is_state_checking_for_portal());
281  CheckPortalState(
282      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
283
284  CompleteURLFetch(net::OK, 204, NULL);
285
286  ASSERT_FALSE(is_state_idle());
287  CheckPortalState(
288      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
289  ASSERT_TRUE(
290      MakeResultHistogramChecker()
291          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
292          ->Check());
293}
294
295TEST_F(NetworkPortalDetectorImplTest, Portal) {
296  ASSERT_TRUE(is_state_idle());
297
298  // Check HTTP 200 response code.
299  SetConnected(kStubWireless1);
300  ASSERT_TRUE(is_state_checking_for_portal());
301
302  CompleteURLFetch(net::OK, 200, NULL);
303
304  ASSERT_FALSE(is_state_idle());
305  CheckPortalState(
306      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
307
308  // Check HTTP 301 response code.
309  SetConnected(kStubWireless2);
310  ASSERT_TRUE(is_state_checking_for_portal());
311
312  CompleteURLFetch(net::OK, 301, NULL);
313
314  ASSERT_FALSE(is_state_idle());
315  CheckPortalState(
316      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 301, kStubWireless2);
317
318  // Check HTTP 302 response code.
319  SetConnected(kStubEthernet);
320  ASSERT_TRUE(is_state_checking_for_portal());
321
322  CompleteURLFetch(net::OK, 302, NULL);
323
324  ASSERT_FALSE(is_state_idle());
325  CheckPortalState(
326      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 302, kStubEthernet);
327
328  ASSERT_TRUE(
329      MakeResultHistogramChecker()
330          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 3)
331          ->Check());
332}
333
334TEST_F(NetworkPortalDetectorImplTest, Online2Offline) {
335  ASSERT_TRUE(is_state_idle());
336
337  MockObserver observer;
338  network_portal_detector()->AddObserver(&observer);
339
340  NetworkPortalDetector::CaptivePortalState offline_state;
341  offline_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE;
342
343  // WiFi is in online state.
344  {
345    // When transitioning to a connected state, the network will transition to
346    // connecting states which will set the default network to NULL. This may
347    // get triggered multiple times.
348    EXPECT_CALL(observer, OnPortalDetectionCompleted(_, offline_state))
349        .Times(AnyNumber());
350
351    // Expect a single transition to an online state.
352    NetworkPortalDetector::CaptivePortalState online_state;
353    online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
354    online_state.response_code = 204;
355    EXPECT_CALL(observer, OnPortalDetectionCompleted(_, online_state)).Times(1);
356
357    SetConnected(kStubWireless1);
358    ASSERT_TRUE(is_state_checking_for_portal());
359
360    CompleteURLFetch(net::OK, 204, NULL);
361    ASSERT_FALSE(is_state_idle());
362
363    // Check that observer was notified about online state.
364    Mock::VerifyAndClearExpectations(&observer);
365  }
366
367  // WiFi is turned off.
368  {
369    EXPECT_CALL(observer, OnPortalDetectionCompleted(NULL, offline_state))
370        .Times(1);
371
372    SetDisconnected(kStubWireless1);
373    ASSERT_TRUE(is_state_idle());
374
375    // Check that observer was notified about offline state.
376    Mock::VerifyAndClearExpectations(&observer);
377  }
378
379  network_portal_detector()->RemoveObserver(&observer);
380
381  ASSERT_TRUE(
382      MakeResultHistogramChecker()
383          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
384          ->Check());
385}
386
387TEST_F(NetworkPortalDetectorImplTest, TwoNetworks) {
388  ASSERT_TRUE(is_state_idle());
389
390  SetConnected(kStubWireless1);
391  ASSERT_TRUE(is_state_checking_for_portal());
392
393  // WiFi is in portal state.
394  CompleteURLFetch(net::OK, 200, NULL);
395  ASSERT_FALSE(is_state_idle());
396
397  SetConnected(kStubEthernet);
398  ASSERT_TRUE(is_state_checking_for_portal());
399
400  // ethernet is in online state.
401  CompleteURLFetch(net::OK, 204, NULL);
402  ASSERT_FALSE(is_state_idle());
403  CheckPortalState(
404      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubEthernet);
405  CheckPortalState(
406      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
407
408  ASSERT_TRUE(
409      MakeResultHistogramChecker()
410          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
411          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
412          ->Check());
413}
414
415TEST_F(NetworkPortalDetectorImplTest, NetworkChanged) {
416  ASSERT_TRUE(is_state_idle());
417
418  SetConnected(kStubWireless1);
419
420  // WiFi is in portal state.
421  fetcher()->set_response_code(200);
422  ASSERT_TRUE(is_state_checking_for_portal());
423
424  // Active network is changed during portal detection for WiFi.
425  SetConnected(kStubEthernet);
426
427  // Portal detection for WiFi is cancelled, portal detection for
428  // ethernet is initiated.
429  ASSERT_TRUE(is_state_checking_for_portal());
430
431  // ethernet is in online state.
432  CompleteURLFetch(net::OK, 204, NULL);
433  ASSERT_FALSE(is_state_idle());
434  CheckPortalState(
435      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubEthernet);
436
437  // As active network was changed during portal detection for wifi
438  // network, it's state must be unknown.
439  CheckPortalState(
440      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
441
442  ASSERT_TRUE(
443      MakeResultHistogramChecker()
444          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
445          ->Check());
446}
447
448TEST_F(NetworkPortalDetectorImplTest, NetworkStateNotChanged) {
449  ASSERT_TRUE(is_state_idle());
450
451  SetConnected(kStubWireless1);
452  ASSERT_TRUE(is_state_checking_for_portal());
453
454  CompleteURLFetch(net::OK, 204, NULL);
455
456  ASSERT_FALSE(is_state_idle());
457  CheckPortalState(
458      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
459
460  SetConnected(kStubWireless1);
461  ASSERT_TRUE(is_state_idle());
462
463  ASSERT_TRUE(
464      MakeResultHistogramChecker()
465          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
466          ->Check());
467}
468
469TEST_F(NetworkPortalDetectorImplTest, NetworkStateChanged) {
470  // Test for Portal -> Online -> Portal network state transitions.
471  ASSERT_TRUE(is_state_idle());
472
473  SetBehindPortal(kStubWireless1);
474  ASSERT_TRUE(is_state_checking_for_portal());
475
476  CompleteURLFetch(net::OK, 200, NULL);
477
478  ASSERT_FALSE(is_state_idle());
479  CheckPortalState(
480      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
481
482  SetConnected(kStubWireless1);
483  ASSERT_TRUE(is_state_checking_for_portal());
484
485  CompleteURLFetch(net::OK, 204, NULL);
486
487  ASSERT_FALSE(is_state_idle());
488  CheckPortalState(
489      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
490
491  SetBehindPortal(kStubWireless1);
492  ASSERT_TRUE(is_state_checking_for_portal());
493
494  CompleteURLFetch(net::OK, 200, NULL);
495
496  ASSERT_FALSE(is_state_idle());
497  CheckPortalState(
498      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
499
500  ASSERT_TRUE(
501      MakeResultHistogramChecker()
502          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
503          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 2)
504          ->Check());
505}
506
507TEST_F(NetworkPortalDetectorImplTest, PortalDetectionTimeout) {
508  ASSERT_TRUE(is_state_idle());
509
510  // For instantaneous timeout.
511  set_next_attempt_timeout(base::TimeDelta::FromSeconds(0));
512
513  ASSERT_TRUE(is_state_idle());
514  ASSERT_EQ(0, same_detection_result_count());
515  ASSERT_EQ(0, no_response_result_count());
516
517  SetConnected(kStubWireless1);
518  base::RunLoop().RunUntilIdle();
519
520  // First portal detection timeouts, next portal detection is
521  // scheduled.
522  ASSERT_TRUE(is_state_portal_detection_pending());
523  ASSERT_EQ(1, no_response_result_count());
524
525  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
526}
527
528TEST_F(NetworkPortalDetectorImplTest, PortalDetectionRetryAfter) {
529  ASSERT_TRUE(is_state_idle());
530
531  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
532
533  ASSERT_TRUE(is_state_idle());
534  ASSERT_EQ(0, no_response_result_count());
535
536  SetConnected(kStubWireless1);
537  ASSERT_TRUE(is_state_checking_for_portal());
538  CompleteURLFetch(net::OK, 503, retry_after);
539
540  // First portal detection completed, next portal detection is
541  // scheduled after 101 seconds.
542  ASSERT_TRUE(is_state_portal_detection_pending());
543  ASSERT_EQ(1, no_response_result_count());
544  ASSERT_EQ(base::TimeDelta::FromSeconds(101), next_attempt_delay());
545
546  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
547}
548
549TEST_F(NetworkPortalDetectorImplTest, PortalDetectorRetryAfterIsSmall) {
550  ASSERT_TRUE(is_state_idle());
551
552  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 1\n\n";
553
554  ASSERT_TRUE(is_state_idle());
555  ASSERT_EQ(0, no_response_result_count());
556
557  SetConnected(kStubWireless1);
558  CompleteURLFetch(net::OK, 503, retry_after);
559
560  // First portal detection completed, next portal detection is
561  // scheduled after 3 seconds (due to minimum time between detection
562  // attemps).
563  ASSERT_TRUE(is_state_portal_detection_pending());
564  ASSERT_EQ(1, no_response_result_count());
565
566  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
567}
568
569TEST_F(NetworkPortalDetectorImplTest, FirstAttemptFailed) {
570  ASSERT_TRUE(is_state_idle());
571
572  set_delay_till_next_attempt(base::TimeDelta());
573  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 0\n\n";
574
575  ASSERT_TRUE(is_state_idle());
576  ASSERT_EQ(0, no_response_result_count());
577
578  SetConnected(kStubWireless1);
579
580  CompleteURLFetch(net::OK, 503, retry_after);
581  ASSERT_TRUE(is_state_portal_detection_pending());
582  ASSERT_EQ(1, no_response_result_count());
583  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
584
585  // To run CaptivePortalDetector::DetectCaptivePortal().
586  base::RunLoop().RunUntilIdle();
587
588  CompleteURLFetch(net::OK, 204, NULL);
589  ASSERT_FALSE(is_state_idle());
590  ASSERT_EQ(0, no_response_result_count());
591  CheckPortalState(
592      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
593
594  ASSERT_TRUE(
595      MakeResultHistogramChecker()
596          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
597          ->Check());
598}
599
600TEST_F(NetworkPortalDetectorImplTest, AllAttemptsFailed) {
601  ASSERT_TRUE(is_state_idle());
602
603  set_delay_till_next_attempt(base::TimeDelta());
604  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 0\n\n";
605
606  ASSERT_TRUE(is_state_idle());
607  ASSERT_EQ(0, no_response_result_count());
608
609  SetConnected(kStubWireless1);
610
611  CompleteURLFetch(net::OK, 503, retry_after);
612  ASSERT_TRUE(is_state_portal_detection_pending());
613  ASSERT_EQ(1, no_response_result_count());
614  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
615
616  // To run CaptivePortalDetector::DetectCaptivePortal().
617  base::RunLoop().RunUntilIdle();
618
619  CompleteURLFetch(net::OK, 503, retry_after);
620  ASSERT_TRUE(is_state_portal_detection_pending());
621  ASSERT_EQ(2, no_response_result_count());
622  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
623
624  // To run CaptivePortalDetector::DetectCaptivePortal().
625  base::RunLoop().RunUntilIdle();
626
627  CompleteURLFetch(net::OK, 503, retry_after);
628  ASSERT_FALSE(is_state_idle());
629  ASSERT_EQ(3, no_response_result_count());
630  CheckPortalState(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE,
631                   503,
632                   kStubWireless1);
633
634  ASSERT_TRUE(
635      MakeResultHistogramChecker()
636          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
637          ->Check());
638}
639
640TEST_F(NetworkPortalDetectorImplTest, ProxyAuthRequired) {
641  ASSERT_TRUE(is_state_idle());
642  set_delay_till_next_attempt(base::TimeDelta());
643
644  SetConnected(kStubWireless1);
645  CompleteURLFetch(net::OK, 407, NULL);
646  ASSERT_EQ(1, no_response_result_count());
647  ASSERT_TRUE(is_state_portal_detection_pending());
648
649  base::RunLoop().RunUntilIdle();
650  CompleteURLFetch(net::OK, 407, NULL);
651  ASSERT_EQ(2, no_response_result_count());
652  ASSERT_TRUE(is_state_portal_detection_pending());
653
654  base::RunLoop().RunUntilIdle();
655  CompleteURLFetch(net::OK, 407, NULL);
656  ASSERT_EQ(3, no_response_result_count());
657  ASSERT_FALSE(is_state_idle());
658
659  CheckPortalState(
660      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED,
661      407,
662      kStubWireless1);
663
664  ASSERT_TRUE(MakeResultHistogramChecker()
665                  ->Expect(NetworkPortalDetector::
666                               CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED,
667                           1)
668                  ->Check());
669}
670
671TEST_F(NetworkPortalDetectorImplTest, NoResponseButBehindPortal) {
672  ASSERT_TRUE(is_state_idle());
673  set_delay_till_next_attempt(base::TimeDelta());
674
675  SetBehindPortal(kStubWireless1);
676  ASSERT_TRUE(is_state_checking_for_portal());
677
678  CompleteURLFetch(
679      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
680  ASSERT_EQ(1, no_response_result_count());
681  ASSERT_TRUE(is_state_portal_detection_pending());
682
683  // To run CaptivePortalDetector::DetectCaptivePortal().
684  base::RunLoop().RunUntilIdle();
685
686  CompleteURLFetch(
687      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
688  ASSERT_EQ(2, no_response_result_count());
689  ASSERT_TRUE(is_state_portal_detection_pending());
690
691  // To run CaptivePortalDetector::DetectCaptivePortal().
692  base::RunLoop().RunUntilIdle();
693
694  CompleteURLFetch(
695      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
696  ASSERT_EQ(3, no_response_result_count());
697  ASSERT_FALSE(is_state_idle());
698
699  CheckPortalState(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL,
700                   net::URLFetcher::RESPONSE_CODE_INVALID,
701                   kStubWireless1);
702
703  ASSERT_TRUE(
704      MakeResultHistogramChecker()
705          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
706          ->Check());
707}
708
709TEST_F(NetworkPortalDetectorImplTest,
710       DisableErrorScreenStrategyWhilePendingRequest) {
711  ASSERT_TRUE(is_state_idle());
712  set_no_response_result_count(3);
713  enable_error_screen_strategy();
714  ASSERT_TRUE(is_state_portal_detection_pending());
715  disable_error_screen_strategy();
716
717  // To run CaptivePortalDetector::DetectCaptivePortal().
718  base::MessageLoop::current()->RunUntilIdle();
719
720  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
721}
722
723TEST_F(NetworkPortalDetectorImplTest, ErrorScreenStrategyForOnlineNetwork) {
724  ASSERT_TRUE(is_state_idle());
725  set_delay_till_next_attempt(base::TimeDelta());
726
727  SetConnected(kStubWireless1);
728  enable_error_screen_strategy();
729  // To run CaptivePortalDetector::DetectCaptivePortal().
730  base::RunLoop().RunUntilIdle();
731  CompleteURLFetch(net::OK, 204, NULL);
732
733  ASSERT_TRUE(is_state_portal_detection_pending());
734  CheckPortalState(
735      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
736
737  // To run CaptivePortalDetector::DetectCaptivePortal().
738  base::RunLoop().RunUntilIdle();
739
740  CompleteURLFetch(net::OK, 204, NULL);
741
742  ASSERT_TRUE(is_state_portal_detection_pending());
743  CheckPortalState(
744      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
745
746  // To run CaptivePortalDetector::DetectCaptivePortal().
747  base::RunLoop().RunUntilIdle();
748
749  disable_error_screen_strategy();
750
751  ASSERT_TRUE(is_state_portal_detection_pending());
752  // To run CaptivePortalDetector::DetectCaptivePortal().
753  base::RunLoop().RunUntilIdle();
754  ASSERT_TRUE(is_state_checking_for_portal());
755  CompleteURLFetch(net::OK, 204, NULL);
756
757  CheckPortalState(
758      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
759
760  ASSERT_TRUE(
761      MakeResultHistogramChecker()
762          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
763          ->Check());
764}
765
766TEST_F(NetworkPortalDetectorImplTest, ErrorScreenStrategyForPortalNetwork) {
767  ASSERT_TRUE(is_state_idle());
768  set_delay_till_next_attempt(base::TimeDelta());
769
770  enable_error_screen_strategy();
771  SetConnected(kStubWireless1);
772
773  CompleteURLFetch(
774      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
775  ASSERT_EQ(1, no_response_result_count());
776  ASSERT_TRUE(is_state_portal_detection_pending());
777  CheckPortalState(
778      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
779
780  // To run CaptivePortalDetector::DetectCaptivePortal().
781  base::RunLoop().RunUntilIdle();
782
783  CompleteURLFetch(
784      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
785  ASSERT_EQ(2, no_response_result_count());
786  ASSERT_TRUE(is_state_portal_detection_pending());
787  CheckPortalState(
788      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
789
790  // To run CaptivePortalDetector::DetectCaptivePortal().
791  base::RunLoop().RunUntilIdle();
792
793  CompleteURLFetch(net::OK, 200, NULL);
794  ASSERT_EQ(0, no_response_result_count());
795  ASSERT_TRUE(is_state_portal_detection_pending());
796  CheckPortalState(
797      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
798
799  // To run CaptivePortalDetector::DetectCaptivePortal().
800  base::RunLoop().RunUntilIdle();
801
802  disable_error_screen_strategy();
803
804  ASSERT_TRUE(is_state_portal_detection_pending());
805  CheckPortalState(
806      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
807
808  ASSERT_TRUE(
809      MakeResultHistogramChecker()
810          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
811          ->Check());
812}
813
814TEST_F(NetworkPortalDetectorImplTest, DetectionTimeoutIsCancelled) {
815  ASSERT_TRUE(is_state_idle());
816  set_delay_till_next_attempt(base::TimeDelta());
817
818  SetConnected(kStubWireless1);
819  ASSERT_TRUE(is_state_checking_for_portal());
820  CheckPortalState(
821      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
822
823  stop_detection();
824
825  ASSERT_TRUE(is_state_idle());
826  ASSERT_TRUE(attempt_timeout_is_cancelled());
827  CheckPortalState(
828      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
829
830  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
831}
832
833TEST_F(NetworkPortalDetectorImplTest, TestDetectionRestart) {
834  ASSERT_TRUE(is_state_idle());
835  set_delay_till_next_attempt(base::TimeDelta());
836
837  // First portal detection attempts determines ONLINE state.
838  SetConnected(kStubWireless1);
839  ASSERT_TRUE(is_state_checking_for_portal());
840  ASSERT_FALSE(start_detection_if_idle());
841
842  CompleteURLFetch(net::OK, 204, NULL);
843
844  CheckPortalState(
845      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
846  ASSERT_FALSE(is_state_idle());
847
848  // First portal detection attempts determines PORTAL state.
849  ASSERT_TRUE(is_state_portal_detection_pending());
850
851  base::RunLoop().RunUntilIdle();
852  ASSERT_TRUE(is_state_checking_for_portal());
853  CompleteURLFetch(net::OK, 200, NULL);
854
855  CheckPortalState(
856      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
857  ASSERT_FALSE(is_state_idle());
858
859  ASSERT_TRUE(
860      MakeResultHistogramChecker()
861          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
862          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
863          ->Check());
864}
865
866TEST_F(NetworkPortalDetectorImplTest, RequestTimeouts) {
867  ASSERT_TRUE(is_state_idle());
868  set_delay_till_next_attempt(base::TimeDelta());
869
870  SetNetworkDeviceEnabled(shill::kTypeWifi, false);
871  SetConnected(kStubCellular);
872
873  // First portal detection attempt for cellular1 uses 5sec timeout.
874  CheckRequestTimeoutAndCompleteAttempt(
875      0 /* expected_same_detection_result_count */,
876      0 /* expected_no_response_result_count */,
877      5 /* expected_request_timeout_sec */,
878      net::ERR_CONNECTION_CLOSED,
879      net::URLFetcher::RESPONSE_CODE_INVALID);
880
881  // Second portal detection attempt for cellular1 uses 10sec timeout.
882  ASSERT_TRUE(is_state_portal_detection_pending());
883  base::RunLoop().RunUntilIdle();
884  CheckRequestTimeoutAndCompleteAttempt(
885      1 /* expected_same_detection_result_count */,
886      1 /* expected_no_response_result_count */,
887      10 /* expected_request_timeout_sec */,
888      net::ERR_CONNECTION_CLOSED,
889      net::URLFetcher::RESPONSE_CODE_INVALID);
890
891  // Third portal detection attempt for cellular1 uses 15sec timeout.
892  ASSERT_TRUE(is_state_portal_detection_pending());
893  base::RunLoop().RunUntilIdle();
894  CheckRequestTimeoutAndCompleteAttempt(
895      2 /* expected_same_detection_result_count */,
896      2 /* expected_no_response_result_count */,
897      15 /* expected_request_timeout_sec */,
898      net::ERR_CONNECTION_CLOSED,
899      net::URLFetcher::RESPONSE_CODE_INVALID);
900
901  ASSERT_FALSE(is_state_idle());
902
903  // Check that on the error screen 15sec timeout is used.
904  enable_error_screen_strategy();
905  ASSERT_TRUE(is_state_portal_detection_pending());
906  base::RunLoop().RunUntilIdle();
907  CheckRequestTimeoutAndCompleteAttempt(
908      0 /* expected_same_detection_result_count */,
909      0 /* expected_no_response_result_count */,
910      15 /* expected_request_timeout_sec */,
911      net::ERR_CONNECTION_CLOSED,
912      net::URLFetcher::RESPONSE_CODE_INVALID);
913  disable_error_screen_strategy();
914  ASSERT_TRUE(is_state_portal_detection_pending());
915
916  SetNetworkDeviceEnabled(shill::kTypeWifi, true);
917  SetConnected(kStubWireless1);
918
919  // First portal detection attempt for wifi1 uses 5sec timeout.
920  CheckRequestTimeoutAndCompleteAttempt(
921      0 /* expected_same_detection_result_count */,
922      0 /* expected_no_response_result_count */,
923      5 /* expected_request_timeout_sec */,
924      net::ERR_CONNECTION_CLOSED,
925      net::URLFetcher::RESPONSE_CODE_INVALID);
926
927  // Second portal detection attempt for wifi1 also uses 5sec timeout.
928  ASSERT_TRUE(is_state_portal_detection_pending());
929  base::RunLoop().RunUntilIdle();
930  CheckRequestTimeoutAndCompleteAttempt(
931      1 /* expected_same_detection_result_count */,
932      1 /* expected_no_response_result_count */,
933      10 /* expected_request_timeout_sec */,
934      net::OK,
935      204);
936  ASSERT_FALSE(is_state_idle());
937
938  // Check that in error screen strategy detection for wifi1 15sec
939  // timeout is used.
940  enable_error_screen_strategy();
941  ASSERT_TRUE(is_state_portal_detection_pending());
942  base::RunLoop().RunUntilIdle();
943  CheckRequestTimeoutAndCompleteAttempt(
944      0 /* expected_same_detection_result_count */,
945      0 /* expected_no_response_result_count */,
946      15 /* expected_request_timeout_sec */,
947      net::OK,
948      204);
949  disable_error_screen_strategy();
950  ASSERT_TRUE(is_state_portal_detection_pending());
951
952  ASSERT_TRUE(
953      MakeResultHistogramChecker()
954          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
955          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
956          ->Check());
957}
958
959TEST_F(NetworkPortalDetectorImplTest, RequestTimeouts2) {
960  ASSERT_TRUE(is_state_idle());
961  set_delay_till_next_attempt(base::TimeDelta());
962  SetConnected(kStubWireless1);
963
964  // First portal detection attempt for wifi1 uses 5sec timeout.
965  CheckRequestTimeoutAndCompleteAttempt(
966      0 /* expected_same_detection_result_count */,
967      0 /* expected_no_response_result_count */,
968      5 /* expected_request_timeout_sec */,
969      net::ERR_CONNECTION_CLOSED,
970      net::URLFetcher::RESPONSE_CODE_INVALID);
971  ASSERT_TRUE(is_state_portal_detection_pending());
972  base::RunLoop().RunUntilIdle();
973
974  // Second portal detection attempt for wifi1 uses 10sec timeout.
975  CheckRequestTimeoutAndCompleteAttempt(
976      1 /* expected_same_detection_result_count */,
977      1 /* expected_no_response_result_count */,
978      10 /* expected_request_timeout_sec */,
979      net::ERR_CONNECTION_CLOSED,
980      net::URLFetcher::RESPONSE_CODE_INVALID);
981  ASSERT_TRUE(is_state_portal_detection_pending());
982  base::RunLoop().RunUntilIdle();
983
984  // Second portal detection attempt for wifi1 uses 15sec timeout.
985  CheckRequestTimeoutAndCompleteAttempt(
986      2 /* expected_same_detection_result_count */,
987      2 /* expected_no_response_result_count */,
988      15 /* expected_request_timeout_sec */,
989      net::ERR_CONNECTION_CLOSED,
990      net::URLFetcher::RESPONSE_CODE_INVALID);
991  ASSERT_FALSE(is_state_idle());
992  ASSERT_TRUE(is_state_portal_detection_pending());
993
994  // Third portal detection attempt for wifi1 uses 20sec timeout.
995  base::RunLoop().RunUntilIdle();
996  CheckRequestTimeoutAndCompleteAttempt(
997      3 /* expected_same_detection_result_count */,
998      3 /* expected_no_response_result_count */,
999      20 /* expected_request_timeout_sec */,
1000      net::OK,
1001      204);
1002  ASSERT_FALSE(is_state_idle());
1003
1004  // Fourth portal detection attempt for wifi1 uses 5sec timeout.
1005  base::RunLoop().RunUntilIdle();
1006  CheckRequestTimeoutAndCompleteAttempt(
1007      1 /* expected_same_detection_result_count */,
1008      0 /* expected_no_response_result_count */,
1009      5 /* expected_request_timeout_sec */,
1010      net::OK,
1011      204);
1012  ASSERT_FALSE(is_state_idle());
1013
1014  ASSERT_TRUE(
1015      MakeResultHistogramChecker()
1016          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
1017          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
1018          ->Check());
1019}
1020
1021}  // namespace chromeos
1022