[go: nahoru, domu]

blob: f63d24a5caa98e40d4b0d686fb0721160ca8f321 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/network/public/cpp/cross_thread_pending_shared_url_loader_factory.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace network {
namespace {
const char kUrl[] = "http://www.example.com/";
const char kData[] = "payload!";
// Checks to make sure clone method is called on the right thread.
class CloneCheckingURLLoaderFactory : public TestURLLoaderFactory {
public:
explicit CloneCheckingURLLoaderFactory(
scoped_refptr<base::SequencedTaskRunner> owning_thread)
: owning_thread_(owning_thread) {}
void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) override {
EXPECT_TRUE(owning_thread_->RunsTasksInCurrentSequence());
}
private:
scoped_refptr<base::SequencedTaskRunner> owning_thread_;
};
} // namespace
// Base class with shared setup logic.
class CrossThreadPendingSharedURLLoaderFactoryTest : public ::testing::Test {
protected:
void SetUp() override {
main_thread_ = base::SequencedTaskRunnerHandle::Get();
loader_thread_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::WithBaseSyncPrimitives()});
test_url_loader_factory_ =
std::make_unique<CloneCheckingURLLoaderFactory>(loader_thread_);
test_url_loader_factory_->SetInterceptor(base::BindRepeating(
&CrossThreadPendingSharedURLLoaderFactoryTest::CheckLoaderThread,
base::Unretained(this)));
test_url_loader_factory_->AddResponse(kUrl, kData);
shared_factory_ = base::MakeRefCounted<WeakWrapperSharedURLLoaderFactory>(
test_url_loader_factory_.get());
base::RunLoop run_loop;
loader_thread_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(&CrossThreadPendingSharedURLLoaderFactoryTest::
SetupFactoryInfoOnLoaderThread,
base::Unretained(this)),
run_loop.QuitClosure());
run_loop.Run();
}
void TearDown() override {
task_environment_.RunUntilIdle();
// Release |shared_factory_| on |loader_thread_|
base::RunLoop run_loop;
loader_thread_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(&CrossThreadPendingSharedURLLoaderFactoryTest::
ReleaseSharedFactoryOnLoaderThread,
base::Unretained(this)),
run_loop.QuitClosure());
run_loop.Run();
}
void CheckLoaderThread(const ResourceRequest& request) {
EXPECT_TRUE(loader_thread_->RunsTasksInCurrentSequence());
}
void SetupFactoryInfoOnLoaderThread() {
DCHECK(loader_thread_->RunsTasksInCurrentSequence());
pending_factory_ =
std::make_unique<CrossThreadPendingSharedURLLoaderFactory>(
shared_factory_);
}
void ReleaseSharedFactoryOnLoaderThread() {
DCHECK(loader_thread_->RunsTasksInCurrentSequence());
shared_factory_ = nullptr;
}
void TestLoad(scoped_refptr<SharedURLLoaderFactory> factory,
scoped_refptr<base::SequencedTaskRunner> client_runner,
base::OnceClosure quit_closure) {
// Make sure we can fetch through |factory|, and that things are on proper
// threads (this is partly done by the CheckLoaderThread interceptor).
auto request = std::make_unique<ResourceRequest>();
request->url = GURL(kUrl);
std::unique_ptr<SimpleURLLoader> loader = SimpleURLLoader::Create(
std::move(request), TRAFFIC_ANNOTATION_FOR_TESTS);
SimpleURLLoader* loader_raw = loader.get();
loader_raw->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
factory.get(),
base::BindOnce(
[](scoped_refptr<base::SequencedTaskRunner> client_runner,
base::OnceClosure quit_closure,
std::unique_ptr<SimpleURLLoader> loader,
std::unique_ptr<std::string> result) {
EXPECT_TRUE(client_runner->RunsTasksInCurrentSequence());
if (!result) {
ADD_FAILURE();
} else {
EXPECT_EQ(kData, *result);
}
std::move(quit_closure).Run();
},
client_runner, std::move(quit_closure), std::move(loader)));
}
void TestClone(scoped_refptr<SharedURLLoaderFactory> factory) {
mojo::PendingRemote<mojom::URLLoaderFactory> factory_client;
factory->Clone(factory_client.InitWithNewPipeAndPassReceiver());
}
void TestLoadOnMainThread(scoped_refptr<SharedURLLoaderFactory> factory) {
base::RunLoop run_loop;
TestLoad(factory, main_thread_, run_loop.QuitClosure());
run_loop.Run();
}
base::test::TaskEnvironment task_environment_;
std::unique_ptr<CloneCheckingURLLoaderFactory> test_url_loader_factory_;
scoped_refptr<SharedURLLoaderFactory> shared_factory_;
scoped_refptr<base::SequencedTaskRunner> loader_thread_;
scoped_refptr<base::SequencedTaskRunner> main_thread_;
std::unique_ptr<CrossThreadPendingSharedURLLoaderFactory> pending_factory_;
};
TEST_F(CrossThreadPendingSharedURLLoaderFactoryTest, Basic) {
// Test with things created from |pending_factory_|.
scoped_refptr<SharedURLLoaderFactory> main_thread_factory =
SharedURLLoaderFactory::Create(std::move(pending_factory_));
TestLoadOnMainThread(main_thread_factory);
TestClone(main_thread_factory);
}
TEST_F(CrossThreadPendingSharedURLLoaderFactoryTest, FurtherClone) {
// Test load with result of a further clone.
scoped_refptr<SharedURLLoaderFactory> main_thread_factory =
SharedURLLoaderFactory::Create(std::move(pending_factory_));
scoped_refptr<SharedURLLoaderFactory> main_thread_factory_clone =
SharedURLLoaderFactory::Create(main_thread_factory->Clone());
TestLoadOnMainThread(main_thread_factory_clone);
TestLoadOnMainThread(main_thread_factory);
TestClone(main_thread_factory_clone);
TestClone(main_thread_factory);
}
TEST_F(CrossThreadPendingSharedURLLoaderFactoryTest, CloneThirdThread) {
// Clone to a third thread.
scoped_refptr<base::SequencedTaskRunner> third_thread =
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::WithBaseSyncPrimitives()});
scoped_refptr<SharedURLLoaderFactory> main_thread_factory =
SharedURLLoaderFactory::Create(std::move(pending_factory_));
std::unique_ptr<PendingSharedURLLoaderFactory> new_pending_factory =
main_thread_factory->Clone();
base::RunLoop run_loop;
base::OnceClosure run_loop_quit = run_loop.QuitClosure();
third_thread->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
scoped_refptr<SharedURLLoaderFactory> third_thread_factory =
SharedURLLoaderFactory::Create(std::move(new_pending_factory));
TestLoad(third_thread_factory, third_thread, std::move(run_loop_quit));
TestClone(third_thread_factory);
}));
run_loop.Run();
}
TEST_F(CrossThreadPendingSharedURLLoaderFactoryTest, CloneLoaderThread) {
// Clone back to the loader thread.
scoped_refptr<SharedURLLoaderFactory> main_thread_factory =
SharedURLLoaderFactory::Create(std::move(pending_factory_));
std::unique_ptr<PendingSharedURLLoaderFactory> new_pending_factory =
main_thread_factory->Clone();
base::RunLoop run_loop;
base::OnceClosure run_loop_quit = run_loop.QuitClosure();
loader_thread_->PostTask(
FROM_HERE, base::BindLambdaForTesting([&]() {
scoped_refptr<SharedURLLoaderFactory> load_thread_factory =
SharedURLLoaderFactory::Create(std::move(new_pending_factory));
TestLoad(load_thread_factory, loader_thread_, std::move(run_loop_quit));
TestClone(load_thread_factory);
}));
run_loop.Run();
}
} // namespace network