blob: 3cd7f97d5f094d13d81d96d0ebd9b5bd959b00b9 [file] [log] [blame]
// Copyright 2019 The Fuchsia 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 <fuchsia/modular/session/cpp/fidl.h>
#include <fuchsia/modular/testing/cpp/fidl.h>
#include <fuchsia/testing/modular/cpp/fidl.h>
#include <sdk/lib/modular/testing/cpp/fake_agent.h>
#include "src/modular/lib/modular_test_harness/cpp/test_harness_fixture.h"
namespace {
const std::string kTestAgentUrl("fuchsia-pkg://fuchsia.com/fake_agent#meta/fake_agent.cmx");
const std::string kTestServiceName(fuchsia::testing::modular::TestProtocol::Name_);
// Configuration for testing |ComponentContext| ConnectToAgentService().
struct ConnectToAgentServiceTestConfig {
// The map of |service_name|->|agent_url| used to look up a service
// handler |agent_url| by name.
std::map<std::string, std::string> service_to_agent_map;
// If true, include the service_name in the |AgentServiceRequest|.
// This is required for a successful connection.
bool provide_service_name = false;
// If true, include the specific handler (agent URL) in the
// |AgentServiceRequest|. This is *not* required for a successful connection.
bool provide_handler = false;
// If true, include the service client-side channel in the
// |AgentServiceRequest|. This is required for a successful connection.
bool provide_channel = false;
// If true, include the |AgentController| in the |AgentServiceRequest|.
// This is required for a successful connection.
bool provide_agent_controller = false;
template <typename Interface>
fuchsia::modular::AgentServiceRequest MakeAgentServiceRequest(
std::string service_name, Interface service_request,
fidl::InterfaceRequest<fuchsia::modular::AgentController> agent_controller) {
fuchsia::modular::AgentServiceRequest agent_service_request;
if (provide_service_name) {
agent_service_request.set_service_name(service_name);
}
if (provide_handler) {
agent_service_request.set_handler(kTestAgentUrl);
}
if (provide_channel) {
agent_service_request.set_channel(service_request.TakeChannel());
}
if (provide_agent_controller) {
agent_service_request.set_agent_controller(std::move(agent_controller));
}
return agent_service_request;
}
};
class AgentServicesTest : public modular_testing::TestHarnessFixture {
protected:
AgentServicesTest() : fake_agent_(modular_testing::FakeAgent::CreateWithDefaultOptions()) {}
fuchsia::modular::ComponentContextPtr StartTestHarness(
ConnectToAgentServiceTestConfig test_config) {
fuchsia::modular::testing::TestHarnessSpec spec;
std::vector<fuchsia::modular::session::AgentServiceIndexEntry> agent_service_index;
for (const auto& entry : test_config.service_to_agent_map) {
fuchsia::modular::session::AgentServiceIndexEntry agent_service;
agent_service.set_service_name(entry.first);
agent_service.set_agent_url(entry.second);
agent_service_index.emplace_back(std::move(agent_service));
}
spec.mutable_sessionmgr_config()->set_agent_service_index(std::move(agent_service_index));
fuchsia::modular::testing::InterceptSpec intercept_spec;
intercept_spec.set_component_url(kTestAgentUrl);
spec.mutable_components_to_intercept()->push_back(std::move(intercept_spec));
test_harness().events().OnNewComponent =
[this](fuchsia::sys::StartupInfo startup_info,
fidl::InterfaceHandle<fuchsia::modular::testing::InterceptedComponent> component) {
ASSERT_EQ(startup_info.launch_info.url, kTestAgentUrl);
fake_agent_->BuildInterceptOptions().launch_handler(std::move(startup_info),
component.Bind());
};
fit::function<void(fidl::InterfaceRequest<fuchsia::testing::modular::TestProtocol>)>
service_handler =
[this](fidl::InterfaceRequest<fuchsia::testing::modular::TestProtocol> request) {
if (fake_agent_service_handler_) {
fake_agent_service_handler_(std::move(request));
}
};
fake_agent_->AddAgentService(std::move(service_handler));
test_harness()->Run(std::move(spec));
fuchsia::modular::ComponentContextPtr component_context;
fuchsia::modular::testing::ModularService modular_service;
modular_service.set_component_context(component_context.NewRequest());
test_harness()->ConnectToModularService(std::move(modular_service));
return component_context;
}
// Called by test functions to invoke ConnectToAgentService with various input configurations.
//
// |test_config| Input configurations and setup options.
zx_status_t ExecuteConnectToAgentServiceTest(ConnectToAgentServiceTestConfig test_config) {
fuchsia::modular::ComponentContextPtr component_context = StartTestHarness(test_config);
// Client-side service pointer
fuchsia::testing::modular::TestProtocolPtr service_ptr;
auto service_name = kTestServiceName;
auto service_request = service_ptr.NewRequest();
zx_status_t service_status = ZX_OK;
bool service_terminated = false;
service_ptr.set_error_handler([&](zx_status_t status) {
service_terminated = true;
service_status = status;
});
bool got_request = false;
fake_agent_service_handler_ =
[&](fidl::InterfaceRequest<fuchsia::testing::modular::TestProtocol> request) {
got_request = true;
};
fuchsia::modular::AgentControllerPtr agent_controller;
auto agent_service_request = test_config.MakeAgentServiceRequest(
service_name, std::move(service_request), agent_controller.NewRequest());
component_context->ConnectToAgentService(std::move(agent_service_request));
RunLoopUntil([&] { return got_request || service_terminated; });
fake_agent_service_handler_ = nullptr; // Callback references local variables.
// Speed up teardown of the test by eagerly terminating the fake agent.
fake_agent_->Exit(0);
// If we got the service request, then routing of the agent service request was successful, even
// though at this point we have already closed the service channel.
if (got_request) {
return ZX_OK;
} else {
EXPECT_NE(service_status, ZX_OK);
}
return service_status;
}
std::unique_ptr<modular_testing::FakeAgent> fake_agent_;
fit::function<void(fidl::InterfaceRequest<fuchsia::testing::modular::TestProtocol>)>
fake_agent_service_handler_;
};
// Ensure Session Manager's ConnectToAgentService can successfully find an
// agent for a given session name, and connect to that agent's service.
TEST_F(AgentServicesTest, ValidAndSuccessfulOneEntry) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{kTestServiceName, kTestAgentUrl},
};
EXPECT_EQ(ZX_OK, ExecuteConnectToAgentServiceTest(test_config));
}
// Find agent and service successfully among multiple index entries.
TEST_F(AgentServicesTest, ValidAndSuccessfulMultipleEntries) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{"chromium.cast.ApplicationConfigManager",
"fuchsia-pkg://fuchsia.com/cast_agent#meta/cast_agent.cmx"},
{kTestServiceName, kTestAgentUrl},
{"fuchsia.feedback.DataProvider",
"fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"},
};
EXPECT_EQ(ZX_OK, ExecuteConnectToAgentServiceTest(test_config));
}
// Find service successfully, from a specific handler. The index specifies this
// agent as the default handler, but should not be necessary.
TEST_F(AgentServicesTest, SpecificHandlerProvidedHasService) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_handler = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{"chromium.cast.ApplicationConfigManager",
"fuchsia-pkg://fuchsia.com/cast_agent#meta/cast_agent.cmx"},
{kTestServiceName, kTestAgentUrl},
{"fuchsia.feedback.DataProvider",
"fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"},
};
EXPECT_EQ(ZX_OK, ExecuteConnectToAgentServiceTest(test_config));
}
// Find service successfully, from a specific handler. The index does not
// include the requested service, but it should not be needed since the
// handler is specified.
TEST_F(AgentServicesTest, SpecificHandlerProvidedHasServiceButNotInIndex) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_handler = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{"chromium.cast.ApplicationConfigManager",
"fuchsia-pkg://fuchsia.com/cast_agent#meta/cast_agent.cmx"},
{"fuchsia.feedback.DataProvider",
"fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"},
};
EXPECT_EQ(ZX_OK, ExecuteConnectToAgentServiceTest(test_config));
}
// Find service successfully, from a specific handler. The index specifies
// a different agent as the handler, but that agent should not be used since
// a specific agent was specified.
TEST_F(AgentServicesTest, SpecificHandlerProvidedHasServiceButIndexHasDifferentHandler) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_handler = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{kTestServiceName, "fuchsia-pkg://fuchsia.com/cast_agent#meta/cast_agent.cmx"},
{"fuchsia.feedback.DataProvider",
"fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"},
};
EXPECT_EQ(ZX_OK, ExecuteConnectToAgentServiceTest(test_config));
}
// Bad request
TEST_F(AgentServicesTest, NoServiceNameProvided) {
ConnectToAgentServiceTestConfig test_config;
// test_config.provide_service_name = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
test_config.service_to_agent_map = {
{"fuchsia.feedback.DataProvider",
"fuchsia-pkg://fuchsia.com/feedback_agent#meta/feedback_agent.cmx"},
};
EXPECT_EQ(ZX_ERR_PEER_CLOSED, ExecuteConnectToAgentServiceTest(test_config));
}
// Bad request
TEST_F(AgentServicesTest, NoChannelProvided) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
// test_config.provide_channel = true;
test_config.provide_agent_controller = true;
EXPECT_EQ(ZX_ERR_PEER_CLOSED, ExecuteConnectToAgentServiceTest(test_config));
}
// Bad request
TEST_F(AgentServicesTest, NoAgentControllerProvided) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_channel = true;
// test_config.provide_agent_controller = true;
EXPECT_EQ(ZX_ERR_PEER_CLOSED, ExecuteConnectToAgentServiceTest(test_config));
}
// Attempt to look up the agent based on the service name, but it is not in
// the index.
TEST_F(AgentServicesTest, NoHandlerForService) {
ConnectToAgentServiceTestConfig test_config;
test_config.provide_service_name = true;
test_config.provide_channel = true;
test_config.provide_agent_controller = true;
EXPECT_EQ(ZX_ERR_NOT_FOUND, ExecuteConnectToAgentServiceTest(test_config));
}
} // namespace