1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/compiler_specific.h"
6#include "base/macros.h"
7#include "base/message_loop/message_loop.h"
8#include "base/run_loop.h"
9#include "chrome/browser/browser_process.h"
10#include "chrome/browser/chromeos/login/login_manager_test.h"
11#include "chrome/browser/chromeos/login/startup_utils.h"
12#include "chrome/browser/chromeos/net/network_portal_detector_impl.h"
13#include "chrome/browser/chromeos/net/network_portal_detector_test_utils.h"
14#include "chromeos/chromeos_switches.h"
15#include "chromeos/dbus/dbus_thread_manager.h"
16#include "chromeos/dbus/shill_service_client.h"
17#include "chromeos/network/portal_detector/network_portal_detector.h"
18#include "chromeos/network/portal_detector/network_portal_detector_strategy.h"
19#include "components/captive_portal/captive_portal_testing_utils.h"
20#include "content/public/test/test_utils.h"
21#include "dbus/object_path.h"
22#include "third_party/cros_system_api/dbus/service_constants.h"
23#include "ui/message_center/message_center.h"
24#include "ui/message_center/message_center_observer.h"
25
26using base::MessageLoop;
27using message_center::MessageCenter;
28using message_center::MessageCenterObserver;
29
30namespace chromeos {
31
32namespace {
33
34const char* kNotificationId =
35    NetworkPortalNotificationController::kNotificationId;
36const char* kNotificationMetric =
37    NetworkPortalNotificationController::kNotificationMetric;
38const char* kUserActionMetric =
39    NetworkPortalNotificationController::kUserActionMetric;
40
41const char kTestUser[] = "test-user@gmail.com";
42const char kWifiServicePath[] = "/service/wifi";
43const char kWifiGuid[] = "wifi";
44
45void ErrorCallbackFunction(const std::string& error_name,
46                           const std::string& error_message) {
47  CHECK(false) << "Shill Error: " << error_name << " : " << error_message;
48}
49
50void SetConnected(const std::string& service_path) {
51  DBusThreadManager::Get()->GetShillServiceClient()->Connect(
52      dbus::ObjectPath(service_path),
53      base::Bind(&base::DoNothing),
54      base::Bind(&ErrorCallbackFunction));
55  base::RunLoop().RunUntilIdle();
56}
57
58class TestObserver : public MessageCenterObserver {
59 public:
60  TestObserver() : run_loop_(new base::RunLoop()) {
61    MessageCenter::Get()->AddObserver(this);
62  }
63
64  virtual ~TestObserver() {
65    MessageCenter::Get()->RemoveObserver(this);
66  }
67
68  void WaitAndReset() {
69    run_loop_->Run();
70    run_loop_.reset(new base::RunLoop());
71  }
72
73  virtual void OnNotificationDisplayed(
74      const std::string& notification_id,
75      const message_center::DisplaySource source)
76      OVERRIDE {
77    if (notification_id == kNotificationId)
78      MessageLoop::current()->PostTask(FROM_HERE, run_loop_->QuitClosure());
79  }
80
81  virtual void OnNotificationRemoved(const std::string& notification_id,
82                                     bool by_user) OVERRIDE {
83    if (notification_id == kNotificationId && by_user)
84      MessageLoop::current()->PostTask(FROM_HERE, run_loop_->QuitClosure());
85  }
86
87 private:
88  scoped_ptr<base::RunLoop> run_loop_;
89
90  DISALLOW_COPY_AND_ASSIGN(TestObserver);
91};
92
93}  // namespace
94
95class NetworkPortalDetectorImplBrowserTest
96    : public LoginManagerTest,
97      public captive_portal::CaptivePortalDetectorTestBase {
98 public:
99  NetworkPortalDetectorImplBrowserTest()
100      : LoginManagerTest(false), network_portal_detector_(NULL) {}
101  virtual ~NetworkPortalDetectorImplBrowserTest() {}
102
103  virtual void SetUpOnMainThread() OVERRIDE {
104    LoginManagerTest::SetUpOnMainThread();
105
106    ShillServiceClient::TestInterface* service_test =
107        DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
108    service_test->ClearServices();
109    service_test->AddService(kWifiServicePath,
110                             kWifiGuid,
111                             "wifi",
112                             shill::kTypeEthernet,
113                             shill::kStateIdle,
114                             true /* add_to_visible */);
115    DBusThreadManager::Get()->GetShillServiceClient()->SetProperty(
116        dbus::ObjectPath(kWifiServicePath),
117        shill::kStateProperty,
118        base::StringValue(shill::kStatePortal),
119        base::Bind(&base::DoNothing),
120        base::Bind(&ErrorCallbackFunction));
121
122    network_portal_detector_ = new NetworkPortalDetectorImpl(
123        g_browser_process->system_request_context());
124    NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
125    network_portal_detector_->Enable(false /* start_detection */);
126    set_detector(network_portal_detector_->captive_portal_detector_.get());
127    PortalDetectorStrategy::set_delay_till_next_attempt_for_testing(
128        base::TimeDelta());
129    base::RunLoop().RunUntilIdle();
130  }
131
132  void RestartDetection() {
133    network_portal_detector_->StopDetection();
134    network_portal_detector_->StartDetection();
135    base::RunLoop().RunUntilIdle();
136  }
137
138  PortalDetectorStrategy* strategy() {
139    return network_portal_detector_->strategy_.get();
140  }
141
142  MessageCenter* message_center() { return MessageCenter::Get(); }
143
144 private:
145  NetworkPortalDetectorImpl* network_portal_detector_;
146
147  DISALLOW_COPY_AND_ASSIGN(NetworkPortalDetectorImplBrowserTest);
148};
149
150IN_PROC_BROWSER_TEST_F(NetworkPortalDetectorImplBrowserTest,
151                       PRE_InSessionDetection) {
152  RegisterUser(kTestUser);
153  StartupUtils::MarkOobeCompleted();
154  ASSERT_EQ(PortalDetectorStrategy::STRATEGY_ID_LOGIN_SCREEN, strategy()->Id());
155}
156
157IN_PROC_BROWSER_TEST_F(NetworkPortalDetectorImplBrowserTest,
158                       InSessionDetection) {
159  typedef NetworkPortalNotificationController Controller;
160
161  TestObserver observer;
162
163  EnumHistogramChecker ui_checker(
164      kNotificationMetric, Controller::NOTIFICATION_METRIC_COUNT, NULL);
165  EnumHistogramChecker action_checker(
166      kUserActionMetric, Controller::USER_ACTION_METRIC_COUNT, NULL);
167
168  LoginUser(kTestUser);
169  content::RunAllPendingInMessageLoop();
170
171  // User connects to wifi.
172  SetConnected(kWifiServicePath);
173
174  ASSERT_EQ(PortalDetectorStrategy::STRATEGY_ID_SESSION, strategy()->Id());
175
176  // No notification until portal detection is completed.
177  ASSERT_FALSE(message_center()->FindVisibleNotificationById(kNotificationId));
178  RestartDetection();
179  CompleteURLFetch(net::OK, 200, NULL);
180
181  // Check that wifi is marked as behind the portal and that notification
182  // is displayed.
183  ASSERT_TRUE(message_center()->FindVisibleNotificationById(kNotificationId));
184  ASSERT_EQ(
185      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL,
186      NetworkPortalDetector::Get()->GetCaptivePortalState(kWifiGuid).status);
187
188  // Wait until notification is displayed.
189  observer.WaitAndReset();
190
191  ASSERT_TRUE(
192      ui_checker.Expect(Controller::NOTIFICATION_METRIC_DISPLAYED, 1)->Check());
193  ASSERT_TRUE(action_checker.Check());
194
195  // User explicitly closes the notification.
196  message_center()->RemoveNotification(kNotificationId, true);
197
198  // Wait until notification is closed.
199  observer.WaitAndReset();
200
201  ASSERT_TRUE(ui_checker.Check());
202  ASSERT_TRUE(
203      action_checker.Expect(Controller::USER_ACTION_METRIC_CLOSED, 1)->Check());
204}
205
206}  // namespace chromeos
207