1// Copyright (c) 2012 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/command_line.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/prefs/pref_service.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/chromeos/login/screens/mock_error_screen.h"
10#include "chrome/browser/chromeos/login/screens/mock_screen_observer.h"
11#include "chrome/browser/chromeos/login/screens/update_screen.h"
12#include "chrome/browser/chromeos/login/startup_utils.h"
13#include "chrome/browser/chromeos/login/test/wizard_in_process_browser_test.h"
14#include "chrome/browser/chromeos/login/wizard_controller.h"
15#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
16#include "chrome/common/pref_names.h"
17#include "chromeos/chromeos_switches.h"
18#include "chromeos/dbus/dbus_thread_manager.h"
19#include "chromeos/dbus/fake_update_engine_client.h"
20#include "chromeos/network/portal_detector/network_portal_detector.h"
21#include "testing/gmock/include/gmock/gmock.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using ::testing::AnyNumber;
25using ::testing::AtLeast;
26using ::testing::Exactly;
27using ::testing::Invoke;
28using ::testing::Return;
29using ::testing::_;
30
31namespace chromeos {
32
33namespace {
34
35const char kStubEthernetGuid[] = "eth0";
36const char kStubWifiGuid[] = "wlan0";
37
38}  // namespace
39
40class UpdateScreenTest : public WizardInProcessBrowserTest {
41 public:
42  UpdateScreenTest() : WizardInProcessBrowserTest("update"),
43                       fake_update_engine_client_(NULL),
44                       network_portal_detector_(NULL) {
45  }
46
47 protected:
48  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
49    fake_update_engine_client_ = new FakeUpdateEngineClient;
50    chromeos::DBusThreadManager::GetSetterForTesting()->SetUpdateEngineClient(
51        scoped_ptr<UpdateEngineClient>(fake_update_engine_client_));
52
53    WizardInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
54
55    // Setup network portal detector to return online state for both
56    // ethernet and wifi networks. Ethernet is an active network by
57    // default.
58    network_portal_detector_ = new NetworkPortalDetectorTestImpl();
59    NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
60    NetworkPortalDetector::CaptivePortalState online_state;
61    online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
62    online_state.response_code = 204;
63    SetDefaultNetwork(kStubEthernetGuid);
64    SetDetectionResults(kStubEthernetGuid, online_state);
65    SetDetectionResults(kStubWifiGuid, online_state);
66  }
67
68  virtual void SetUpOnMainThread() OVERRIDE {
69    WizardInProcessBrowserTest::SetUpOnMainThread();
70
71    mock_screen_observer_.reset(new MockScreenObserver());
72    mock_error_screen_actor_.reset(new MockErrorScreenActor());
73    mock_error_screen_.reset(
74        new MockErrorScreen(mock_screen_observer_.get(),
75                            mock_error_screen_actor_.get()));
76    EXPECT_CALL(*mock_screen_observer_, ShowCurrentScreen())
77        .Times(AnyNumber());
78    EXPECT_CALL(*mock_screen_observer_, GetErrorScreen())
79        .Times(AnyNumber())
80        .WillRepeatedly(Return(mock_error_screen_.get()));
81
82    ASSERT_TRUE(WizardController::default_controller() != NULL);
83    update_screen_ = UpdateScreen::Get(WizardController::default_controller());
84    ASSERT_TRUE(update_screen_ != NULL);
85    ASSERT_EQ(WizardController::default_controller()->current_screen(),
86              update_screen_);
87    update_screen_->screen_observer_ = mock_screen_observer_.get();
88  }
89
90  virtual void TearDownOnMainThread() OVERRIDE {
91    mock_error_screen_.reset();
92    mock_error_screen_actor_.reset();
93    WizardInProcessBrowserTest::TearDownOnMainThread();
94  }
95
96  virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
97    NetworkPortalDetector::Shutdown();
98    WizardInProcessBrowserTest::TearDownInProcessBrowserTestFixture();
99  }
100
101  void SetDefaultNetwork(const std::string& guid) {
102    DCHECK(network_portal_detector_);
103    network_portal_detector_->SetDefaultNetworkForTesting(guid);
104  }
105
106  void SetDetectionResults(
107      const std::string& guid,
108      const NetworkPortalDetector::CaptivePortalState& state) {
109    DCHECK(network_portal_detector_);
110    network_portal_detector_->SetDetectionResultsForTesting(guid, state);
111  }
112
113  void NotifyPortalDetectionCompleted() {
114    DCHECK(network_portal_detector_);
115    network_portal_detector_->NotifyObserversForTesting();
116  }
117
118  FakeUpdateEngineClient* fake_update_engine_client_;
119  scoped_ptr<MockScreenObserver> mock_screen_observer_;
120  scoped_ptr<MockErrorScreenActor> mock_error_screen_actor_;
121  scoped_ptr<MockErrorScreen> mock_error_screen_;
122  UpdateScreen* update_screen_;
123  NetworkPortalDetectorTestImpl* network_portal_detector_;
124
125 private:
126  DISALLOW_COPY_AND_ASSIGN(UpdateScreenTest);
127};
128
129IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestBasic) {
130  ASSERT_TRUE(update_screen_->actor_ != NULL);
131}
132
133IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestNoUpdate) {
134  update_screen_->SetIgnoreIdleStatus(true);
135  UpdateEngineClient::Status status;
136  status.status = UpdateEngineClient::UPDATE_STATUS_IDLE;
137  update_screen_->UpdateStatusChanged(status);
138  status.status = UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE;
139  update_screen_->UpdateStatusChanged(status);
140  status.status = UpdateEngineClient::UPDATE_STATUS_IDLE;
141  // GetLastStatus() will be called via ExitUpdate() called from
142  // UpdateStatusChanged().
143  fake_update_engine_client_->set_default_status(status);
144
145  EXPECT_CALL(*mock_screen_observer_, OnExit(ScreenObserver::UPDATE_NOUPDATE))
146      .Times(1);
147  update_screen_->UpdateStatusChanged(status);
148}
149
150IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateAvailable) {
151  update_screen_->is_ignore_update_deadlines_ = true;
152
153  UpdateEngineClient::Status status;
154  status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
155  status.new_version = "latest and greatest";
156  update_screen_->UpdateStatusChanged(status);
157
158  status.status = UpdateEngineClient::UPDATE_STATUS_DOWNLOADING;
159  status.download_progress = 0.0;
160  update_screen_->UpdateStatusChanged(status);
161
162  status.download_progress = 0.5;
163  update_screen_->UpdateStatusChanged(status);
164
165  status.download_progress = 1.0;
166  update_screen_->UpdateStatusChanged(status);
167
168  status.status = UpdateEngineClient::UPDATE_STATUS_VERIFYING;
169  update_screen_->UpdateStatusChanged(status);
170
171  status.status = UpdateEngineClient::UPDATE_STATUS_FINALIZING;
172  update_screen_->UpdateStatusChanged(status);
173
174  status.status = UpdateEngineClient::UPDATE_STATUS_UPDATED_NEED_REBOOT;
175  update_screen_->UpdateStatusChanged(status);
176  // UpdateStatusChanged(status) calls RebootAfterUpdate().
177  EXPECT_EQ(1, fake_update_engine_client_->reboot_after_update_call_count());
178  // Check that OOBE will resume back at this screen.
179  base::MessageLoop::current()->RunUntilIdle();
180  EXPECT_FALSE(StartupUtils::IsOobeCompleted());
181  EXPECT_EQ(update_screen_->GetName(),
182      g_browser_process->local_state()->GetString(prefs::kOobeScreenPending));
183}
184
185IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorIssuingUpdateCheck) {
186  // First, cancel the update that is already in progress.
187  EXPECT_CALL(*mock_screen_observer_,
188              OnExit(ScreenObserver::UPDATE_NOUPDATE))
189      .Times(1);
190  update_screen_->CancelUpdate();
191
192  fake_update_engine_client_->set_update_check_result(
193      chromeos::UpdateEngineClient::UPDATE_RESULT_FAILED);
194  EXPECT_CALL(*mock_screen_observer_,
195              OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE))
196      .Times(1);
197  update_screen_->StartNetworkCheck();
198}
199
200IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorCheckingForUpdate) {
201  UpdateEngineClient::Status status;
202  status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
203  // GetLastStatus() will be called via ExitUpdate() called from
204  // UpdateStatusChanged().
205  fake_update_engine_client_->set_default_status(status);
206
207  EXPECT_CALL(*mock_screen_observer_,
208              OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE))
209      .Times(1);
210  update_screen_->UpdateStatusChanged(status);
211}
212
213IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorUpdating) {
214  UpdateEngineClient::Status status;
215  status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE;
216  status.new_version = "latest and greatest";
217  // GetLastStatus() will be called via ExitUpdate() called from
218  // UpdateStatusChanged().
219  fake_update_engine_client_->set_default_status(status);
220
221  update_screen_->UpdateStatusChanged(status);
222
223  status.status = UpdateEngineClient::UPDATE_STATUS_ERROR;
224  // GetLastStatus() will be called via ExitUpdate() called from
225  // UpdateStatusChanged().
226  fake_update_engine_client_->set_default_status(status);
227
228  EXPECT_CALL(*mock_screen_observer_,
229              OnExit(ScreenObserver::UPDATE_ERROR_UPDATING))
230      .Times(1);
231  update_screen_->UpdateStatusChanged(status);
232}
233
234IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTemproraryOfflineNetwork) {
235  EXPECT_CALL(*mock_screen_observer_,
236              OnExit(ScreenObserver::UPDATE_NOUPDATE))
237      .Times(1);
238  update_screen_->CancelUpdate();
239
240  // Change ethernet state to portal.
241  NetworkPortalDetector::CaptivePortalState portal_state;
242  portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
243  portal_state.response_code = 200;
244  SetDetectionResults(kStubEthernetGuid, portal_state);
245
246  // Update screen will show error message about portal state because
247  // ethernet is behind captive portal.
248  EXPECT_CALL(*mock_error_screen_actor_,
249              SetUIState(ErrorScreen::UI_STATE_UPDATE))
250      .Times(1);
251  EXPECT_CALL(*mock_error_screen_actor_,
252              SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, std::string()))
253      .Times(1);
254  EXPECT_CALL(*mock_error_screen_actor_, FixCaptivePortal())
255      .Times(1);
256  EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen())
257      .Times(1);
258
259  update_screen_->StartNetworkCheck();
260
261  NetworkPortalDetector::CaptivePortalState online_state;
262  online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
263  online_state.response_code = 204;
264  SetDetectionResults(kStubEthernetGuid, online_state);
265
266  // Second notification from portal detector will be about online state,
267  // so update screen will hide error message and proceed to update.
268  EXPECT_CALL(*mock_screen_observer_, HideErrorScreen(update_screen_))
269      .Times(1);
270  fake_update_engine_client_->set_update_check_result(
271      chromeos::UpdateEngineClient::UPDATE_RESULT_FAILED);
272
273  EXPECT_CALL(*mock_screen_observer_,
274              OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE))
275      .Times(1);
276
277  NotifyPortalDetectionCompleted();
278}
279
280IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTwoOfflineNetworks) {
281  EXPECT_CALL(*mock_screen_observer_,
282              OnExit(ScreenObserver::UPDATE_NOUPDATE))
283      .Times(1);
284  update_screen_->CancelUpdate();
285
286  // Change ethernet state to portal.
287  NetworkPortalDetector::CaptivePortalState portal_state;
288  portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
289  portal_state.response_code = 200;
290  SetDetectionResults(kStubEthernetGuid, portal_state);
291
292  // Update screen will show error message about portal state because
293  // ethernet is behind captive portal.
294  EXPECT_CALL(*mock_error_screen_actor_,
295              SetUIState(ErrorScreen::UI_STATE_UPDATE))
296      .Times(1);
297  EXPECT_CALL(*mock_error_screen_actor_,
298              SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, std::string()))
299      .Times(1);
300  EXPECT_CALL(*mock_error_screen_actor_, FixCaptivePortal())
301      .Times(1);
302  EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen())
303      .Times(1);
304
305  update_screen_->StartNetworkCheck();
306
307  // Change active network to the wifi behind proxy.
308  NetworkPortalDetector::CaptivePortalState proxy_state;
309  proxy_state.status =
310      NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED;
311  proxy_state.response_code = -1;
312  SetDefaultNetwork(kStubWifiGuid);
313  SetDetectionResults(kStubWifiGuid, proxy_state);
314
315  // Update screen will show message about proxy error because wifie
316  // network requires proxy authentication.
317  EXPECT_CALL(*mock_error_screen_actor_,
318              SetErrorState(ErrorScreen::ERROR_STATE_PROXY, std::string()))
319      .Times(1);
320
321  NotifyPortalDetectionCompleted();
322}
323
324IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestVoidNetwork) {
325  SetDefaultNetwork(std::string());
326
327  // Cancels pending update request.
328  EXPECT_CALL(*mock_screen_observer_,
329              OnExit(ScreenObserver::UPDATE_NOUPDATE))
330      .Times(1);
331  update_screen_->CancelUpdate();
332
333  // First portal detection attempt returns NULL network and undefined
334  // results, so detection is restarted.
335  EXPECT_CALL(*mock_error_screen_actor_,
336              SetUIState(_))
337      .Times(Exactly(0));
338  EXPECT_CALL(*mock_error_screen_actor_,
339              SetErrorState(_, _))
340      .Times(Exactly(0));
341  EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen())
342      .Times(Exactly(0));
343  update_screen_->StartNetworkCheck();
344
345  // Second portal detection also returns NULL network and undefined
346  // results.  In this case, offline message should be displayed.
347  EXPECT_CALL(*mock_error_screen_actor_,
348              SetUIState(ErrorScreen::UI_STATE_UPDATE))
349      .Times(1);
350  EXPECT_CALL(*mock_error_screen_actor_,
351              SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE, std::string()))
352      .Times(1);
353  EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen())
354      .Times(1);
355  base::MessageLoop::current()->RunUntilIdle();
356  NotifyPortalDetectionCompleted();
357}
358
359IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestAPReselection) {
360  EXPECT_CALL(*mock_screen_observer_,
361              OnExit(ScreenObserver::UPDATE_NOUPDATE))
362      .Times(1);
363  update_screen_->CancelUpdate();
364
365  // Change ethernet state to portal.
366  NetworkPortalDetector::CaptivePortalState portal_state;
367  portal_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL;
368  portal_state.response_code = 200;
369  SetDetectionResults(kStubEthernetGuid, portal_state);
370
371  // Update screen will show error message about portal state because
372  // ethernet is behind captive portal.
373  EXPECT_CALL(*mock_error_screen_actor_,
374              SetUIState(ErrorScreen::UI_STATE_UPDATE))
375      .Times(1);
376  EXPECT_CALL(*mock_error_screen_actor_,
377              SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, std::string()))
378      .Times(1);
379  EXPECT_CALL(*mock_error_screen_actor_, FixCaptivePortal())
380      .Times(1);
381  EXPECT_CALL(*mock_screen_observer_, ShowErrorScreen())
382      .Times(1);
383
384  update_screen_->StartNetworkCheck();
385
386  // User re-selects the same network manually. In this case, hide
387  // offline message and skip network check. Since ethernet is still
388  // behind portal, update engine fails to update.
389  EXPECT_CALL(*mock_screen_observer_, HideErrorScreen(update_screen_))
390      .Times(1);
391  fake_update_engine_client_->set_update_check_result(
392      chromeos::UpdateEngineClient::UPDATE_RESULT_FAILED);
393  EXPECT_CALL(*mock_screen_observer_,
394              OnExit(ScreenObserver::UPDATE_ERROR_CHECKING_FOR_UPDATE))
395      .Times(1);
396
397  update_screen_->OnConnectToNetworkRequested();
398  base::MessageLoop::current()->RunUntilIdle();
399}
400
401}  // namespace chromeos
402