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 11 using chrome_common_net::DnsProbeStatus; 12 using chrome_common_net::DnsProbeStatusToString; 13 14 // NetErrorHelperTest cases consist of a string of these steps. 15 enum 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 30 class 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 77 class 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 114 void 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 185 TEST_F(NetErrorHelperTest, Null) { 186 // Test that we can simply create and destroy a NetErrorHelper. 187 } 188 189 TEST_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 199 TEST_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 211 TEST_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 223 TEST_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 231 TEST_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 239 TEST_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 247 TEST_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 255 TEST_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 263 TEST_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 271 TEST_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 279 TEST_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 287 TEST_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 295 TEST_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 303 TEST_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 311 TEST_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 319 TEST_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 327 TEST_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 335 TEST_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 344 TEST_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 352 TEST_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 360 TEST_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 368 TEST_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 376 TEST_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 384 TEST_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 393 TEST_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 404 TEST_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