blob: fbf9b250a40dabc9e59ed21670011a6dcbb249bd [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ios/chrome/browser/ssl/ios_ssl_error_handler.h"
#include "base/bind.h"
#include "base/run_loop.h"
#import "base/test/ios/wait_util.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
#import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
#include "ios/web/public/interstitials/web_interstitial.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#import "ios/web/public/web_state/web_state.h"
#include "net/http/http_status_code.h"
#include "net/ssl/ssl_info.h"
#include "net/test/cert_test_util.h"
#include "net/test/test_data_directory.h"
#include "services/network/test/test_url_loader_factory.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using base::test::ios::kWaitForUIElementTimeout;
using base::test::ios::WaitUntilConditionOrTimeout;
namespace {
const char kTestCertFileName[] = "ok_cert.pem";
const char kTestHostName[] = "https://chromium.test/";
} // namespace
// Test fixture for IOSSSLErrorHandler class.
class IOSSSLErrorHandlerTest : public web::WebTestWithWebState {
protected:
IOSSSLErrorHandlerTest()
: browser_state_(builder_.Build()),
cert_(net::ImportCertFromFile(net::GetTestCertsDirectory(),
kTestCertFileName)) {}
// web::WebTestWithWebState overrides:
void SetUp() override {
web::WebTestWithWebState::SetUp();
test_loader_factory_.AddResponse("http://www.gstatic.com/generate_204", "",
net::HTTP_NO_CONTENT);
id captive_portal_detector_tab_helper_delegate = [OCMockObject
mockForProtocol:@protocol(CaptivePortalDetectorTabHelperDelegate)];
// Use a testing URLLoaderFactory so that these tests don't attempt to make
// network requests.
CaptivePortalDetectorTabHelper::CreateForWebState(
web_state(), captive_portal_detector_tab_helper_delegate,
&test_loader_factory_);
ASSERT_TRUE(cert_);
ASSERT_FALSE(web_state()->IsShowingWebInterstitial());
// Transient item can only be added for pending non-app-specific loads.
AddPendingItem(GURL(kTestHostName),
ui::PageTransition::PAGE_TRANSITION_TYPED);
}
web::BrowserState* GetBrowserState() override { return browser_state_.get(); }
// Waits for and returns true if an interstitial is displayed. Returns false
// otherwise.
WARN_UNUSED_RESULT bool WaitForInterstitialDisplayed() {
// Required in order for CaptivePortalDetector to receive simulated network
// response from |test_loader_factory_|.
base::RunLoop().RunUntilIdle();
// Wait for the interstitial to be displayed.
return WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, ^{
return web_state()->IsShowingWebInterstitial();
});
}
// Returns certificate for testing.
scoped_refptr<net::X509Certificate> cert() { return cert_; }
private:
network::TestURLLoaderFactory test_loader_factory_;
TestChromeBrowserState::Builder builder_;
std::unique_ptr<TestChromeBrowserState> browser_state_;
scoped_refptr<net::X509Certificate> cert_;
};
// Tests non-overridable error handling.
TEST_F(IOSSSLErrorHandlerTest, NonOverridable) {
net::SSLInfo ssl_info;
ssl_info.cert = cert();
GURL url(kTestHostName);
__block bool do_not_proceed_callback_called = false;
IOSSSLErrorHandler::HandleSSLError(
web_state(), net::ERR_CERT_AUTHORITY_INVALID, ssl_info, url, false,
base::BindRepeating(^(bool proceed) {
EXPECT_FALSE(proceed);
do_not_proceed_callback_called = true;
}));
EXPECT_TRUE(WaitForInterstitialDisplayed());
web::WebInterstitial* interstitial = web_state()->GetWebInterstitial();
EXPECT_TRUE(interstitial);
// Make sure callback is called on dismissal.
interstitial->DontProceed();
EXPECT_TRUE(do_not_proceed_callback_called);
}
// Tests proceed with overridable error.
// Flaky: http://crbug.com/660343.
TEST_F(IOSSSLErrorHandlerTest, DISABLED_OverridableProceed) {
net::SSLInfo ssl_info;
ssl_info.cert = cert();
GURL url(kTestHostName);
__block bool proceed_callback_called = false;
IOSSSLErrorHandler::HandleSSLError(
web_state(), net::ERR_CERT_AUTHORITY_INVALID, ssl_info, url, true,
base::BindRepeating(^(bool proceed) {
EXPECT_TRUE(proceed);
proceed_callback_called = true;
}));
EXPECT_TRUE(WaitForInterstitialDisplayed());
web::WebInterstitial* interstitial = web_state()->GetWebInterstitial();
EXPECT_TRUE(interstitial);
// Make sure callback is called on dismissal.
interstitial->Proceed();
EXPECT_TRUE(proceed_callback_called);
}
// Tests do not proceed with overridable error.
TEST_F(IOSSSLErrorHandlerTest, OverridableDontProceed) {
net::SSLInfo ssl_info;
ssl_info.cert = cert();
GURL url(kTestHostName);
__block bool do_not_proceed_callback_called = false;
IOSSSLErrorHandler::HandleSSLError(
web_state(), net::ERR_CERT_AUTHORITY_INVALID, ssl_info, url, true,
base::BindRepeating(^(bool proceed) {
EXPECT_FALSE(proceed);
do_not_proceed_callback_called = true;
}));
EXPECT_TRUE(WaitForInterstitialDisplayed());
web::WebInterstitial* interstitial = web_state()->GetWebInterstitial();
EXPECT_TRUE(interstitial);
// Make sure callback is called on dismissal.
interstitial->DontProceed();
EXPECT_TRUE(do_not_proceed_callback_called);
}