[modular][testing] Teach TestHarness to inject a service directory into environment
Refactor:
* |TestHarnesSpec.env_config| provides a way for tests to configure what
goes into the environment. This deprecates the |services_to_inherit| and
|services_to_inject| fields.
Changes:
* |TestHarnessSpec.env_config.service_dir| is a directory of services a
test can provide to the test harness environment.
TestHarness.ConnectToEnvironmentService() can be used to connect to the
env services.
Test:
* PseudoDirServerTest tests OpenAt() and Serve()
* TestHarnessImplTest.EnvironmentServices tests that the test-provided
directory of services are available in the test harness environment.
MF-390 #done
Change-Id: I717313db03493b292d5cd7b79788f56d3d2e5278
diff --git a/peridot/bin/modular_test_harness/modular_test_harness_test.cc b/peridot/bin/modular_test_harness/modular_test_harness_test.cc
index eaf7f68..f4c5f62 100644
--- a/peridot/bin/modular_test_harness/modular_test_harness_test.cc
+++ b/peridot/bin/modular_test_harness/modular_test_harness_test.cc
@@ -7,10 +7,10 @@
#include <sdk/lib/sys/cpp/service_directory.h>
#include <sdk/lib/sys/cpp/testing/test_with_environment.h>
-class TestHarnessFixtureTest : public modular::testing::TestHarnessFixture {};
+class ModularTestHarnessTest : public modular::testing::TestHarnessFixture {};
// Ensure that the TestHarnessFixture is able to launch the modular runtime.
-TEST_F(TestHarnessFixtureTest, SimpleSuccess) {
+TEST_F(ModularTestHarnessTest, SimpleSuccess) {
constexpr char kFakeBaseShellUrl[] =
"fuchsia-pkg://example.com/FAKE_BASE_SHELL_PKG/fake_base_shell.cmx";
diff --git a/peridot/lib/util/BUILD.gn b/peridot/lib/util/BUILD.gn
index c773e38c..f28c915 100644
--- a/peridot/lib/util/BUILD.gn
+++ b/peridot/lib/util/BUILD.gn
@@ -58,13 +58,13 @@
testonly = true
sources = [
+ "pseudo_dir_server_unittest.cc",
"pseudo_dir_utils_unittest.cc",
"string_escape_unittest.cc",
]
public_deps = [
":util",
- "//peridot/lib/testing:test_with_ledger",
"//src/lib/fxl",
"//third_party/googletest:gtest",
]
diff --git a/peridot/lib/util/pseudo_dir_server.cc b/peridot/lib/util/pseudo_dir_server.cc
index 65439d9..5a4be8f 100644
--- a/peridot/lib/util/pseudo_dir_server.cc
+++ b/peridot/lib/util/pseudo_dir_server.cc
@@ -4,6 +4,8 @@
#include "peridot/lib/util/pseudo_dir_server.h"
+#include <lib/async/cpp/task.h>
+
namespace modular {
PseudoDirServer::PseudoDirServer(std::unique_ptr<vfs::PseudoDir> pseudo_dir)
@@ -37,6 +39,18 @@
return fsl::OpenChannelAsFileDescriptor(node.Unbind().TakeChannel());
}
+fuchsia::io::DirectoryPtr PseudoDirServer::Serve() {
+ fuchsia::io::DirectoryPtr directory;
+ auto req = directory.NewRequest().TakeChannel();
+ async::PostTask(
+ thread_loop_->dispatcher(), [this, req = std::move(req)]() mutable {
+ pseudo_dir_->Serve(
+ fuchsia::io::OPEN_RIGHT_READABLE | fuchsia::io::OPEN_RIGHT_WRITABLE,
+ std::move(req));
+ });
+ return directory;
+}
+
// This method is the handler for a new thread. It lets the owning thread know
// that it has started and serves a directory requests. The thread is exited
// when this object is destroyed.
diff --git a/peridot/lib/util/pseudo_dir_server.h b/peridot/lib/util/pseudo_dir_server.h
index bb56879..b5a40ca 100644
--- a/peridot/lib/util/pseudo_dir_server.h
+++ b/peridot/lib/util/pseudo_dir_server.h
@@ -36,9 +36,13 @@
// This destructor blocks the current thread until the child thread exits.
~PseudoDirServer();
- // Opens a read-only FD at |path|. Path must not begin with '/'.
+ // Opens a read-only FD at |path|. |path| must not lead with a '/'.
fxl::UniqueFD OpenAt(std::string path);
+ // Returns a directory connection for this pseudo dir. This directory is
+ // served on a different thread than the caller's thread.
+ fuchsia::io::DirectoryPtr Serve();
+
private:
// This method is the handler for a new thread. It lets the owning thread
// know that it has started and serves a directory requests. The thread is
@@ -46,8 +50,9 @@
void StartThread(fidl::InterfaceRequest<fuchsia::io::Directory> request);
std::unique_ptr<vfs::PseudoDir> pseudo_dir_;
- // The directory connection we that |pseudo_dir| serves over in a differnt
- // thread.
+
+ // The directory connection which |OpenAt()| uses. This directory connection
+ // is served on |serving_thread_|'s thread.
fuchsia::io::DirectoryPtr dir_;
// The mutex & condition variable are used by the new thread (owned by
diff --git a/peridot/lib/util/pseudo_dir_server_unittest.cc b/peridot/lib/util/pseudo_dir_server_unittest.cc
new file mode 100644
index 0000000..5958e1b
--- /dev/null
+++ b/peridot/lib/util/pseudo_dir_server_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 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 "peridot/lib/util/pseudo_dir_server.h"
+
+#include <gtest/gtest.h>
+#include <lib/gtest/real_loop_fixture.h>
+#include <peridot/lib/util/pseudo_dir_utils.h>
+#include <src/lib/files/directory.h>
+#include <src/lib/files/file.h>
+
+namespace modular {
+namespace {
+
+class PseudoDirServerTest : public gtest::RealLoopFixture {};
+
+// Test that |PseudoDirServer::OpenAt| gives you an FD can be used on the same
+// thread as |PseudoDirServer|.
+TEST_F(PseudoDirServerTest, OpenAt) {
+ constexpr char kContents[] = "file contents";
+ modular::PseudoDirServer server(MakeFilePathWithContents("a/b/c", kContents));
+
+ {
+ // Paths with leading '/' don't work.
+ fxl::UniqueFD fd = server.OpenAt("/a");
+ EXPECT_FALSE(fd.is_valid());
+ }
+ {
+ // 'x' doesn't exist, so not valid.
+ fxl::UniqueFD fd = server.OpenAt("x");
+ EXPECT_FALSE(fd.is_valid());
+ }
+ {
+ fxl::UniqueFD fd = server.OpenAt("a");
+ EXPECT_TRUE(fd.is_valid());
+ }
+ {
+ fxl::UniqueFD fd = server.OpenAt("a/b");
+ EXPECT_TRUE(fd.is_valid());
+ }
+ {
+ fxl::UniqueFD fd = server.OpenAt("a/b/c");
+ EXPECT_TRUE(fd.is_valid());
+
+ std::string contents;
+ ASSERT_TRUE(files::ReadFileDescriptorToString(fd.get(), &contents));
+ EXPECT_EQ(kContents, contents);
+ }
+}
+
+// Test that |PseudoDirServer::Serve| serves a directory which doesn't block the
+// current thread. Test this by using thread-blocking POSIX apis.
+TEST_F(PseudoDirServerTest, Serve) {
+ constexpr char kFileName[] = "file_name";
+ constexpr char kContents[] = "file contents";
+ modular::PseudoDirServer server(
+ MakeFilePathWithContents(kFileName, kContents));
+ auto dir_fd =
+ fsl::OpenChannelAsFileDescriptor(server.Serve().Unbind().TakeChannel());
+
+ std::string contents;
+ ASSERT_TRUE(files::ReadFileToStringAt(dir_fd.get(), kFileName, &contents));
+ EXPECT_EQ(kContents, contents);
+}
+
+} // namespace
+} // namespace modular
diff --git a/peridot/lib/util/pseudo_dir_utils_unittest.cc b/peridot/lib/util/pseudo_dir_utils_unittest.cc
index 651e640..174e2cd 100644
--- a/peridot/lib/util/pseudo_dir_utils_unittest.cc
+++ b/peridot/lib/util/pseudo_dir_utils_unittest.cc
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "peridot/lib/util/pseudo_dir_utils.h"
+
#include <gtest/gtest.h>
-#include <peridot/lib/testing/test_with_ledger.h>
+#include <lib/gtest/real_loop_fixture.h>
#include <peridot/lib/util/pseudo_dir_server.h>
-#include <peridot/lib/util/pseudo_dir_utils.h>
#include <src/lib/files/directory.h>
#include <src/lib/files/file.h>
@@ -14,7 +15,7 @@
constexpr int kDefaultBufferSize = 1024;
-class PseudoDirUtilsTest : public testing::TestWithLedger {
+class PseudoDirUtilsTest : public gtest::RealLoopFixture {
public:
PseudoDirUtilsTest() = default;
~PseudoDirUtilsTest() override = default;
diff --git a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.cc b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.cc
index 2d6f4e1..34e49f9e 100644
--- a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.cc
+++ b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.cc
@@ -4,6 +4,9 @@
#include "lib/modular_test_harness/cpp/test_harness_impl.h"
+#include <dirent.h>
+#include <lib/fdio/directory.h>
+#include <lib/fsl/io/fd.h>
#include <lib/fsl/vmo/strings.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/vfs/cpp/pseudo_file.h>
@@ -11,10 +14,12 @@
#include <peridot/lib/modular_config/modular_config_xdr.h>
#include <peridot/lib/util/pseudo_dir_utils.h>
#include <src/lib/files/path.h>
+#include <src/lib/files/unique_fd.h>
#include <src/lib/fxl/logging.h>
#include <src/lib/fxl/strings/join_strings.h>
#include <src/lib/fxl/strings/split_string.h>
#include <src/lib/fxl/strings/substitute.h>
+#include <zircon/status.h>
namespace modular::testing {
namespace {
@@ -171,6 +176,8 @@
bool TestHarnessImpl::CloseBindingIfError(zx_status_t status) {
if (status != ZX_OK) {
+ FXL_LOG(ERROR) << "Destroying TestHarness because of error: "
+ << zx_status_get_string(status);
binding_.Close(status);
// destory |enclosing_env_| should kill all processes.
enclosing_env_.reset();
@@ -180,30 +187,6 @@
return false;
}
-void TestHarnessImpl::InjectServicesIntoEnvironment(
- sys::testing::EnvironmentServices* env_services,
- std::map<std::string, std::string>* default_injected_svcs) {
- // Wire up client-specified injected services, and remove them from the
- // default injected services.
- if (spec_.has_env_services_to_inject()) {
- for (const auto& injected_svc : spec_.env_services_to_inject()) {
- default_injected_svcs->erase(injected_svc.name);
-
- fuchsia::sys::LaunchInfo info;
- info.url = injected_svc.url;
- env_services->AddServiceWithLaunchInfo(std::move(info),
- injected_svc.name);
- }
- }
-
- // Wire up the remaining default injected services.
- for (const auto& injected_svc : *default_injected_svcs) {
- fuchsia::sys::LaunchInfo info;
- info.url = injected_svc.second;
- env_services->AddServiceWithLaunchInfo(std::move(info), injected_svc.first);
- }
-}
-
std::string MakeTestHarnessEnvironmentName() {
// Apply a random suffix to the environment name so that multiple hermetic
// test harness environments may coexist under the same parent env.
@@ -213,6 +196,150 @@
std::to_string(random_env_suffix));
}
+zx_status_t TestHarnessImpl::PopulateEnvServices(
+ sys::testing::EnvironmentServices* env_services) {
+ // The default set of component-provided services are all basemgr's hard
+ // dependencies. A map of service name => component URL providing the service.
+ std::map<std::string, std::string> default_svcs = {
+ {fuchsia::auth::account::AccountManager::Name_,
+ "fuchsia-pkg://fuchsia.com/account_manager#meta/account_manager.cmx"},
+ {fuchsia::devicesettings::DeviceSettingsManager::Name_,
+ "fuchsia-pkg://fuchsia.com/device_settings_manager#meta/"
+ "device_settings_manager.cmx"}};
+
+ std::set<std::string> added_svcs;
+
+ // 1. Allow services to be inherited from parent environment.
+ if (spec_.has_env_services_to_inherit()) {
+ for (auto& svc_name : spec_.env_services_to_inherit()) {
+ added_svcs.insert(svc_name);
+ env_services->AllowParentService(svc_name);
+ }
+ }
+
+ // 2. Inject component-provided services.
+ if (auto retval = PopulateEnvServicesWithComponents(env_services,
+ &added_svcs) != ZX_OK) {
+ return retval;
+ }
+
+ // 3. Inject service_dir services.
+ if (auto retval = PopulateEnvServicesWithServiceDir(env_services,
+ &added_svcs) != ZX_OK) {
+ return retval;
+ }
+
+ // 4. Inject the remaining default component-provided services.
+ for (const auto& svc_component : default_svcs) {
+ if (added_svcs.find(svc_component.first) != added_svcs.end()) {
+ continue;
+ }
+ fuchsia::sys::LaunchInfo info;
+ info.url = svc_component.second;
+ env_services->AddServiceWithLaunchInfo(std::move(info),
+ svc_component.first);
+ }
+
+ return ZX_OK;
+}
+
+zx_status_t TestHarnessImpl::PopulateEnvServicesWithComponents(
+ sys::testing::EnvironmentServices* env_services,
+ std::set<std::string>* added_svcs) {
+ // Wire up client-specified injected services, and remove them from the
+ // default injected services.
+ if (spec_.has_env_services_to_inject()) {
+ for (const auto& svc : spec_.env_services_to_inject()) {
+ if (added_svcs->find(svc.name) != added_svcs->end()) {
+ FXL_LOG(ERROR) << svc.name
+ << " has already been injected into the environment, "
+ "cannot add twice.";
+ return ZX_ERR_ALREADY_EXISTS;
+ }
+ added_svcs->insert(svc.name);
+
+ fuchsia::sys::LaunchInfo info;
+ info.url = svc.url;
+ env_services->AddServiceWithLaunchInfo(std::move(info), svc.name);
+ }
+ }
+
+ if (!spec_.has_env_services() ||
+ !spec_.env_services().has_services_from_components()) {
+ return ZX_OK;
+ }
+ for (const auto& svc : spec_.env_services().services_from_components()) {
+ if (added_svcs->find(svc.name) != added_svcs->end()) {
+ FXL_LOG(ERROR) << svc.name
+ << " has already been injected into the environment, "
+ "cannot add twice.";
+ return ZX_ERR_ALREADY_EXISTS;
+ }
+ added_svcs->insert(svc.name);
+
+ fuchsia::sys::LaunchInfo info;
+ info.url = svc.url;
+ env_services->AddServiceWithLaunchInfo(std::move(info), svc.name);
+ }
+ return ZX_OK;
+} // namespace modular::testing
+
+std::vector<std::string> GetDirListing(fuchsia::io::Directory* dir) {
+ // Make a clone of |dir| since translating to a POSIX fd is destructive.
+ fuchsia::io::NodePtr dir_copy;
+ dir->Clone(fuchsia::io::OPEN_RIGHT_READABLE, dir_copy.NewRequest());
+
+ std::vector<std::string> svcs;
+ DIR* fd = fdopendir(
+ fsl::OpenChannelAsFileDescriptor(dir_copy.Unbind().TakeChannel())
+ .release());
+ FXL_CHECK(fd != nullptr);
+
+ struct dirent* dp = nullptr;
+ while ((dp = readdir(fd)) != nullptr) {
+ if (dp->d_name[0] != '.') {
+ svcs.push_back(dp->d_name);
+ }
+ }
+
+ closedir(fd);
+ return svcs;
+}
+
+zx_status_t TestHarnessImpl::PopulateEnvServicesWithServiceDir(
+ sys::testing::EnvironmentServices* env_services,
+ std::set<std::string>* added_svcs) {
+ if (!spec_.has_env_services() || !spec_.env_services().has_service_dir() ||
+ !spec_.env_services().service_dir()) {
+ return ZX_OK;
+ }
+
+ fuchsia::io::DirectoryPtr dir;
+ dir.Bind(std::move(*spec_.mutable_env_services()->mutable_service_dir()));
+ for (auto& svc_name : GetDirListing(dir.get())) {
+ if (added_svcs->find(svc_name) != added_svcs->end()) {
+ FXL_LOG(ERROR)
+ << svc_name
+ << " is already injected into the environment, cannot add twice.";
+ return ZX_ERR_ALREADY_EXISTS;
+ }
+ env_services->AddService(
+ std::make_unique<vfs::Service>([this, svc_name](
+ zx::channel request,
+ async_dispatcher_t* dispatcher) {
+ FXL_CHECK(env_service_dir_->Connect(svc_name, std::move(request)) ==
+ ZX_OK);
+ }),
+ svc_name);
+ added_svcs->insert(svc_name);
+ }
+
+ env_service_dir_ =
+ std::make_unique<sys::ServiceDirectory>(dir.Unbind().TakeChannel());
+
+ return ZX_OK;
+}
+
void TestHarnessImpl::Run(fuchsia::modular::testing::TestHarnessSpec spec) {
// Run() can only be called once.
if (enclosing_env_) {
@@ -232,25 +359,10 @@
std::unique_ptr<sys::testing::EnvironmentServices> env_services =
interceptor_.MakeEnvironmentServices(parent_env_);
- // The default injected services are all basemgr's hard dependencies.
- // A map of service name => component URL serving it.
- std::map<std::string, std::string> default_injected_svcs = {
- {fuchsia::auth::account::AccountManager::Name_,
- "fuchsia-pkg://fuchsia.com/account_manager#meta/account_manager.cmx"},
- {fuchsia::devicesettings::DeviceSettingsManager::Name_,
- "fuchsia-pkg://fuchsia.com/device_settings_manager#meta/"
- "device_settings_manager.cmx"}};
-
- // Allow services to be inherited from outside the test harness environment.
- if (spec_.has_env_services_to_inherit()) {
- for (auto& svc_name : spec_.env_services_to_inherit()) {
- default_injected_svcs.erase(svc_name);
- env_services->AllowParentService(svc_name);
- }
+ if (CloseBindingIfError(PopulateEnvServices(env_services.get()))) {
+ return;
}
- InjectServicesIntoEnvironment(env_services.get(), &default_injected_svcs);
-
// Ledger configuration for tests by default:
// * use a memory-backed FS for ledger.
// * doesn't sync with a cloudprovider.
diff --git a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.h b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.h
index c2a4d75..565beb9 100644
--- a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.h
+++ b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl.h
@@ -139,6 +139,28 @@
// Processes the service requests which are buffered from |GetService()|.
void FlushBufferedSessionAgentServices();
+ // Populates the test harness environment with services described by
+ // |spec_.env_services|.
+ zx_status_t PopulateEnvServices(
+ sys::testing::EnvironmentServices* env_services);
+
+ // Injects services into the test harness environment according to
+ // |spec_.env_services.services_from_components| and
+ // |spec_.env_services_to_inject|.
+ //
+ // Injected service names are inserted into |added_svcs|.
+ zx_status_t PopulateEnvServicesWithComponents(
+ sys::testing::EnvironmentServices* env_services,
+ std::set<std::string>* added_svcs);
+
+ // Injects services into the test harness environment according to
+ // |spec_.env_services.service_dir|.
+ //
+ // Injected service names are inserted into |added_svcs|.
+ zx_status_t PopulateEnvServicesWithServiceDir(
+ sys::testing::EnvironmentServices* env_services,
+ std::set<std::string>* added_svcs);
+
// The test harness environment is a child of |parent_env_|.
const fuchsia::sys::EnvironmentPtr& parent_env_; // Not owned.
@@ -147,9 +169,9 @@
fit::function<void()> on_disconnected_;
- // This map manages InterceptedComponent bindings (and their implementations).
- // When a |InterceptedComponent| connection is closed, it is automatically
- // removed from this map (and its impl is deleted as well).
+ // This map manages InterceptedComponent bindings (and their
+ // implementations). When a |InterceptedComponent| connection is closed, it
+ // is automatically removed from this map (and its impl is deleted as well).
//
// The key is the raw-pointer backing the unique_ptr value.
std::map<InterceptedComponentImpl*, std::unique_ptr<InterceptedComponentImpl>>
@@ -163,6 +185,8 @@
InterceptedSessionAgentInfo intercepted_session_agent_info_;
+ std::unique_ptr<sys::ServiceDirectory> env_service_dir_;
+
friend class TestHarnessImplTest;
};
diff --git a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl_unittest.cc b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl_unittest.cc
index 17cc280..50470fb 100644
--- a/peridot/public/lib/modular_test_harness/cpp/test_harness_impl_unittest.cc
+++ b/peridot/public/lib/modular_test_harness/cpp/test_harness_impl_unittest.cc
@@ -122,8 +122,8 @@
auto generated_accountmgr_url = GenerateFakeUrl();
- spec.mutable_env_services_to_inject()->push_back(
- fuchsia::modular::testing::InjectedService{
+ spec.mutable_env_services()->mutable_services_from_components()->push_back(
+ fuchsia::modular::testing::ComponentService{
// Override the default injected AccountManager.
.name = fuchsia::auth::account::AccountManager::Name_,
.url = generated_accountmgr_url});
@@ -161,13 +161,13 @@
// Test that additional injected services are made available, spin up the
// associated component when requested. This test exercises injecting a custom
// service.
-TEST_F(TestHarnessImplTest, CustomInjectedServices) {
+TEST_F(TestHarnessImplTest, ComponentProvidedService) {
fuchsia::modular::testing::TestHarnessSpec spec;
auto generated_componentctx_url = GenerateFakeUrl();
- spec.mutable_env_services_to_inject()->push_back(
- fuchsia::modular::testing::InjectedService{
+ spec.mutable_env_services()->mutable_services_from_components()->push_back(
+ fuchsia::modular::testing::ComponentService{
// Provide a custom injected service.
.name = fuchsia::modular::ComponentContext::Name_,
.url = generated_componentctx_url});
@@ -333,6 +333,33 @@
zx::sec(10)));
};
+// Tests that services in |TestHarnessSpec.env_services.service_dir| are
+// accessible in the test harness environment.
+TEST_F(TestHarnessImplTest, EnvironmentServiceDirectory) {
+ constexpr char kTestServiceName[] = "my.test.service";
+
+ bool svc_requested = false;
+ auto svc_dir = std::make_unique<vfs::PseudoDir>();
+ svc_dir->AddEntry(kTestServiceName,
+ std::make_unique<vfs::Service>(
+ [&svc_requested](zx::channel request,
+ async_dispatcher_t* dispatcher) {
+ svc_requested = true;
+ }));
+
+ PseudoDirServer svc_dir_server(std::move(svc_dir));
+
+ fuchsia::modular::testing::TestHarnessSpec spec;
+ spec.mutable_env_services()->set_service_dir(
+ svc_dir_server.Serve().Unbind().TakeChannel());
+ test_harness()->Run(std::move(spec));
+
+ fuchsia::io::NodePtr node;
+ test_harness()->ConnectToEnvironmentService(kTestServiceName,
+ node.NewRequest().TakeChannel());
+ RunLoopUntil([&] { return svc_requested; });
+}
+
} // namespace
} // namespace testing
} // namespace modular
diff --git a/sdk/fidl/fuchsia.modular.testing/fuchsia.modular.testing.api b/sdk/fidl/fuchsia.modular.testing/fuchsia.modular.testing.api
index dccda00..b410f1e 100644
--- a/sdk/fidl/fuchsia.modular.testing/fuchsia.modular.testing.api
+++ b/sdk/fidl/fuchsia.modular.testing/fuchsia.modular.testing.api
@@ -1,3 +1,3 @@
{
- "fidl/fuchsia.modular.testing/test_harness.fidl": "e173bbde49a937ff14db4acebf865d46"
+ "fidl/fuchsia.modular.testing/test_harness.fidl": "79439b4fe93a9f61a6477750fd515694"
}
\ No newline at end of file
diff --git a/sdk/fidl/fuchsia.modular.testing/test_harness.fidl b/sdk/fidl/fuchsia.modular.testing/test_harness.fidl
index e52b84b..5350d1a 100644
--- a/sdk/fidl/fuchsia.modular.testing/test_harness.fidl
+++ b/sdk/fidl/fuchsia.modular.testing/test_harness.fidl
@@ -23,6 +23,8 @@
/// * ZX_ERR_INVALID_ARGS: Run() failed to execute succesfully.
/// * ZX_ERR_BAD_STATE: Other methods are called before Run() is called.
/// * ZX_ERR_ALREADY_BOUND: Run() was already called.
+/// * ZX_ERR_ALREADY_EXISTS: The same environment service is being provided
+/// twice.
[Discoverable]
protocol TestHarness {
/// Initializes an instance of the modular runtime in an enclosed
@@ -32,6 +34,8 @@
/// This protocol connection is closed if Run() fails, with the following
/// epitaphs:
/// * ZX_ERR_INVALID_ARGS: |spec| is mal-formed.
+ /// * ZX_ERR_ALREADY_EXISTS: The same environment service is being provided
+ /// twice in |spec.env_services|
/// * ZX_ERR_ALREADY_BOUND: Run() was already called.
Run(TestHarnessSpec spec);
@@ -60,7 +64,7 @@
/// environment.
ConnectToEnvironmentService(string service_name, handle<channel> request);
- /// DEPRECATED. Use |ConnectToModularService()| instead, they are the same.
+ /// DEPRECATED. Use |ConnectToModularService()| instead.
GetService(TestHarnessService service);
};
@@ -126,35 +130,51 @@
/// defaults.
2: fuchsia.modular.session.SessionmgrConfig sessionmgr_config;
- /// The test harness starts the modular runtime in a hermetic environment
- /// which does not allow accessing services outside of the environment,
- /// unless the service names are specified in this list.
- ///
- /// For example, adding "fuchsia.net.SocketProvider" here allows the
- /// hermetic environment to inherit the test process' environment's instance
- /// of the socket provider. This lets the test code, and the code under
- /// test, to share the same SocketProvider.
- 3: vector<string> env_services_to_inherit;
-
- /// A list of services and their providers to inject into this environment,
- /// along with components which provide them. Multiple services may be
- /// provided by the same component, but only one instance of the component
- /// is launched to serve its services. Components are started when one of
- /// their services is requested, and are kept alive for the duration of the
- /// test harness environment's life.
- 5: vector<InjectedService> env_services_to_inject;
-
/// List of component URLs (and additional .cmx contents) to intercept.
4: vector<InterceptSpec> components_to_intercept;
+
+ /// Options to configure the test harness environment. Use this to inject
+ /// services into the environment.
+ ///
+ /// Optional.
+ 6: EnvironmentServicesSpec env_services;
+
+ /// DEPRECATED. Use |env_services.service_dir| to pass through services from
+ /// parent environment.
+ 3: vector<string> env_services_to_inherit;
+
+ /// DEPRECATED. Use |env_services.services_from_components| instead.
+ 5: vector<InjectedService> env_services_to_inject;
};
-/// Describes a single injected service.
-struct InjectedService {
+/// Options for configuring the test harness environment with services.
+///
+/// If the same service is provided in more than one place, |TestHarness|
+/// connection is closed with a ZX_ERR_ALREADY_EXISTS epitaph.
+table EnvironmentServicesSpec {
+ /// A directory of services to be provided to the test harness environment.
+ ///
+ /// Optional.
+ 1: handle<channel> service_dir;
+
+ /// A list of services provided by components to inject into the test
+ /// harness environment. Multiple services may be provided by the same
+ /// component, but only one instance of the component is launched to serve
+ /// its services. Components are started when one of their services is
+ /// requested, and are kept alive for the duration of the test harness
+ /// environment's life.
+ ///
+ /// Optional.
+ 2: vector<ComponentService> services_from_components;
+};
+
+/// Describes a service to be provided by a component instance.
+struct ComponentService {
/// Name of the service.
string name;
- /// URL of the component which will provide the service (denoted by |name|).
- /// The service is retrieved from the component's /out/svc namespace.
+ /// URL of the component which will provide the service.
+ /// The service is retrieved from this component's /out/svc namespace.
fuchsia.sys.component_url url;
};
@@ -188,3 +208,14 @@
request<fuchsia.modular.ComponentContext> component_context;
request<fuchsia.modular.AgentContext> agent_context;
};
+
+/// DEPRECATED. Renamed to ComponentService.
+struct InjectedService {
+ /// Name of the service.
+ string name;
+
+ /// URL of the component which will provide the service.
+ /// The service is retrieved from this component's /out/svc namespace.
+ fuchsia.sys.component_url url;
+};
+