1// Copyright 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 "chrome/renderer/net/net_error_helper.h"
6
7#include "base/logging.h"
8#include "chrome/common/net/net_error_info.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11using chrome_common_net::DnsProbeStatus;
12using chrome_common_net::DnsProbeStatusToString;
13
14// NetErrorHelperTest cases consist of a string of these steps.
15enum TestStep {
16  // Simulate a provisional load start, fail, commit or a finish-load event.
17  // (Start and fail differentiate between normal and error pages.)
18  LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START,
19  LOAD_COMMIT, LOAD_FINISH,
20
21  // Simulate an IPC from the browser with DNS_PROBE_STARTED, _NOT_RUN, or
22  // _FINISHED_NXDOMAIN.
23  STATUS_STARTED, STATUS_NOT_RUN, STATUS_FINISHED,
24
25  // Expect that the *next* step will cause an update.  (Any step that is not
26  // prefixed by this pseudo-step is expected *not* to cause an update.)
27  EXPECT_UPDATE
28};
29
30class TestNetErrorHelper : public NetErrorHelper {
31 public:
32  TestNetErrorHelper()
33      : NetErrorHelper(NULL),
34        mock_page_update_count_(0),
35        mock_displayed_probe_status_(chrome_common_net::DNS_PROBE_MAX) {}
36
37  virtual ~TestNetErrorHelper() {}
38
39  void StartLoad(bool is_main_frame, bool is_error_page) {
40    OnStartLoad(is_main_frame, is_error_page);
41  }
42
43  void FailLoad(bool is_main_frame, bool is_dns_error) {
44    OnFailLoad(is_main_frame, is_dns_error);
45  }
46
47  void CommitLoad(bool is_main_frame) {
48    OnCommitLoad(is_main_frame);
49  }
50
51  void FinishLoad(bool is_main_frame) {
52    OnFinishLoad(is_main_frame);
53  }
54
55  void ReceiveProbeStatus(DnsProbeStatus status) {
56    OnNetErrorInfo(static_cast<int>(status));
57  }
58
59  int mock_page_update_count() const { return mock_page_update_count_;  }
60  DnsProbeStatus mock_displayed_probe_status() const {
61    return mock_displayed_probe_status_;
62  }
63
64 protected:
65  virtual void UpdateErrorPage() OVERRIDE {
66    DVLOG(1) << "Updating error page with status "
67             << DnsProbeStatusToString(last_probe_status_);
68    mock_page_update_count_++;
69    mock_displayed_probe_status_ = last_probe_status_;
70  }
71
72 private:
73  int mock_page_update_count_;
74  DnsProbeStatus mock_displayed_probe_status_;
75};
76
77class NetErrorHelperTest : public testing::Test {
78 protected:
79  enum MainFrame { SUB_FRAME, MAIN_FRAME };
80  enum ErrorPage { NORMAL_PAGE, ERROR_PAGE };
81  enum ErrorType { OTHER_ERROR, DNS_ERROR };
82
83  void StartLoad(MainFrame main_frame, ErrorPage error_page) {
84    helper_.StartLoad(main_frame == MAIN_FRAME, error_page == ERROR_PAGE);
85  }
86
87  void FailLoad(MainFrame main_frame, ErrorType error_type) {
88    helper_.FailLoad(main_frame == MAIN_FRAME, error_type == DNS_ERROR);
89  }
90
91  void CommitLoad(MainFrame main_frame) {
92    helper_.CommitLoad(main_frame == MAIN_FRAME);
93  }
94
95  void FinishLoad(MainFrame main_frame) {
96    helper_.FinishLoad(main_frame == MAIN_FRAME);
97  }
98
99  void ReceiveProbeStatus(DnsProbeStatus status) {
100    helper_.ReceiveProbeStatus(status);
101  }
102
103  void RunTest(const TestStep steps[], int step_count);
104
105  int page_update_count() const { return helper_.mock_page_update_count(); }
106  DnsProbeStatus displayed_probe_status() const {
107    return helper_.mock_displayed_probe_status();
108  }
109
110 private:
111  TestNetErrorHelper helper_;
112};
113
114void NetErrorHelperTest::RunTest(const TestStep steps[], int step_count) {
115  // Whether the next instruction is expected to cause an update (since the
116  // step right before it was EXPECT_UPDATE) or not.
117  bool update_expected = false;
118  int expected_update_count = page_update_count();
119  // The last status that the test simulated receiving from the browser.
120  // When an update is expected, the status is expected to match this.
121  chrome_common_net::DnsProbeStatus last_status_received =
122      chrome_common_net::DNS_PROBE_POSSIBLE;
123
124  for (int i = 0; i < step_count; i++) {
125    switch (steps[i]) {
126    case LOAD_NORMAL_START:
127      StartLoad(MAIN_FRAME, NORMAL_PAGE);
128      break;
129    case LOAD_NORMAL_FAIL:
130      FailLoad(MAIN_FRAME, DNS_ERROR);
131      break;
132    case LOAD_ERROR_START:
133      StartLoad(MAIN_FRAME, ERROR_PAGE);
134      break;
135    case LOAD_COMMIT:
136      CommitLoad(MAIN_FRAME);
137      break;
138    case LOAD_FINISH:
139      FinishLoad(MAIN_FRAME);
140      break;
141    case STATUS_STARTED:
142      ReceiveProbeStatus(chrome_common_net::DNS_PROBE_STARTED);
143      last_status_received = chrome_common_net::DNS_PROBE_STARTED;
144      break;
145    case STATUS_NOT_RUN:
146      ReceiveProbeStatus(chrome_common_net::DNS_PROBE_NOT_RUN);
147      last_status_received = chrome_common_net::DNS_PROBE_NOT_RUN;
148      break;
149    case STATUS_FINISHED:
150      ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN);
151      last_status_received = chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN;
152      break;
153    case EXPECT_UPDATE:
154      ASSERT_FALSE(update_expected);
155      update_expected = true;
156      // Skip to next step to see if it updates the status, instead of
157      // checking whether EXPECT_UPDATE itself caused an update.
158      continue;
159    }
160
161    if (update_expected) {
162      DCHECK_NE(chrome_common_net::DNS_PROBE_POSSIBLE, last_status_received);
163      ++expected_update_count;
164
165      EXPECT_EQ(last_status_received, displayed_probe_status());
166      if (displayed_probe_status() != last_status_received) {
167        LOG(ERROR) << "Unexpected status at step " << i << ".";
168        return;
169      }
170    }
171
172    EXPECT_EQ(expected_update_count, page_update_count());
173    if (page_update_count() != expected_update_count) {
174      LOG(ERROR) << (update_expected ? "Missing" : "Spurious")
175                 << " update at step " << i << ".";
176      return;
177    }
178
179    update_expected = false;
180  }
181
182  DCHECK(!update_expected);
183}
184
185TEST_F(NetErrorHelperTest, Null) {
186  // Test that we can simply create and destroy a NetErrorHelper.
187}
188
189TEST_F(NetErrorHelperTest, SuccessfulPageLoad) {
190  StartLoad(MAIN_FRAME, NORMAL_PAGE);
191  CommitLoad(MAIN_FRAME);
192  FinishLoad(MAIN_FRAME);
193
194  // Ignore spurious status.
195  ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN);
196  EXPECT_EQ(0, page_update_count());
197}
198
199TEST_F(NetErrorHelperTest, MainFrameNonDnsError) {
200  StartLoad(MAIN_FRAME, NORMAL_PAGE);
201  FailLoad(MAIN_FRAME, OTHER_ERROR);
202  StartLoad(MAIN_FRAME, ERROR_PAGE);
203  CommitLoad(MAIN_FRAME);
204  FinishLoad(MAIN_FRAME);
205
206  // Ignore spurious status.
207  ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN);
208  EXPECT_EQ(0, page_update_count());
209}
210
211TEST_F(NetErrorHelperTest, SubFrameDnsError) {
212  StartLoad(SUB_FRAME, NORMAL_PAGE);
213  FailLoad(SUB_FRAME, DNS_ERROR);
214  StartLoad(SUB_FRAME, ERROR_PAGE);
215  CommitLoad(SUB_FRAME);
216  FinishLoad(SUB_FRAME);
217
218  // Ignore spurious status.
219  ReceiveProbeStatus(chrome_common_net::DNS_PROBE_FINISHED_NXDOMAIN);
220  EXPECT_EQ(0, page_update_count());
221}
222
223TEST_F(NetErrorHelperTest, FinishedAfterFail) {
224  const TestStep steps[] = {
225    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_FINISHED, LOAD_ERROR_START,
226    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
227  };
228  RunTest(steps, arraysize(steps));
229}
230
231TEST_F(NetErrorHelperTest, FinishedAfterFail_StartedAfterFail) {
232  const TestStep steps[] = {
233    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, STATUS_FINISHED,
234    LOAD_ERROR_START, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
235  };
236  RunTest(steps, arraysize(steps));
237}
238
239TEST_F(NetErrorHelperTest, FinishedAfterStart) {
240  const TestStep steps[] = {
241    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_FINISHED,
242    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
243  };
244  RunTest(steps, arraysize(steps));
245}
246
247TEST_F(NetErrorHelperTest, FinishedAfterStart_StartedAfterFail) {
248  const TestStep steps[] = {
249    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
250    STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
251  };
252  RunTest(steps, arraysize(steps));
253}
254
255TEST_F(NetErrorHelperTest, FinishedAfterStart_StartedAfterStart) {
256  const TestStep steps[] = {
257    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
258    STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
259  };
260  RunTest(steps, arraysize(steps));
261}
262
263TEST_F(NetErrorHelperTest, FinishedAfterCommit) {
264  const TestStep steps[] = {
265    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
266    STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH
267  };
268  RunTest(steps, arraysize(steps));
269}
270
271TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterFail) {
272  const TestStep steps[] = {
273    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
274    LOAD_COMMIT, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH
275  };
276  RunTest(steps, arraysize(steps));
277}
278
279TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterStart) {
280  const TestStep steps[] = {
281    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_STARTED,
282    LOAD_ERROR_START, LOAD_COMMIT, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH
283  };
284  RunTest(steps, arraysize(steps));
285}
286
287TEST_F(NetErrorHelperTest, FinishedAfterCommit_StartedAfterCommit) {
288  const TestStep steps[] = {
289    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
290    STATUS_STARTED, STATUS_FINISHED, EXPECT_UPDATE, LOAD_FINISH
291  };
292  RunTest(steps, arraysize(steps));
293}
294
295TEST_F(NetErrorHelperTest, FinishedAfterFinish) {
296  const TestStep steps[] = {
297    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
298    LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED
299  };
300  RunTest(steps, arraysize(steps));
301}
302
303TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterFail) {
304  const TestStep steps[] = {
305    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
306    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED
307  };
308  RunTest(steps, arraysize(steps));
309}
310
311TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterStart) {
312  const TestStep steps[] = {
313    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_STARTED,
314    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED
315  };
316  RunTest(steps, arraysize(steps));
317}
318
319TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterCommit) {
320  const TestStep steps[] = {
321    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
322    STATUS_STARTED, EXPECT_UPDATE, LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED
323  };
324  RunTest(steps, arraysize(steps));
325}
326
327TEST_F(NetErrorHelperTest, FinishedAfterFinish_StartAfterFinish) {
328  const TestStep steps[] = {
329    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
330    LOAD_FINISH, EXPECT_UPDATE, STATUS_STARTED, EXPECT_UPDATE, STATUS_FINISHED
331  };
332  RunTest(steps, arraysize(steps));
333}
334
335TEST_F(NetErrorHelperTest, FinishedAfterNewStart) {
336  const TestStep steps[] = {
337    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
338    LOAD_FINISH, LOAD_NORMAL_START, EXPECT_UPDATE, STATUS_FINISHED,
339    LOAD_COMMIT, LOAD_FINISH
340  };
341  RunTest(steps, arraysize(steps));
342}
343
344TEST_F(NetErrorHelperTest, NotRunAfterFail) {
345  const TestStep steps[] = {
346    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_NOT_RUN, LOAD_ERROR_START,
347    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
348  };
349  RunTest(steps, arraysize(steps));
350}
351
352TEST_F(NetErrorHelperTest, NotRunAfterStart) {
353  const TestStep steps[] = {
354    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, STATUS_NOT_RUN,
355    LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
356  };
357  RunTest(steps, arraysize(steps));
358}
359
360TEST_F(NetErrorHelperTest, NotRunAfterCommit) {
361  const TestStep steps[] = {
362    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
363    STATUS_NOT_RUN, EXPECT_UPDATE, LOAD_FINISH
364  };
365  RunTest(steps, arraysize(steps));
366}
367
368TEST_F(NetErrorHelperTest, NotRunAfterFinish) {
369  const TestStep steps[] = {
370    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
371    LOAD_FINISH, EXPECT_UPDATE, STATUS_NOT_RUN
372  };
373  RunTest(steps, arraysize(steps));
374}
375
376TEST_F(NetErrorHelperTest, FinishedAfterNewCommit) {
377  const TestStep steps[] = {
378    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
379    LOAD_FINISH, LOAD_NORMAL_START, LOAD_COMMIT, STATUS_FINISHED, LOAD_FINISH
380  };
381  RunTest(steps, arraysize(steps));
382}
383
384TEST_F(NetErrorHelperTest, FinishedAfterNewFinish) {
385  const TestStep steps[] = {
386    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
387    LOAD_FINISH, LOAD_NORMAL_START, LOAD_COMMIT, LOAD_FINISH, STATUS_FINISHED
388  };
389  RunTest(steps, arraysize(steps));
390}
391
392// Two iterations of FinishedAfterStart_StartAfterFail
393TEST_F(NetErrorHelperTest, TwoProbes_FinishedAfterStart_StartAfterFail) {
394  const TestStep steps[] = {
395    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
396    STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH,
397    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, STATUS_STARTED, LOAD_ERROR_START,
398    STATUS_FINISHED, LOAD_COMMIT, EXPECT_UPDATE, LOAD_FINISH
399  };
400  RunTest(steps, arraysize(steps));
401}
402
403// Two iterations of FinishedAfterFinish
404TEST_F(NetErrorHelperTest, TwoProbes_FinishedAfterFinish) {
405  const TestStep steps[] = {
406    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
407    LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED,
408    LOAD_NORMAL_START, LOAD_NORMAL_FAIL, LOAD_ERROR_START, LOAD_COMMIT,
409    LOAD_FINISH, EXPECT_UPDATE, STATUS_FINISHED
410  };
411  RunTest(steps, arraysize(steps));
412}
413