blob: 255181b34d2cee3fede436b85d15bd59569c8ff5 [file] [log] [blame]
// Copyright 2018 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.
#ifndef LIB_COMPONENT_CPP_TESTING_TEST_WITH_ENVIRONMENT_H_
#define LIB_COMPONENT_CPP_TESTING_TEST_WITH_ENVIRONMENT_H_
#include <fs/pseudo-dir.h>
#include <fuchsia/sys/cpp/fidl.h>
#include "lib/component/cpp/testing/enclosing_environment.h"
#include "lib/component/cpp/testing/launcher_impl.h"
#include "lib/component/cpp/testing/termination_result.h"
#include "lib/fidl/cpp/binding_set.h"
#include "lib/gtest/real_loop_fixture.h"
namespace component {
namespace testing {
// Test fixture for tests to run Components inside a new isolated Environment,
// wrapped in a enclosing Environment.
//
// The new isolated Environment, provided to the Component under test, is not
// visible to any real Environments, such as the Environment that the test
// program was launched in.
//
// That isloated environment needs to be created using
// |CreateNewEnclosingEnvironment*| APIs.
//
// The isolated Environment is enclosed in a enclosing Environment, allowing the
// test to provide Loader, Services, and other Directories that are visible to
// Components under test, and only to those Components.
//
//
// This fixture also allows you to create components in the real environment in
// which this test was launched. Those components should only be used to
// validate real system state.
//
// To use this fixture you need to whitelist "fuchsia.sys.Environment" and
// "fuchsia.sys.Loader" in your component manifest file in "sandbox.services".
// It is necessary because this fixture needs to access
// "fuchsia.sys.Environment" and if you create a |EnclosingEnvironment| then it
// will need access to parent's "fuchsia.sys.Loader" to serve it own Loader
// service.
//
// If you are going to create a new EnclosingEnvironment then you also need to
// run your own loop to serve services provided by that environment. So use of
// SyncPtrs is not advisable unless you can run a loop safely in a new thread
// which stops running before you kill your EnclosingEnvironment.
class TestWithEnvironment : public gtest::RealLoopFixture {
protected:
TestWithEnvironment();
fuchsia::sys::LauncherPtr launcher_ptr() {
fuchsia::sys::LauncherPtr launcher;
real_launcher_.AddBinding(launcher.NewRequest());
return launcher;
}
const std::shared_ptr<component::Services>& real_services() {
return real_services_;
}
const fuchsia::sys::EnvironmentPtr& real_env() { return real_env_; }
// Creates a new enclosing environment inside current real environment with
// the given services.
//
// This environment and components created in it will not have access to any
// of services(except Loader) and resources from the real environment unless
// explicitly allowed by calling AllowPublicService.
//
// After all services are added/passed through to the environment, you must
// call Launch() to actually start it.
std::unique_ptr<EnclosingEnvironment> CreateNewEnclosingEnvironment(
const std::string& label,
std::unique_ptr<EnvironmentServices> services) const {
return EnclosingEnvironment::Create(label, real_env_, std::move(services));
}
// Returns an EnvironmentServices object that the caller can use to pass
// services to a new EnclosingEnvironment.
//
// The returned object has the parent's loader, but no other services by
// default.
std::unique_ptr<EnvironmentServices> CreateServices() {
return EnvironmentServices::Create(real_env_);
}
std::unique_ptr<EnvironmentServices> CreateServicesWithCustomLoader(
const fbl::RefPtr<fs::Service>& loader_service) {
return EnvironmentServices::CreateWithCustomLoader(real_env_,
loader_service);
}
// Creates component in current real environment. This component will have
// access to the services, directories and other resources from the
// environment in which your test was launched.
//
// This should be mostly used for observing the state of system and for
// nothing else. For eg. Try launching "glob" component and validate how it
// behaves in various environments.
void CreateComponentInCurrentEnvironment(
fuchsia::sys::LaunchInfo launch_info,
fidl::InterfaceRequest<fuchsia::sys::ComponentController> request);
// Returns true if environment was created.
//
// You should either use this function to wait or run your own loop if you
// want CreateComponent* to succed on |enclosing_environment|.
bool WaitForEnclosingEnvToStart(
const EnclosingEnvironment* enclosing_environment,
zx::duration timeout = zx::sec(5)) {
return RunLoopWithTimeoutOrUntil(
[enclosing_environment] { return enclosing_environment->is_running(); },
timeout);
}
// Run a loop until the given component is terminated or |timeout| elapses.
bool RunComponentUntilTerminatedOrTimeout(
fuchsia::sys::ComponentControllerPtr component_controller,
TerminationResult* termination_result = nullptr,
zx::duration timeout = zx::sec(5), zx::duration step = zx::msec(10));
private:
std::shared_ptr<component::Services> real_services_;
fuchsia::sys::EnvironmentPtr real_env_;
LauncherImpl real_launcher_;
};
} // namespace testing
} // namespace component
#endif // LIB_COMPONENT_CPP_TESTING_TEST_WITH_ENVIRONMENT_H_