network_portal_detector_impl_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// Copyright (c) 2013 The Chromium Authors. All rights reserved.
295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// Use of this source code is governed by a BSD-style license that can be
395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// found in the LICENSE file.
495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <algorithm>
695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include <vector>
795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/command_line.h"
995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/compiler_specific.h"
1095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/logging.h"
1195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/memory/scoped_ptr.h"
1295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/metrics/histogram_base.h"
1395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/metrics/histogram_samples.h"
1495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/metrics/statistics_recorder.h"
1595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "base/run_loop.h"
1695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chrome/browser/captive_portal/captive_portal_detector.h"
1795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chrome/browser/captive_portal/testing_utils.h"
1895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
1995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chrome/test/base/testing_profile.h"
2095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/chromeos_switches.h"
2195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/dbus/dbus_thread_manager.h"
2295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/dbus/shill_device_client.h"
2395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/dbus/shill_service_client.h"
2495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/network/network_state.h"
2595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/network/network_state_handler.h"
2695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "chromeos/network/shill_property_util.h"
2795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "content/public/test/test_browser_thread_bundle.h"
2895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "dbus/object_path.h"
2995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "net/base/net_errors.h"
3095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "testing/gmock/include/gmock/gmock.h"
3195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "testing/gtest/include/gtest/gtest.h"
3295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley#include "third_party/cros_system_api/dbus/service_constants.h"
3395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
3495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyusing testing::AnyNumber;
3595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyusing testing::Mock;
3695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyusing testing::_;
3795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
3895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleynamespace chromeos {
3995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleynamespace {
4195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley// Service paths for stub network devices.
4395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst char kStubEthernet[] = "stub_ethernet";
4495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst char kStubWireless1[] = "stub_wifi1";
4595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst char kStubWireless2[] = "stub_wifi2";
4695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyconst char kStubCellular[] = "stub_cellular";
4795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
4895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyvoid ErrorCallbackFunction(const std::string& error_name,
4995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                           const std::string& error_message) {
5095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
5195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
5295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyclass MockObserver : public NetworkPortalDetector::Observer {
5495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley public:
5595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  virtual ~MockObserver() {}
5695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
5795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  MOCK_METHOD2(OnPortalDetectionCompleted,
5895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley               void(const NetworkState* network,
5995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                    const NetworkPortalDetector::CaptivePortalState& state));
6095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
6195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyclass ResultHistogramChecker {
6395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley public:
6495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  explicit ResultHistogramChecker(base::HistogramSamples* base)
6595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      : base_(base),
6695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        count_(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT) {}
6795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  virtual ~ResultHistogramChecker() {}
6895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
6995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ResultHistogramChecker* Expect(
7095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CaptivePortalStatus status,
7195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      int count) {
7295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    count_[status] = count;
7395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return this;
7495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
7595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
7695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool Check() const {
7795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(
7895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        NetworkPortalDetectorImpl::kDetectionResultHistogram);
7995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool empty = false;
8095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (static_cast<size_t>(std::count(count_.begin(), count_.end(), 0)) ==
8195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        count_.size()) {
8295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      empty = true;
8395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
8495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
8595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!histogram) {
8695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (empty)
8795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return true;
8895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      LOG(ERROR) << "Can't get histogram for "
8995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 << NetworkPortalDetectorImpl::kDetectionResultHistogram;
9095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return false;
9195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
9295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    scoped_ptr<base::HistogramSamples> samples = histogram->SnapshotSamples();
9395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (!samples.get()) {
9495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (empty)
9595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        return true;
9695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      LOG(ERROR) << "Can't get samples for "
9795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                 << NetworkPortalDetectorImpl::kDetectionResultHistogram;
9895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      return false;
9995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
10095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    bool ok = true;
10195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    for (size_t i = 0; i < count_.size(); ++i) {
10295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      const int base = base_ ? base_->GetCount(i) : 0;
10395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      const int actual = samples->GetCount(i) - base;
10495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      const NetworkPortalDetector::CaptivePortalStatus status =
10595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          static_cast<NetworkPortalDetector::CaptivePortalStatus>(i);
10695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      if (actual != count_[i]) {
10795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        LOG(ERROR) << "Expected: " << count_[i] << ", "
10895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                   << "actual: " << actual << " for "
10995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                   << NetworkPortalDetector::CaptivePortalStatusString(status);
11095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        ok = false;
11195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      }
11295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
11395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return ok;
11495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
11595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
11695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley private:
11795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  base::HistogramSamples* base_;
11895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  std::vector<int> count_;
11995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  DISALLOW_COPY_AND_ASSIGN(ResultHistogramChecker);
12195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
12295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}  // namespace
12495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
12595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langleyclass NetworkPortalDetectorImplTest
12695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    : public testing::Test,
12795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      public captive_portal::CaptivePortalDetectorTestBase {
12895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley protected:
12995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  virtual void SetUp() {
13095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CommandLine* cl = CommandLine::ForCurrentProcess();
13195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    cl->AppendSwitch(switches::kDisableNetworkPortalNotification);
13295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
13395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    DBusThreadManager::InitializeWithStub();
13495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::StatisticsRecorder::Initialize();
13595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    SetupNetworkHandler();
13695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
13795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    profile_.reset(new TestingProfile());
13895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector_.reset(
13995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        new NetworkPortalDetectorImpl(profile_->GetRequestContext()));
14095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector_->Enable(false);
14195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    set_detector(network_portal_detector_->captive_portal_detector_.get());
14395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    // Prevents flakiness due to message loop delays.
14595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    set_time_ticks(base::TimeTicks::Now());
14695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
14795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    if (base::HistogramBase* histogram =
14895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley            base::StatisticsRecorder::FindHistogram(
14995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                NetworkPortalDetectorImpl::kDetectionResultHistogram)) {
15095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      original_samples_.reset(histogram->SnapshotSamples().release());
15195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    }
15295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
15395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
15495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  virtual void TearDown() {
15595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector_.reset();
15695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    profile_.reset();
15795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    NetworkHandler::Shutdown();
15895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    DBusThreadManager::Shutdown();
15995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PortalDetectorStrategy::reset_fields_for_testing();
16095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
16195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
16295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void CheckPortalState(NetworkPortalDetector::CaptivePortalStatus status,
16395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        int response_code,
16495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                        const std::string& service_path) {
16595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    NetworkPortalDetector::CaptivePortalState state =
16695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        network_portal_detector()->GetCaptivePortalState(service_path);
16795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ASSERT_EQ(status, state.status);
16895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ASSERT_EQ(response_code, state.response_code);
16995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
17095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
17195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void CheckRequestTimeoutAndCompleteAttempt(int expected_attempt_count,
17295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                             int expected_request_timeout_sec,
17395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                             int net_error,
17495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                                             int status_code) {
17595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ASSERT_TRUE(is_state_checking_for_portal());
17695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ASSERT_EQ(expected_attempt_count, attempt_count());
17795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ASSERT_EQ(base::TimeDelta::FromSeconds(expected_request_timeout_sec),
17895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley              get_next_attempt_timeout());
17995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    CompleteURLFetch(net_error, status_code, NULL);
18095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
18195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  Profile* profile() { return profile_.get(); }
18395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  NetworkPortalDetectorImpl* network_portal_detector() {
18595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector_.get();
18695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
18795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
18895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  NetworkPortalDetectorImpl::State state() {
18995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->state();
19095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool start_detection_if_idle() {
19395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->StartDetectionIfIdle();
19495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
19695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void enable_error_screen_strategy() {
19795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector()->OnErrorScreenShow();
19895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
19995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void disable_error_screen_strategy() {
20195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector()->OnErrorScreenHide();
20295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
20395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void stop_detection() {
20595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector()->StopDetection();
20695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
20795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
20895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool attempt_timeout_is_cancelled() {
20995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->AttemptTimeoutIsCancelledForTesting();
21095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
21195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  base::TimeDelta get_next_attempt_timeout() {
21395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->strategy_->GetNextAttemptTimeout();
21495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
21595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
21695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void set_next_attempt_timeout(const base::TimeDelta& timeout) {
21795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PortalDetectorStrategy::set_next_attempt_timeout_for_testing(timeout);
21895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
21995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool is_state_idle() {
22195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return (NetworkPortalDetectorImpl::STATE_IDLE == state());
22295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool is_state_portal_detection_pending() {
22595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return (NetworkPortalDetectorImpl::STATE_PORTAL_CHECK_PENDING == state());
22695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
22795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
22895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  bool is_state_checking_for_portal() {
22995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return (NetworkPortalDetectorImpl::STATE_CHECKING_FOR_PORTAL == state());
23095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  const base::TimeDelta& next_attempt_delay() {
23595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->next_attempt_delay_for_testing();
23695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
23795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
23895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  int attempt_count() {
23995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return network_portal_detector()->attempt_count_for_testing();
24095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
24195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void set_attempt_count(int ac) {
24395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector()->set_attempt_count_for_testing(ac);
24495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
24595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
24695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void set_delay_till_next_attempt(const base::TimeDelta& delta) {
24795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    PortalDetectorStrategy::set_delay_till_next_attempt_for_testing(delta);
24895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
24995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void set_time_ticks(const base::TimeTicks& time_ticks) {
25195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    network_portal_detector()->set_time_ticks_for_testing(time_ticks);
25295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
25395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
25495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetBehindPortal(const std::string& service_path) {
25595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
25695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dbus::ObjectPath(service_path),
25795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        shill::kStateProperty,
25895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::StringValue(shill::kStatePortal),
25995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&base::DoNothing),
26095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&ErrorCallbackFunction));
26195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::RunLoop().RunUntilIdle();
26295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
26395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
26495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetNetworkDeviceEnabled(const std::string& type, bool enabled) {
26595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    NetworkHandler::Get()->network_state_handler()->SetTechnologyEnabled(
26695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        NetworkTypePattern::Primitive(type),
26795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        enabled,
26895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        network_handler::ErrorCallback());
26995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::RunLoop().RunUntilIdle();
27095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
27195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
27295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetConnected(const std::string& service_path) {
27395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    DBusThreadManager::Get()->GetShillServiceClient()->Connect(
27495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dbus::ObjectPath(service_path),
27595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&base::DoNothing),
27695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&ErrorCallbackFunction));
27795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::RunLoop().RunUntilIdle();
27895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
27995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetDisconnected(const std::string& service_path) {
28195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    DBusThreadManager::Get()->GetShillServiceClient()->Disconnect(
28295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        dbus::ObjectPath(service_path),
28395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&*base::DoNothing),
28495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        base::Bind(&ErrorCallbackFunction));
28595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::RunLoop().RunUntilIdle();
28695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
28795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
28895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  scoped_ptr<ResultHistogramChecker> MakeResultHistogramChecker() {
28995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    return scoped_ptr<ResultHistogramChecker>(
29095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        new ResultHistogramChecker(original_samples_.get())).Pass();
29195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
29295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
29395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley private:
29495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetupDefaultShillState() {
29595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    base::RunLoop().RunUntilIdle();
29695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    ShillServiceClient::TestInterface* service_test =
29795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
29895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    service_test->ClearServices();
29995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const bool add_to_visible = true;
30095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    const bool add_to_watchlist = true;
30195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    service_test->AddService(kStubEthernet,
30295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             kStubEthernet,
30395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kTypeEthernet,
30495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kStateIdle,
30595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_visible,
30695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_watchlist);
30795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    service_test->AddService(kStubWireless1,
30895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             kStubWireless1,
30995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kTypeWifi,
31095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kStateIdle,
31195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_visible,
31295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_watchlist);
31395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    service_test->AddService(kStubWireless2,
31495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             kStubWireless2,
31595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kTypeWifi,
31695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kStateIdle,
31795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_visible,
31895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_watchlist);
31995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    service_test->AddService(kStubCellular,
32095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             kStubCellular,
32195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kTypeCellular,
32295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             shill::kStateIdle,
32395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_visible,
32495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley                             add_to_watchlist);
32595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
32695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
32795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  void SetupNetworkHandler() {
32895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    SetupDefaultShillState();
32995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley    NetworkHandler::Initialize();
33095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  }
33195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  content::TestBrowserThreadBundle thread_bundle_;
33395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  scoped_ptr<TestingProfile> profile_;
33495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  scoped_ptr<NetworkPortalDetectorImpl> network_portal_detector_;
33595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  scoped_ptr<base::HistogramSamples> original_samples_;
33695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley};
33795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
33895c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyTEST_F(NetworkPortalDetectorImplTest, NoPortal) {
33995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
34095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetConnected(kStubWireless1);
34295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_checking_for_portal());
34495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CheckPortalState(
34595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
34695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CompleteURLFetch(net::OK, 204, NULL);
34895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
34995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
35095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CheckPortalState(
35195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
35295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(
35395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      MakeResultHistogramChecker()
35495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
35595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          ->Check());
35695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley}
35795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
35895c29f3cd1f6c08c6c0927868683392eea727ccAdam LangleyTEST_F(NetworkPortalDetectorImplTest, Portal) {
35995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
36095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Check HTTP 200 response code.
36295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetConnected(kStubWireless1);
36395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_checking_for_portal());
36495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CompleteURLFetch(net::OK, 200, NULL);
36695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
36795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
36895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CheckPortalState(
36995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
37095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Check HTTP 301 response code.
37295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetConnected(kStubWireless2);
37395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_checking_for_portal());
37495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CompleteURLFetch(net::OK, 301, NULL);
37695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
37795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
37895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CheckPortalState(
37995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 301, kStubWireless2);
38095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  // Check HTTP 302 response code.
38295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  SetConnected(kStubEthernet);
38395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_checking_for_portal());
38495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38595c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CompleteURLFetch(net::OK, 302, NULL);
38695c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
38795c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(is_state_idle());
38895c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  CheckPortalState(
38995c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 302, kStubEthernet);
39095c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley
39195c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley  ASSERT_TRUE(
39295c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley      MakeResultHistogramChecker()
39395c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 3)
39495c29f3cd1f6c08c6c0927868683392eea727ccAdam Langley          ->Check());
395}
396
397TEST_F(NetworkPortalDetectorImplTest, Online2Offline) {
398  ASSERT_TRUE(is_state_idle());
399
400  MockObserver observer;
401  network_portal_detector()->AddObserver(&observer);
402
403  NetworkPortalDetector::CaptivePortalState offline_state;
404  offline_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE;
405
406  // WiFi is in online state.
407  {
408    // When transitioning to a connected state, the network will transition to
409    // connecting states which will set the default network to NULL. This may
410    // get triggered multiple times.
411    EXPECT_CALL(observer, OnPortalDetectionCompleted(_, offline_state))
412        .Times(AnyNumber());
413
414    // Expect a single transition to an online state.
415    NetworkPortalDetector::CaptivePortalState online_state;
416    online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
417    online_state.response_code = 204;
418    EXPECT_CALL(observer, OnPortalDetectionCompleted(_, online_state)).Times(1);
419
420    SetConnected(kStubWireless1);
421    ASSERT_TRUE(is_state_checking_for_portal());
422
423    CompleteURLFetch(net::OK, 204, NULL);
424    ASSERT_TRUE(is_state_idle());
425
426    // Check that observer was notified about online state.
427    Mock::VerifyAndClearExpectations(&observer);
428  }
429
430  // WiFi is turned off.
431  {
432    EXPECT_CALL(observer, OnPortalDetectionCompleted(NULL, offline_state))
433        .Times(1);
434
435    SetDisconnected(kStubWireless1);
436    ASSERT_TRUE(is_state_idle());
437
438    // Check that observer was notified about offline state.
439    Mock::VerifyAndClearExpectations(&observer);
440  }
441
442  network_portal_detector()->RemoveObserver(&observer);
443
444  ASSERT_TRUE(
445      MakeResultHistogramChecker()
446          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
447          ->Check());
448}
449
450TEST_F(NetworkPortalDetectorImplTest, TwoNetworks) {
451  ASSERT_TRUE(is_state_idle());
452
453  SetConnected(kStubWireless1);
454  ASSERT_TRUE(is_state_checking_for_portal());
455
456  // WiFi is in portal state.
457  CompleteURLFetch(net::OK, 200, NULL);
458  ASSERT_TRUE(is_state_idle());
459
460  SetConnected(kStubEthernet);
461  ASSERT_TRUE(is_state_checking_for_portal());
462
463  // ethernet is in online state.
464  CompleteURLFetch(net::OK, 204, NULL);
465  ASSERT_TRUE(is_state_idle());
466  CheckPortalState(
467      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubEthernet);
468  CheckPortalState(
469      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
470
471  ASSERT_TRUE(
472      MakeResultHistogramChecker()
473          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
474          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
475          ->Check());
476}
477
478TEST_F(NetworkPortalDetectorImplTest, NetworkChanged) {
479  ASSERT_TRUE(is_state_idle());
480
481  SetConnected(kStubWireless1);
482
483  // WiFi is in portal state.
484  fetcher()->set_response_code(200);
485  ASSERT_TRUE(is_state_checking_for_portal());
486
487  // Active network is changed during portal detection for WiFi.
488  SetConnected(kStubEthernet);
489
490  // Portal detection for WiFi is cancelled, portal detection for
491  // ethernet is initiated.
492  ASSERT_TRUE(is_state_checking_for_portal());
493
494  // ethernet is in online state.
495  CompleteURLFetch(net::OK, 204, NULL);
496  ASSERT_TRUE(is_state_idle());
497  CheckPortalState(
498      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubEthernet);
499
500  // As active network was changed during portal detection for wifi
501  // network, it's state must be unknown.
502  CheckPortalState(
503      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
504
505  ASSERT_TRUE(
506      MakeResultHistogramChecker()
507          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
508          ->Check());
509}
510
511TEST_F(NetworkPortalDetectorImplTest, NetworkStateNotChanged) {
512  ASSERT_TRUE(is_state_idle());
513
514  SetConnected(kStubWireless1);
515  ASSERT_TRUE(is_state_checking_for_portal());
516
517  CompleteURLFetch(net::OK, 204, NULL);
518
519  ASSERT_TRUE(is_state_idle());
520  CheckPortalState(
521      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
522
523  SetConnected(kStubWireless1);
524  ASSERT_TRUE(is_state_idle());
525
526  ASSERT_TRUE(
527      MakeResultHistogramChecker()
528          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
529          ->Check());
530}
531
532TEST_F(NetworkPortalDetectorImplTest, NetworkStateChanged) {
533  // Test for Portal -> Online -> Portal network state transitions.
534  ASSERT_TRUE(is_state_idle());
535
536  SetBehindPortal(kStubWireless1);
537  ASSERT_TRUE(is_state_checking_for_portal());
538
539  CompleteURLFetch(net::OK, 200, NULL);
540
541  ASSERT_TRUE(is_state_idle());
542  CheckPortalState(
543      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
544
545  SetConnected(kStubWireless1);
546  ASSERT_TRUE(is_state_checking_for_portal());
547
548  CompleteURLFetch(net::OK, 204, NULL);
549
550  ASSERT_TRUE(is_state_idle());
551  CheckPortalState(
552      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
553
554  SetBehindPortal(kStubWireless1);
555  ASSERT_TRUE(is_state_checking_for_portal());
556
557  CompleteURLFetch(net::OK, 200, NULL);
558
559  ASSERT_TRUE(is_state_idle());
560  CheckPortalState(
561      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
562
563  ASSERT_TRUE(
564      MakeResultHistogramChecker()
565          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
566          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 2)
567          ->Check());
568}
569
570TEST_F(NetworkPortalDetectorImplTest, PortalDetectionTimeout) {
571  ASSERT_TRUE(is_state_idle());
572
573  // For instantaneous timeout.
574  set_next_attempt_timeout(base::TimeDelta::FromSeconds(0));
575
576  ASSERT_TRUE(is_state_idle());
577  ASSERT_EQ(0, attempt_count());
578
579  SetConnected(kStubWireless1);
580  base::RunLoop().RunUntilIdle();
581
582  // First portal detection timeouts, next portal detection is
583  // scheduled.
584  ASSERT_TRUE(is_state_portal_detection_pending());
585  ASSERT_EQ(1, attempt_count());
586  ASSERT_EQ(base::TimeDelta::FromSeconds(3), next_attempt_delay());
587
588  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
589}
590
591TEST_F(NetworkPortalDetectorImplTest, PortalDetectionRetryAfter) {
592  ASSERT_TRUE(is_state_idle());
593
594  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 101\n\n";
595
596  ASSERT_TRUE(is_state_idle());
597  ASSERT_EQ(0, attempt_count());
598
599  SetConnected(kStubWireless1);
600  ASSERT_TRUE(is_state_checking_for_portal());
601  CompleteURLFetch(net::OK, 503, retry_after);
602
603  // First portal detection completed, next portal detection is
604  // scheduled after 101 seconds.
605  ASSERT_TRUE(is_state_portal_detection_pending());
606  ASSERT_EQ(1, attempt_count());
607  ASSERT_EQ(base::TimeDelta::FromSeconds(101), next_attempt_delay());
608
609  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
610}
611
612TEST_F(NetworkPortalDetectorImplTest, PortalDetectorRetryAfterIsSmall) {
613  ASSERT_TRUE(is_state_idle());
614
615  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 1\n\n";
616
617  ASSERT_TRUE(is_state_idle());
618  ASSERT_EQ(0, attempt_count());
619
620  SetConnected(kStubWireless1);
621  CompleteURLFetch(net::OK, 503, retry_after);
622
623  // First portal detection completed, next portal detection is
624  // scheduled after 3 seconds (due to minimum time between detection
625  // attemps).
626  ASSERT_TRUE(is_state_portal_detection_pending());
627  ASSERT_EQ(1, attempt_count());
628  ASSERT_EQ(base::TimeDelta::FromSeconds(3), next_attempt_delay());
629
630  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
631}
632
633TEST_F(NetworkPortalDetectorImplTest, FirstAttemptFailed) {
634  ASSERT_TRUE(is_state_idle());
635
636  set_delay_till_next_attempt(base::TimeDelta());
637  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 0\n\n";
638
639  ASSERT_TRUE(is_state_idle());
640  ASSERT_EQ(0, attempt_count());
641
642  SetConnected(kStubWireless1);
643
644  CompleteURLFetch(net::OK, 503, retry_after);
645  ASSERT_TRUE(is_state_portal_detection_pending());
646  ASSERT_EQ(1, attempt_count());
647  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
648
649  // To run CaptivePortalDetector::DetectCaptivePortal().
650  base::RunLoop().RunUntilIdle();
651
652  CompleteURLFetch(net::OK, 204, NULL);
653  ASSERT_TRUE(is_state_idle());
654  ASSERT_EQ(2, attempt_count());
655  CheckPortalState(
656      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
657
658  ASSERT_TRUE(
659      MakeResultHistogramChecker()
660          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
661          ->Check());
662}
663
664TEST_F(NetworkPortalDetectorImplTest, AllAttemptsFailed) {
665  ASSERT_TRUE(is_state_idle());
666
667  set_delay_till_next_attempt(base::TimeDelta());
668  const char* retry_after = "HTTP/1.1 503 OK\nRetry-After: 0\n\n";
669
670  ASSERT_TRUE(is_state_idle());
671  ASSERT_EQ(0, attempt_count());
672
673  SetConnected(kStubWireless1);
674
675  CompleteURLFetch(net::OK, 503, retry_after);
676  ASSERT_TRUE(is_state_portal_detection_pending());
677  ASSERT_EQ(1, attempt_count());
678  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
679
680  // To run CaptivePortalDetector::DetectCaptivePortal().
681  base::RunLoop().RunUntilIdle();
682
683  CompleteURLFetch(net::OK, 503, retry_after);
684  ASSERT_TRUE(is_state_portal_detection_pending());
685  ASSERT_EQ(2, attempt_count());
686  ASSERT_EQ(base::TimeDelta::FromSeconds(0), next_attempt_delay());
687
688  // To run CaptivePortalDetector::DetectCaptivePortal().
689  base::RunLoop().RunUntilIdle();
690
691  CompleteURLFetch(net::OK, 503, retry_after);
692  ASSERT_TRUE(is_state_idle());
693  ASSERT_EQ(3, attempt_count());
694  CheckPortalState(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE,
695                   503,
696                   kStubWireless1);
697
698  ASSERT_TRUE(
699      MakeResultHistogramChecker()
700          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
701          ->Check());
702}
703
704TEST_F(NetworkPortalDetectorImplTest, ProxyAuthRequired) {
705  ASSERT_TRUE(is_state_idle());
706  set_delay_till_next_attempt(base::TimeDelta());
707
708  SetConnected(kStubWireless1);
709  CompleteURLFetch(net::OK, 407, NULL);
710  ASSERT_EQ(1, attempt_count());
711  ASSERT_TRUE(is_state_idle());
712  CheckPortalState(
713      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED,
714      407,
715      kStubWireless1);
716
717  ASSERT_TRUE(MakeResultHistogramChecker()
718                  ->Expect(NetworkPortalDetector::
719                               CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED,
720                           1)
721                  ->Check());
722}
723
724TEST_F(NetworkPortalDetectorImplTest, NoResponseButBehindPortal) {
725  ASSERT_TRUE(is_state_idle());
726  set_delay_till_next_attempt(base::TimeDelta());
727
728  SetBehindPortal(kStubWireless1);
729  ASSERT_TRUE(is_state_checking_for_portal());
730
731  CompleteURLFetch(
732      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
733  ASSERT_EQ(1, attempt_count());
734  ASSERT_TRUE(is_state_portal_detection_pending());
735
736  // To run CaptivePortalDetector::DetectCaptivePortal().
737  base::RunLoop().RunUntilIdle();
738
739  CompleteURLFetch(
740      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
741  ASSERT_EQ(2, attempt_count());
742  ASSERT_TRUE(is_state_portal_detection_pending());
743
744  // To run CaptivePortalDetector::DetectCaptivePortal().
745  base::RunLoop().RunUntilIdle();
746
747  CompleteURLFetch(
748      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
749  ASSERT_EQ(3, attempt_count());
750  ASSERT_TRUE(is_state_idle());
751
752  CheckPortalState(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL,
753                   net::URLFetcher::RESPONSE_CODE_INVALID,
754                   kStubWireless1);
755
756  ASSERT_TRUE(
757      MakeResultHistogramChecker()
758          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
759          ->Check());
760}
761
762TEST_F(NetworkPortalDetectorImplTest,
763       DisableErrorScreenStrategyWhilePendingRequest) {
764  ASSERT_TRUE(is_state_idle());
765  set_attempt_count(3);
766  enable_error_screen_strategy();
767  ASSERT_TRUE(is_state_portal_detection_pending());
768  disable_error_screen_strategy();
769
770  // To run CaptivePortalDetector::DetectCaptivePortal().
771  base::MessageLoop::current()->RunUntilIdle();
772
773  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
774}
775
776TEST_F(NetworkPortalDetectorImplTest, ErrorScreenStrategyForOnlineNetwork) {
777  ASSERT_TRUE(is_state_idle());
778  set_delay_till_next_attempt(base::TimeDelta());
779
780  SetConnected(kStubWireless1);
781  enable_error_screen_strategy();
782  // To run CaptivePortalDetector::DetectCaptivePortal().
783  base::RunLoop().RunUntilIdle();
784  CompleteURLFetch(net::OK, 204, NULL);
785
786  ASSERT_TRUE(is_state_portal_detection_pending());
787  CheckPortalState(
788      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
789
790  // To run CaptivePortalDetector::DetectCaptivePortal().
791  base::RunLoop().RunUntilIdle();
792
793  CompleteURLFetch(net::OK, 204, NULL);
794
795  ASSERT_TRUE(is_state_portal_detection_pending());
796  CheckPortalState(
797      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, 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  // To run CaptivePortalDetector::DetectCaptivePortal().
806  base::RunLoop().RunUntilIdle();
807  ASSERT_TRUE(is_state_checking_for_portal());
808  CompleteURLFetch(net::OK, 204, NULL);
809
810  CheckPortalState(
811      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
812
813  ASSERT_TRUE(
814      MakeResultHistogramChecker()
815          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
816          ->Check());
817}
818
819TEST_F(NetworkPortalDetectorImplTest, ErrorScreenStrategyForPortalNetwork) {
820  ASSERT_TRUE(is_state_idle());
821  set_delay_till_next_attempt(base::TimeDelta());
822
823  enable_error_screen_strategy();
824  SetConnected(kStubWireless1);
825
826  CompleteURLFetch(
827      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
828  ASSERT_EQ(1, attempt_count());
829  ASSERT_TRUE(is_state_portal_detection_pending());
830  CheckPortalState(
831      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
832
833  // To run CaptivePortalDetector::DetectCaptivePortal().
834  base::RunLoop().RunUntilIdle();
835
836  CompleteURLFetch(
837      net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID, NULL);
838  ASSERT_EQ(2, attempt_count());
839  ASSERT_TRUE(is_state_portal_detection_pending());
840  CheckPortalState(
841      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
842
843  // To run CaptivePortalDetector::DetectCaptivePortal().
844  base::RunLoop().RunUntilIdle();
845
846  CompleteURLFetch(net::OK, 200, NULL);
847  ASSERT_EQ(3, attempt_count());
848  ASSERT_TRUE(is_state_portal_detection_pending());
849  CheckPortalState(
850      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
851
852  // To run CaptivePortalDetector::DetectCaptivePortal().
853  base::RunLoop().RunUntilIdle();
854
855  disable_error_screen_strategy();
856
857  ASSERT_TRUE(is_state_portal_detection_pending());
858  CheckPortalState(
859      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
860
861  ASSERT_TRUE(
862      MakeResultHistogramChecker()
863          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
864          ->Check());
865}
866
867TEST_F(NetworkPortalDetectorImplTest, DetectionTimeoutIsCancelled) {
868  ASSERT_TRUE(is_state_idle());
869  set_delay_till_next_attempt(base::TimeDelta());
870
871  SetConnected(kStubWireless1);
872  ASSERT_TRUE(is_state_checking_for_portal());
873  CheckPortalState(
874      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
875
876  stop_detection();
877
878  ASSERT_TRUE(is_state_idle());
879  ASSERT_TRUE(attempt_timeout_is_cancelled());
880  CheckPortalState(
881      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN, -1, kStubWireless1);
882
883  ASSERT_TRUE(MakeResultHistogramChecker()->Check());
884}
885
886TEST_F(NetworkPortalDetectorImplTest, TestDetectionRestart) {
887  ASSERT_TRUE(is_state_idle());
888  set_delay_till_next_attempt(base::TimeDelta());
889
890  // First portal detection attempts determines ONLINE state.
891  SetConnected(kStubWireless1);
892  ASSERT_TRUE(is_state_checking_for_portal());
893  ASSERT_FALSE(start_detection_if_idle());
894
895  CompleteURLFetch(net::OK, 204, NULL);
896
897  CheckPortalState(
898      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 204, kStubWireless1);
899  ASSERT_TRUE(is_state_idle());
900
901  // First portal detection attempts determines PORTAL state.
902  ASSERT_TRUE(start_detection_if_idle());
903  ASSERT_TRUE(is_state_portal_detection_pending());
904  ASSERT_FALSE(start_detection_if_idle());
905
906  base::RunLoop().RunUntilIdle();
907  ASSERT_TRUE(is_state_checking_for_portal());
908  CompleteURLFetch(net::OK, 200, NULL);
909
910  CheckPortalState(
911      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 200, kStubWireless1);
912  ASSERT_TRUE(is_state_idle());
913
914  ASSERT_TRUE(
915      MakeResultHistogramChecker()
916          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
917          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL, 1)
918          ->Check());
919}
920
921TEST_F(NetworkPortalDetectorImplTest, RequestTimeouts) {
922  ASSERT_TRUE(is_state_idle());
923  set_delay_till_next_attempt(base::TimeDelta());
924
925  SetNetworkDeviceEnabled(shill::kTypeWifi, false);
926  SetConnected(kStubCellular);
927
928  // First portal detection attempt for cellular1 uses 5sec timeout.
929  CheckRequestTimeoutAndCompleteAttempt(
930      0, 5, net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID);
931
932  // Second portal detection attempt for cellular1 uses 10sec timeout.
933  ASSERT_TRUE(is_state_portal_detection_pending());
934  base::RunLoop().RunUntilIdle();
935  CheckRequestTimeoutAndCompleteAttempt(1,
936                                        10,
937                                        net::ERR_CONNECTION_CLOSED,
938                                        net::URLFetcher::RESPONSE_CODE_INVALID);
939
940  // Third portal detection attempt for cellular1 uses 15sec timeout.
941  ASSERT_TRUE(is_state_portal_detection_pending());
942  base::RunLoop().RunUntilIdle();
943  CheckRequestTimeoutAndCompleteAttempt(2,
944                                        15,
945                                        net::ERR_CONNECTION_CLOSED,
946                                        net::URLFetcher::RESPONSE_CODE_INVALID);
947
948  ASSERT_TRUE(is_state_idle());
949
950  // Check that in lazy detection for cellular1 15sec timeout is used.
951  enable_error_screen_strategy();
952  ASSERT_TRUE(is_state_portal_detection_pending());
953  base::RunLoop().RunUntilIdle();
954  CheckRequestTimeoutAndCompleteAttempt(0,
955                                        15,
956                                        net::ERR_CONNECTION_CLOSED,
957                                        net::URLFetcher::RESPONSE_CODE_INVALID);
958  disable_error_screen_strategy();
959  ASSERT_TRUE(is_state_portal_detection_pending());
960
961  SetNetworkDeviceEnabled(shill::kTypeWifi, true);
962  SetConnected(kStubWireless1);
963
964  // First portal detection attempt for wifi1 uses 5sec timeout.
965  CheckRequestTimeoutAndCompleteAttempt(
966      0, 5, net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID);
967
968  // Second portal detection attempt for wifi1 also uses 5sec timeout.
969  ASSERT_TRUE(is_state_portal_detection_pending());
970  base::RunLoop().RunUntilIdle();
971  CheckRequestTimeoutAndCompleteAttempt(1, 10, net::OK, 204);
972  ASSERT_TRUE(is_state_idle());
973
974  // Check that in error screen strategy detection for wifi1 15sec
975  // timeout is used.
976  enable_error_screen_strategy();
977  ASSERT_TRUE(is_state_portal_detection_pending());
978  base::RunLoop().RunUntilIdle();
979  CheckRequestTimeoutAndCompleteAttempt(0, 15, net::OK, 204);
980  disable_error_screen_strategy();
981  ASSERT_TRUE(is_state_portal_detection_pending());
982
983  ASSERT_TRUE(
984      MakeResultHistogramChecker()
985          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
986          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
987          ->Check());
988}
989
990TEST_F(NetworkPortalDetectorImplTest, StartDetectionIfIdle) {
991  ASSERT_TRUE(is_state_idle());
992  set_delay_till_next_attempt(base::TimeDelta());
993  SetConnected(kStubWireless1);
994
995  // First portal detection attempt for wifi1 uses 5sec timeout.
996  CheckRequestTimeoutAndCompleteAttempt(
997      0, 5, net::ERR_CONNECTION_CLOSED, net::URLFetcher::RESPONSE_CODE_INVALID);
998  ASSERT_TRUE(is_state_portal_detection_pending());
999  base::RunLoop().RunUntilIdle();
1000
1001  // Second portal detection attempt for wifi1 uses 10sec timeout.
1002  CheckRequestTimeoutAndCompleteAttempt(1,
1003                                        10,
1004                                        net::ERR_CONNECTION_CLOSED,
1005                                        net::URLFetcher::RESPONSE_CODE_INVALID);
1006  ASSERT_TRUE(is_state_portal_detection_pending());
1007  base::RunLoop().RunUntilIdle();
1008
1009  // Second portal detection attempt for wifi1 uses 15sec timeout.
1010  CheckRequestTimeoutAndCompleteAttempt(2,
1011                                        15,
1012                                        net::ERR_CONNECTION_CLOSED,
1013                                        net::URLFetcher::RESPONSE_CODE_INVALID);
1014  ASSERT_TRUE(is_state_idle());
1015  start_detection_if_idle();
1016
1017  ASSERT_TRUE(is_state_portal_detection_pending());
1018
1019  // First portal detection attempt for wifi1 uses 5sec timeout.
1020  base::RunLoop().RunUntilIdle();
1021  CheckRequestTimeoutAndCompleteAttempt(0, 5, net::OK, 204);
1022  ASSERT_TRUE(is_state_idle());
1023
1024  ASSERT_TRUE(
1025      MakeResultHistogramChecker()
1026          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE, 1)
1027          ->Expect(NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE, 1)
1028          ->Check());
1029}
1030
1031}  // namespace chromeos
1032