| // 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. |
| // |
| // This application is intenteded to be used for manual testing of |
| // the Cobalt logger client on Fuchsia by Cobalt engineers. |
| // |
| // It also serves as an example of how to use the Cobalt FIDL API. |
| // |
| // It is also invoked by the cobalt_client CQ and CI. |
| |
| #include "src/cobalt/bin/testapp/cobalt_testapp.h" |
| |
| #include <fuchsia/cobalt/cpp/fidl.h> |
| #include <fuchsia/metrics/cpp/fidl.h> |
| #include <fuchsia/sys/cpp/fidl.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include <memory> |
| #include <sstream> |
| #include <string> |
| |
| #include "lib/fidl/cpp/binding.h" |
| #include "lib/fidl/cpp/synchronous_interface_ptr.h" |
| #include "lib/sys/cpp/component_context.h" |
| #include "src/cobalt/bin/testapp/cobalt_testapp_logger.h" |
| #include "src/cobalt/bin/testapp/prober_metrics_registry.cb.h" |
| #include "src/cobalt/bin/testapp/testapp_metrics_registry.cb.h" |
| #include "src/cobalt/bin/testapp/tests.h" |
| #include "src/cobalt/bin/utils/status_utils.h" |
| #include "src/lib/fsl/vmo/file.h" |
| #include "src/lib/fxl/command_line.h" |
| #include "src/lib/fxl/log_settings_command_line.h" |
| #include "src/lib/fxl/macros.h" |
| |
| namespace cobalt { |
| namespace testapp { |
| |
| using ::cobalt::StatusToString; |
| |
| // This must be less than 2^31. There appears to be a bug in |
| // std::condition_variable::wait_for() in which setting the wait time to |
| // std::chrono::seconds::max() effectively sets the wait time to zero. |
| constexpr uint32_t kInfiniteTime = 999999999; |
| |
| #define TRY_TEST(test) \ |
| if (!(test)) { \ |
| return false; \ |
| } |
| |
| #define CONNECT_AND_TRY_TEST(test, backfill_days) \ |
| Connect(kInfiniteTime, 0, backfill_days, false, 0); \ |
| if (!(test)) { \ |
| return false; \ |
| } |
| |
| #define CONNECT_AND_TRY_TEST_TWICE(test, backfill_days) \ |
| Connect(kInfiniteTime, 0, backfill_days, false, 0); \ |
| if (!(test)) { \ |
| Connect(kInfiniteTime, 0, backfill_days, false, 0); \ |
| if (!(test)) { \ |
| return false; \ |
| } \ |
| } |
| |
| bool CobaltTestApp::RunTests() { |
| // With the following values for the scheduling parameters we are |
| // essentially configuring the ShippingManager to be in manual mode. It will |
| // never send Observations because of the schedule and send them immediately |
| // in response to RequestSendSoon(). |
| Connect(kInfiniteTime, 0, kEventAggregatorBackfillDays, true, 0); |
| |
| // TODO(zmbush): Create tests for all logger methods. |
| TRY_TEST(TestLogEvent(&logger_)); |
| TRY_TEST(TestLogEventCount(&logger_)); |
| TRY_TEST(TestLogElapsedTime(&logger_)); |
| TRY_TEST(TestLogFrameRate(&logger_)); |
| TRY_TEST(TestLogMemoryUsage(&logger_)); |
| TRY_TEST(TestLogIntHistogram(&logger_)); |
| TRY_TEST(TestLogCustomEvent(&logger_)); |
| TRY_TEST(TestLogCobaltEvent(&logger_)); |
| |
| if (!DoLocalAggregationTests(kEventAggregatorBackfillDays)) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool CobaltTestApp::DoLocalAggregationTests(const size_t backfill_days) { |
| uint32_t project_id = |
| (test_for_prober_ ? cobalt_prober_registry::kProjectId : cobalt_registry::kProjectId); |
| // TODO(fxbug.dev/52750): We try each of these tests twice in case the failure |
| // reason is that the calendar date has changed mid-test. |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogEventWithAggregation(&logger_, clock_.get(), &cobalt_controller_, backfill_days, |
| project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogEventCountWithAggregation(&logger_, clock_.get(), &cobalt_controller_, backfill_days, |
| project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogElapsedTimeWithAggregation(&logger_, clock_.get(), &cobalt_controller_, backfill_days, |
| project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogInteger(&logger_, clock_.get(), &cobalt_controller_, backfill_days, project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogOccurrence(&logger_, clock_.get(), &cobalt_controller_, backfill_days, project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE(TestLogIntegerHistogram(&logger_, clock_.get(), &cobalt_controller_, |
| backfill_days, project_id), |
| backfill_days); |
| CONNECT_AND_TRY_TEST_TWICE( |
| TestLogString(&logger_, clock_.get(), &cobalt_controller_, backfill_days, project_id), |
| backfill_days); |
| |
| return true; |
| } |
| |
| void CobaltTestApp::Connect(uint32_t schedule_interval_seconds, uint32_t min_interval_seconds, |
| size_t event_aggregator_backfill_days, |
| bool start_event_aggregator_worker, uint32_t initial_interval_seconds) { |
| controller_.Unbind(); |
| fidl::InterfaceHandle<fuchsia::io::Directory> directory; |
| fuchsia::sys::LaunchInfo launch_info; |
| launch_info.url = "fuchsia-pkg://fuchsia.com/cobalt#meta/cobalt.cmx"; |
| launch_info.directory_request = directory.NewRequest().TakeChannel(); |
| launch_info.arguments.emplace(); |
| { |
| std::ostringstream stream; |
| stream << "--schedule_interval_seconds=" << schedule_interval_seconds; |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| if (initial_interval_seconds > 0) { |
| std::ostringstream stream; |
| stream << "--initial_interval_seconds=" << initial_interval_seconds; |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| { |
| std::ostringstream stream; |
| stream << "--min_interval_seconds=" << min_interval_seconds; |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| { |
| std::ostringstream stream; |
| stream << "--event_aggregator_backfill_days=" << event_aggregator_backfill_days; |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| { |
| std::ostringstream stream; |
| stream << "--start_event_aggregator_worker=" |
| << (start_event_aggregator_worker ? "true" : "false"); |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| { |
| std::ostringstream stream; |
| stream << "--verbose=" << syslog::GetVlogVerbosity(); |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| if (!use_network_) { |
| std::ostringstream stream; |
| stream << "--test_only_use_fake_clock"; |
| launch_info.arguments->push_back(stream.str()); |
| } |
| |
| fuchsia::sys::LauncherPtr launcher; |
| context_->svc()->Connect(launcher.NewRequest()); |
| launcher->CreateComponent(std::move(launch_info), controller_.NewRequest()); |
| controller_.set_error_handler([](zx_status_t status) { |
| FX_LOGS(ERROR) << "Connection error from CobaltTestApp to Cobalt FIDL Service."; |
| }); |
| |
| sys::ServiceDirectory services(std::move(directory)); |
| |
| fuchsia::cobalt::LoggerFactorySyncPtr logger_factory; |
| services.Connect(logger_factory.NewRequest()); |
| |
| fuchsia::cobalt::Status status = fuchsia::cobalt::Status::INTERNAL_ERROR; |
| |
| uint32_t project_id = |
| (test_for_prober_ ? cobalt_prober_registry::kProjectId : cobalt_registry::kProjectId); |
| FX_LOGS(INFO) << "Test app is logging for the " << project_id << " project"; |
| logger_factory->CreateLoggerFromProjectId(project_id, logger_.logger_.NewRequest(), &status); |
| FX_CHECK(status == fuchsia::cobalt::Status::OK) << "CreateLogger() => " << StatusToString(status); |
| |
| logger_factory->CreateLoggerSimpleFromProjectId(project_id, logger_.logger_simple_.NewRequest(), |
| &status); |
| FX_CHECK(status == fuchsia::cobalt::Status::OK) |
| << "CreateLoggerSimple() => " << StatusToString(status); |
| |
| fuchsia::metrics::MetricEventLoggerFactorySyncPtr metric_event_logger_factory; |
| services.Connect(metric_event_logger_factory.NewRequest()); |
| |
| fuchsia::metrics::Status metrics_status = fuchsia::metrics::Status::INTERNAL_ERROR; |
| fuchsia::metrics::ProjectSpec project; |
| project.set_customer_id(1); |
| project.set_project_id(project_id); |
| metric_event_logger_factory->CreateMetricEventLogger( |
| std::move(project), logger_.metric_event_logger_.NewRequest(), &metrics_status); |
| FX_CHECK(metrics_status == fuchsia::metrics::Status::OK) |
| << "CreateMetricEventLogger() => " << StatusToString(metrics_status); |
| |
| services.Connect(system_data_updater_.NewRequest()); |
| status = fuchsia::cobalt::Status::INTERNAL_ERROR; |
| fuchsia::cobalt::SoftwareDistributionInfo info; |
| info.set_current_channel("devhost"); |
| info.set_current_realm(""); |
| system_data_updater_->SetSoftwareDistributionInfo(std::move(info), &status); |
| FX_CHECK(status == fuchsia::cobalt::Status::OK) << "Unable to set software distribution info"; |
| |
| services.Connect(cobalt_controller_.NewRequest()); |
| |
| // Block until the Cobalt service has been fully initialized. This includes |
| // being notified by the timekeeper service that the system clock is accurate. |
| FX_LOGS(INFO) << "Blocking until the Cobalt service is fully initialized."; |
| cobalt_controller_->ListenForInitialized(); |
| FX_LOGS(INFO) << "Continuing because the Cobalt service is fully initialzied."; |
| } |
| |
| } // namespace testapp |
| } // namespace cobalt |