Commit d1fb11bd authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[content-service] Add FakeNavigableContentsFactory

Adds a new test support library with a single helper class,
FakeNavigableContentsFactory. This allows unit test code to fake out a
basic Content Service implementation to help drive Content Service
client code under test.

Bug: 854367
Change-Id: I3e81aa7b6540aa35347e6c3311c0f816cb945a01
Reviewed-on: https://chromium-review.googlesource.com/c/1277960
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604853}
parent 9c4cb797
......@@ -69,6 +69,7 @@ source_set("tests") {
"//base",
"//base/test:test_support",
"//services/content/public/cpp",
"//services/content/public/cpp/test:tests",
"//services/content/public/mojom",
"//services/service_manager/public/cpp/test:test_support",
"//testing/gtest",
......
......@@ -79,6 +79,7 @@ class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView {
#endif // defined(TOOLKIT_VIEWS) && defined(USE_AURA)
private:
friend class FakeNavigableContents;
friend class NavigableContents;
friend class NavigableContentsImpl;
......
# Copyright 2018 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.
source_set("test_support") {
testonly = true
sources = [
"fake_navigable_contents.cc",
"fake_navigable_contents.h",
"fake_navigable_contents_factory.cc",
"fake_navigable_contents_factory.h",
]
public_deps = [
"//base",
"//base/test:test_support",
"//mojo/public/cpp/bindings",
"//services/content/public/cpp",
"//services/content/public/mojom",
]
}
source_set("tests") {
testonly = true
sources = [
"fake_navigable_contents_factory_unittest.cc",
]
deps = [
":test_support",
"//base",
"//base/test:test_support",
"//net",
"//services/content/public/cpp",
"//services/content/public/mojom",
"//testing/gtest",
"//url",
]
}
// Copyright 2018 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 "services/content/public/cpp/test/fake_navigable_contents.h"
#include "base/bind.h"
#include "base/unguessable_token.h"
#include "services/content/public/cpp/navigable_contents_view.h"
#include "services/content/public/cpp/test/fake_navigable_contents_factory.h"
namespace content {
FakeNavigableContents::FakeNavigableContents() {
// This test-only object should only be used in environments where there is
// no Content Service. Hence we let the client think it's running in the
// same process as this service. This makes it easier to support fake
// behavior. Only needs to be called once, but there's no harm in calling it
// multiple times. This is more convenient.
NavigableContentsView::SetClientRunningInServiceProcess();
}
FakeNavigableContents::~FakeNavigableContents() = default;
void FakeNavigableContents::Bind(mojom::NavigableContentsRequest request,
mojom::NavigableContentsClientPtr client) {
binding_.Bind(std::move(request));
client_ = std::move(client);
}
void FakeNavigableContents::Navigate(const GURL& url,
mojom::NavigateParamsPtr params) {
client_->DidFinishNavigation(url, true /* is_main_frame */,
false /* is_error_page */,
default_response_headers_);
client_->DidStopLoading();
}
void FakeNavigableContents::CreateView(bool in_service_process,
CreateViewCallback callback) {
auto token = base::UnguessableToken::Create();
NavigableContentsView::RegisterInProcessEmbedCallback(token,
base::DoNothing());
std::move(callback).Run(token);
}
} // namespace content
// Copyright 2018 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.
#ifndef SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_H_
#define SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/http/http_response_headers.h"
#include "services/content/public/mojom/navigable_contents.mojom.h"
namespace content {
// Implementation of NavigableContents to be used by tests in conjunction with
// FakeNavigableContentsFactory.
class FakeNavigableContents : public mojom::NavigableContents {
public:
FakeNavigableContents();
~FakeNavigableContents() override;
// Set response headers to provide in calls to |DidFinishNavigation()| on any
// NavigableContentsClient when driven by a call to
// |NavigableContents::Navigate()|.
void set_default_response_headers(
const scoped_refptr<net::HttpResponseHeaders> headers) {
default_response_headers_ = headers;
}
// Binds this object to a NavigableContents request and gives it a
// corresponding client interface. May only be called once.
void Bind(mojom::NavigableContentsRequest request,
mojom::NavigableContentsClientPtr client);
private:
// mojom::NavigableContents:
void Navigate(const GURL& url, mojom::NavigateParamsPtr params) override;
void CreateView(bool in_service_process,
CreateViewCallback callback) override;
mojo::Binding<mojom::NavigableContents> binding_{this};
mojom::NavigableContentsClientPtr client_;
scoped_refptr<net::HttpResponseHeaders> default_response_headers_;
DISALLOW_COPY_AND_ASSIGN(FakeNavigableContents);
};
} // namespace content
#endif // SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_H_
// Copyright 2018 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 "services/content/public/cpp/test/fake_navigable_contents_factory.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/bind_test_util.h"
#include "services/content/public/cpp/test/fake_navigable_contents.h"
#include "services/content/public/mojom/navigable_contents.mojom.h"
namespace content {
FakeNavigableContentsFactory::FakeNavigableContentsFactory() = default;
FakeNavigableContentsFactory::~FakeNavigableContentsFactory() = default;
void FakeNavigableContentsFactory::BindRequest(
mojom::NavigableContentsFactoryRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void FakeNavigableContentsFactory::WaitForAndBindNextContentsRequest(
FakeNavigableContents* contents) {
base::RunLoop loop;
next_create_contents_callback_ = base::BindLambdaForTesting(
[&loop, contents](mojom::NavigableContentsRequest request,
mojom::NavigableContentsClientPtr client) {
contents->Bind(std::move(request), std::move(client));
loop.Quit();
});
loop.Run();
}
void FakeNavigableContentsFactory::CreateContents(
mojom::NavigableContentsParamsPtr params,
mojom::NavigableContentsRequest request,
mojom::NavigableContentsClientPtr client) {
if (!next_create_contents_callback_) {
LOG(ERROR) << "Dropping unexpected CreateContents() request.";
return;
}
std::move(next_create_contents_callback_)
.Run(std::move(request), std::move(client));
}
} // namespace content
// Copyright 2018 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.
#ifndef SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_FACTORY_H_
#define SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_FACTORY_H_
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
namespace content {
class FakeNavigableContents;
// Usable by unit tests which drive Content Service client code. Allows tests
// to fake a simple Content Service implementation which drives and customizes
// basic navigation lifecycle events.
class FakeNavigableContentsFactory : public mojom::NavigableContentsFactory {
public:
FakeNavigableContentsFactory();
~FakeNavigableContentsFactory() override;
// Bind a new factory request. A single FakeNavigableContentsFactory supports
// binding any number of requests simultaneously.
void BindRequest(mojom::NavigableContentsFactoryRequest request);
// Waits for the next |CreateContents()| request on the factory and fulfills
// it by binding to |*contents|.
void WaitForAndBindNextContentsRequest(FakeNavigableContents* contents);
private:
// mojom::NavigableContentsFactory:
void CreateContents(mojom::NavigableContentsParamsPtr params,
mojom::NavigableContentsRequest request,
mojom::NavigableContentsClientPtr client) override;
mojo::BindingSet<mojom::NavigableContentsFactory> bindings_;
using CreateContentsCallback =
base::OnceCallback<void(mojom::NavigableContentsRequest,
mojom::NavigableContentsClientPtr)>;
CreateContentsCallback next_create_contents_callback_;
DISALLOW_COPY_AND_ASSIGN(FakeNavigableContentsFactory);
};
} // namespace content
#endif // SERVICES_CONTENT_PUBLIC_CPP_TEST_FAKE_NAVIGABLE_CONTENTS_FACTORY_H_
// Copyright 2018 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 "services/content/public/cpp/test/fake_navigable_contents_factory.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "net/http/http_response_headers.h"
#include "services/content/public/cpp/navigable_contents.h"
#include "services/content/public/cpp/navigable_contents_observer.h"
#include "services/content/public/cpp/test/fake_navigable_contents.h"
#include "services/content/public/mojom/navigable_contents.mojom.h"
#include "services/content/public/mojom/navigable_contents_factory.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace content {
namespace {
class FakeNavigableContentsFactoryTest : public testing::Test {
public:
FakeNavigableContentsFactoryTest() {
factory_.BindRequest(mojo::MakeRequest(&factory_proxy_));
}
~FakeNavigableContentsFactoryTest() override = default;
FakeNavigableContentsFactory& factory() { return factory_; }
mojom::NavigableContentsFactory* factory_proxy() const {
return factory_proxy_.get();
}
private:
base::test::ScopedTaskEnvironment task_environment_;
mojom::NavigableContentsFactoryPtr factory_proxy_;
FakeNavigableContentsFactory factory_;
DISALLOW_COPY_AND_ASSIGN(FakeNavigableContentsFactoryTest);
};
class NavigationObserver : public NavigableContentsObserver {
public:
explicit NavigationObserver(NavigableContents* contents)
: contents_(contents) {
contents_->AddObserver(this);
}
~NavigationObserver() override { contents_->RemoveObserver(this); }
const GURL& last_url() const { return last_url_; }
const scoped_refptr<net::HttpResponseHeaders>& last_response_headers() const {
return last_response_headers_;
}
size_t navigations_observed() const { return navigations_observed_; }
bool last_navigation_succeeded() const { return last_navigation_succeeded_; }
void WaitForNavigation() {
if (!navigation_run_loop_)
navigation_run_loop_.emplace();
navigation_run_loop_->Run();
navigation_run_loop_.reset();
}
private:
// NavigableContentsObserver:
void DidFinishNavigation(
const GURL& url,
bool is_main_frame,
bool is_error_page,
const net::HttpResponseHeaders* response_headers) override {
last_url_ = url;
last_navigation_succeeded_ = !is_error_page;
if (response_headers) {
last_response_headers_ = base::MakeRefCounted<net::HttpResponseHeaders>(
response_headers->raw_headers());
} else {
last_response_headers_ = nullptr;
}
++navigations_observed_;
if (navigation_run_loop_)
navigation_run_loop_->Quit();
}
NavigableContents* const contents_;
GURL last_url_;
scoped_refptr<net::HttpResponseHeaders> last_response_headers_;
bool last_navigation_succeeded_ = false;
size_t navigations_observed_ = 0;
base::Optional<base::RunLoop> navigation_run_loop_;
DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
};
TEST_F(FakeNavigableContentsFactoryTest, BasicNavigation) {
NavigableContents contents(factory_proxy());
FakeNavigableContents contents_impl;
factory().WaitForAndBindNextContentsRequest(&contents_impl);
const GURL kTestUrl("https://www.google.com/");
contents.Navigate(kTestUrl);
NavigationObserver observer(&contents);
observer.WaitForNavigation();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(1u, observer.navigations_observed());
EXPECT_EQ(kTestUrl, observer.last_url());
EXPECT_EQ(nullptr, observer.last_response_headers());
}
TEST_F(FakeNavigableContentsFactoryTest, MultipleClients) {
NavigableContents contents1(factory_proxy());
FakeNavigableContents contents1_impl;
factory().WaitForAndBindNextContentsRequest(&contents1_impl);
NavigableContents contents2(factory_proxy());
FakeNavigableContents contents2_impl;
factory().WaitForAndBindNextContentsRequest(&contents2_impl);
const GURL kTestUrl1("https://www.google.com/?q=cats");
const GURL kTestUrl2("https://www.google.com/?q=dogs");
contents1.Navigate(kTestUrl1);
contents2.Navigate(kTestUrl2);
NavigationObserver observer1(&contents1);
NavigationObserver observer2(&contents2);
observer1.WaitForNavigation();
observer2.WaitForNavigation();
EXPECT_TRUE(observer1.last_navigation_succeeded());
EXPECT_EQ(1u, observer1.navigations_observed());
EXPECT_EQ(kTestUrl1, observer1.last_url());
EXPECT_EQ(nullptr, observer1.last_response_headers());
EXPECT_TRUE(observer2.last_navigation_succeeded());
EXPECT_EQ(1u, observer2.navigations_observed());
EXPECT_EQ(kTestUrl2, observer2.last_url());
EXPECT_EQ(nullptr, observer2.last_response_headers());
}
TEST_F(FakeNavigableContentsFactoryTest, CustomHeaders) {
NavigableContents contents(factory_proxy());
FakeNavigableContents contents_impl;
factory().WaitForAndBindNextContentsRequest(&contents_impl);
const std::string kTestHeader1 = "Test-Header-1";
const std::string kTestHeaderValue1 = "apples";
const std::string kTestHeader2 = "Test-Header-2";
const std::string kTestHeaderValue2 = "bananas";
auto test_headers =
base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200 OK");
test_headers->AddHeader(kTestHeader1 + ": " + kTestHeaderValue1);
test_headers->AddHeader(kTestHeader2 + ": " + kTestHeaderValue2);
contents_impl.set_default_response_headers(test_headers);
const GURL kTestUrl("https://www.google.com/");
contents.Navigate(kTestUrl);
NavigationObserver observer(&contents);
observer.WaitForNavigation();
EXPECT_TRUE(observer.last_navigation_succeeded());
EXPECT_EQ(kTestUrl, observer.last_url());
ASSERT_TRUE(observer.last_response_headers());
EXPECT_TRUE(observer.last_response_headers()->HasHeaderValue(
kTestHeader1, kTestHeaderValue1));
EXPECT_TRUE(observer.last_response_headers()->HasHeaderValue(
kTestHeader2, kTestHeaderValue2));
}
} // namespace
} // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment