blob: a3b91fb972d1e1531b528d3c81db7ac0733833ed [file] [log] [blame]
// Copyright 2017 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 "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/storage_partition_impl.h"
#include "content/browser/url_loader_factory_getter.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/common/simple_url_loader.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/simple_url_loader_test_helper.h"
#include "content/shell/browser/shell.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/interfaces/network_service.mojom.h"
namespace content {
namespace {
network::mojom::NetworkContextPtr CreateNetworkContext() {
network::mojom::NetworkContextPtr network_context;
network::mojom::NetworkContextParamsPtr context_params =
network::mojom::NetworkContextParams::New();
GetNetworkService()->CreateNetworkContext(mojo::MakeRequest(&network_context),
std::move(context_params));
return network_context;
}
int LoadBasicRequestOnIOThread(
URLLoaderFactoryGetter* url_loader_factory_getter,
const GURL& url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto request = std::make_unique<network::ResourceRequest>();
request->url = url;
SimpleURLLoaderTestHelper simple_loader_helper;
// Wait for callback on UI thread to avoid nesting IO message loops.
simple_loader_helper.SetRunLoopQuitThread(BrowserThread::UI);
std::unique_ptr<content::SimpleURLLoader> simple_loader =
content::SimpleURLLoader::Create(std::move(request),
TRAFFIC_ANNOTATION_FOR_TESTS);
// |URLLoaderFactoryGetter::GetNetworkFactory()| can only be accessed on IO
// thread.
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::BindOnce(
[](content::SimpleURLLoader* loader,
URLLoaderFactoryGetter* factory_getter,
SimpleURLLoader::BodyAsStringCallback body_as_string_callback) {
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
factory_getter->GetNetworkFactory(),
std::move(body_as_string_callback));
},
base::Unretained(simple_loader.get()),
base::Unretained(url_loader_factory_getter),
simple_loader_helper.GetCallback()));
simple_loader_helper.WaitForCallback();
return simple_loader->NetError();
}
} // namespace
// This test source has been excluded from Android as Android doesn't have
// out-of-process Network Service.
class NetworkServiceRestartBrowserTest : public ContentBrowserTest {
public:
NetworkServiceRestartBrowserTest() {
scoped_feature_list_.InitAndEnableFeature(features::kNetworkService);
EXPECT_TRUE(embedded_test_server()->Start());
}
GURL GetTestURL() const {
// Use '/echoheader' instead of '/echo' to avoid a disk_cache bug.
// See https://crbug.com/792255.
return embedded_test_server()->GetURL("/echoheader");
}
BrowserContext* browser_context() {
return shell()->web_contents()->GetBrowserContext();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(NetworkServiceRestartBrowserTest);
};
IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
NetworkServiceProcessRecovery) {
network::mojom::NetworkContextPtr network_context = CreateNetworkContext();
EXPECT_EQ(net::OK, LoadBasicRequest(network_context.get(), GetTestURL()));
EXPECT_TRUE(network_context.is_bound());
EXPECT_FALSE(network_context.encountered_error());
// Crash the NetworkService process. Existing interfaces should receive error
// notifications at some point.
SimulateNetworkServiceCrash();
// |network_context| will receive an error notification, but it's not
// guaranteed to have arrived at this point. Flush the pointer to make sure
// the notification has been received.
network_context.FlushForTesting();
EXPECT_TRUE(network_context.is_bound());
EXPECT_TRUE(network_context.encountered_error());
// Make sure we could get |net::ERR_FAILED| with an invalid |network_context|.
EXPECT_EQ(net::ERR_FAILED,
LoadBasicRequest(network_context.get(), GetTestURL()));
// NetworkService should restart automatically and return valid interface.
network::mojom::NetworkContextPtr network_context2 = CreateNetworkContext();
EXPECT_EQ(net::OK, LoadBasicRequest(network_context2.get(), GetTestURL()));
EXPECT_TRUE(network_context2.is_bound());
EXPECT_FALSE(network_context2.encountered_error());
}
// Make sure |StoragePartitionImpl::GetNetworkContext()| returns valid interface
// after crash.
IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
StoragePartitionImplGetNetworkContext) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
network::mojom::NetworkContext* old_network_context =
partition->GetNetworkContext();
EXPECT_EQ(net::OK, LoadBasicRequest(old_network_context, GetTestURL()));
// Crash the NetworkService process. Existing interfaces should receive error
// notifications at some point.
SimulateNetworkServiceCrash();
// Flush the interface to make sure the error notification was received.
partition->FlushNetworkInterfaceForTesting();
// |partition->GetNetworkContext()| should return a valid new pointer after
// crash.
EXPECT_NE(old_network_context, partition->GetNetworkContext());
EXPECT_EQ(net::OK,
LoadBasicRequest(partition->GetNetworkContext(), GetTestURL()));
}
// Make sure |URLLoaderFactoryGetter| returns valid interface after crash.
IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
URLLoaderFactoryGetterGetNetworkFactory) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter =
partition->url_loader_factory_getter();
EXPECT_EQ(net::OK, LoadBasicRequestOnIOThread(url_loader_factory_getter.get(),
GetTestURL()));
// Crash the NetworkService process. Existing interfaces should receive error
// notifications at some point.
SimulateNetworkServiceCrash();
// Flush the interface to make sure the error notification was received.
partition->FlushNetworkInterfaceForTesting();
url_loader_factory_getter->FlushNetworkInterfaceOnIOThreadForTesting();
// |url_loader_factory_getter| should be able to get a valid new pointer after
// crash.
EXPECT_EQ(net::OK, LoadBasicRequestOnIOThread(url_loader_factory_getter.get(),
GetTestURL()));
}
// Make sure basic navigation works after crash.
IN_PROC_BROWSER_TEST_F(NetworkServiceRestartBrowserTest,
NavigationURLLoaderBasic) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
BrowserContext::GetDefaultStoragePartition(browser_context()));
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title1.html")));
// Crash the NetworkService process. Existing interfaces should receive error
// notifications at some point.
SimulateNetworkServiceCrash();
// Flush the interface to make sure the error notification was received.
partition->FlushNetworkInterfaceForTesting();
partition->url_loader_factory_getter()
->FlushNetworkInterfaceOnIOThreadForTesting();
EXPECT_TRUE(
NavigateToURL(shell(), embedded_test_server()->GetURL("/title2.html")));
}
} // namespace content