| // 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 <lib/integration_testing/cpp/testing.h> |
| |
| #include <set> |
| |
| #include <fuchsia/testing/runner/cpp/fidl.h> |
| #include <lib/fxl/logging.h> |
| |
| using fuchsia::testing::runner::TestRunner; |
| using fuchsia::testing::runner::TestRunnerPtr; |
| using fuchsia::testing::runner::TestRunnerStore; |
| using fuchsia::testing::runner::TestRunnerStorePtr; |
| |
| namespace modular { |
| namespace testing { |
| |
| namespace { |
| TestRunnerPtr g_test_runner; |
| TestRunnerStorePtr g_test_runner_store; |
| std::set<std::string> g_test_points; |
| bool g_connected; |
| } // namespace |
| |
| void Init(component::StartupContext* context, const std::string& identity) { |
| FXL_CHECK(context); |
| FXL_CHECK(!g_test_runner.is_bound()); |
| FXL_CHECK(!g_test_runner_store.is_bound()); |
| |
| g_test_runner = context->ConnectToEnvironmentService<TestRunner>(); |
| g_test_runner.set_error_handler([](zx_status_t status) { |
| if (g_connected) { |
| FXL_LOG(ERROR) << "Lost connection to TestRunner. This indicates that " |
| "there was an observed process that was terminated " |
| "without calling TestRunner.Done()."; |
| } else { |
| FXL_LOG(ERROR) << "This application must be run under test_runner."; |
| } |
| exit(1); |
| }); |
| g_test_runner->Identify(identity, [] { g_connected = true; }); |
| g_test_runner->SetTestPointCount(g_test_points.size()); |
| g_test_runner_store = context->ConnectToEnvironmentService<TestRunnerStore>(); |
| } |
| |
| void Fail(const std::string& log_msg) { |
| if (g_test_runner.is_bound()) { |
| g_test_runner->Fail(log_msg); |
| } |
| } |
| |
| void Done(const std::function<void()>& ack) { |
| if (g_test_runner.is_bound()) { |
| g_test_runner->Done([ack] { |
| ack(); |
| g_test_runner.Unbind(); |
| }); |
| } else { |
| ack(); |
| } |
| |
| if (g_test_runner_store.is_bound()) { |
| g_test_runner_store.Unbind(); |
| } |
| } |
| |
| void Teardown(const std::function<void()>& ack) { |
| if (g_test_runner.is_bound()) { |
| g_test_runner->Teardown([ack] { |
| ack(); |
| g_test_runner.Unbind(); |
| }); |
| } else { |
| ack(); |
| } |
| |
| if (g_test_runner_store.is_bound()) { |
| g_test_runner_store.Unbind(); |
| } |
| } |
| |
| TestRunnerStore* GetStore() { |
| FXL_CHECK(g_test_runner_store.is_bound()); |
| return g_test_runner_store.get(); |
| } |
| |
| std::function<void(fidl::StringPtr)> NewBarrierClosure( |
| const int limit, std::function<void()> proceed) { |
| return [limit, count = std::make_shared<int>(0), |
| proceed = std::move(proceed)](fidl::StringPtr value) { |
| ++*count; |
| if (*count == limit) { |
| proceed(); |
| } |
| }; |
| } |
| |
| void Put(const fidl::StringPtr& key, const fidl::StringPtr& value) { |
| modular::testing::GetStore()->Put(key, value, [] {}); |
| } |
| |
| void Get(const fidl::StringPtr& key, |
| std::function<void(fidl::StringPtr)> callback) { |
| modular::testing::GetStore()->Get(key, std::move(callback)); |
| } |
| |
| void Signal(const fidl::StringPtr& condition) { |
| modular::testing::GetStore()->Put(condition, condition, [] {}); |
| } |
| |
| void Await(const fidl::StringPtr& condition, std::function<void()> cont) { |
| modular::testing::GetStore()->Get( |
| condition, [cont = std::move(cont)](fidl::StringPtr) { cont(); }); |
| } |
| |
| void RegisterTestPoint(const std::string& label) { |
| // Test points can only be registered before Init is called. |
| FXL_CHECK(!g_test_runner.is_bound()) |
| << "Test Runner connection not bound. You must call " |
| << "ComponentBase::TestInit() before registering " |
| << "\"" << label << "\"."; |
| |
| auto inserted = g_test_points.insert(label); |
| |
| // Test points must have unique labels. |
| FXL_CHECK(inserted.second) << "Test points must have unique labels. " |
| << "\"" << label << "\" is repeated."; |
| } |
| |
| void PassTestPoint(const std::string& label) { |
| // Test points can only be passed after initialization. |
| FXL_CHECK(g_test_runner.is_bound()) |
| << "Test Runner connection not bound. You must call " |
| << "ComponentBase::TestInit() before \"" << label << "\".Pass() can be " |
| << "called."; |
| |
| // Test points can only be passed once. |
| FXL_CHECK(g_test_points.erase(label)) |
| << "TEST FAILED: Test point can only be passed once. " |
| << "\"" << label << "\".Pass() has been called twice."; |
| |
| g_test_runner->PassTestPoint(); |
| } |
| |
| } // namespace testing |
| } // namespace modular |