blob: 972552f12e8432434065070c9b8ed20865b8259d [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.
#include "peridot/lib/cobalt/cobalt.h"
#include <lib/async/default.h>
#include <lib/component/cpp/service_provider_impl.h>
#include <lib/fidl/cpp/clone.h>
#include <lib/fsl/vmo/strings.h>
#include <lib/fxl/logging.h>
#include <lib/fxl/macros.h>
#include <lib/gtest/test_loop_fixture.h>
#include <lib/svc/cpp/service_provider_bridge.h>
namespace cobalt {
namespace {
bool Equals(const fuchsia::cobalt::Value& v1,
const fuchsia::cobalt::Value& v2) {
if (v1.Which() != v2.Which()) {
return false;
}
switch (v1.Which()) {
case fuchsia::cobalt::Value::Tag::Invalid:
return true;
case fuchsia::cobalt::Value::Tag::kDoubleValue:
return v1.double_value() == v2.double_value();
case fuchsia::cobalt::Value::Tag::kIndexValue:
return v1.index_value() == v2.index_value();
case fuchsia::cobalt::Value::Tag::kIntBucketDistribution: {
const auto& bucket1 = v1.int_bucket_distribution();
const auto& bucket2 = v2.int_bucket_distribution();
if (bucket1.is_null() != bucket2.is_null()) {
return false;
}
if (!bucket1) {
return true;
}
if (bucket1->size() != bucket2->size()) {
return false;
}
for (size_t i = 0; i < bucket1->size(); ++i) {
const auto& entry1 = bucket1->at(i);
const auto& entry2 = bucket2->at(i);
if (entry1.count != entry2.count || entry1.index != entry2.index) {
return false;
}
}
return true;
}
case fuchsia::cobalt::Value::Tag::kIntValue:
return v1.int_value() == v2.int_value();
case fuchsia::cobalt::Value::Tag::kStringValue:
return v1.string_value() == v1.string_value();
}
}
bool Equals(const fidl::VectorPtr<fuchsia::cobalt::ObservationValue>& v1,
const fidl::VectorPtr<fuchsia::cobalt::ObservationValue>& v2) {
if (v1.is_null() != v2.is_null()) {
return false;
}
if (!v1) {
return true;
}
if (v1->size() != v2->size()) {
return false;
}
for (size_t i = 0; i < v1->size(); ++i) {
const auto& value1 = v1->at(i);
const auto& value2 = v2->at(i);
if (value1.encoding_id != value2.encoding_id ||
value1.name != value2.name || !Equals(value1.value, value2.value)) {
return false;
}
}
return true;
}
constexpr char kFakeCobaltConfig[] = "FakeConfig";
constexpr int32_t kFakeCobaltMetricId = 2;
constexpr int32_t kFakeCobaltEncodingId = 3;
class FakeCobaltEncoderImpl : public fuchsia::cobalt::Encoder {
public:
FakeCobaltEncoderImpl() {}
void AddObservation(uint32_t metric_id, uint32_t encoding_id,
fuchsia::cobalt::Value observation,
AddObservationCallback callback) override {
RecordCall("AddObservation", std::move(observation));
callback(fuchsia::cobalt::Status::OK);
};
void AddStringObservation(uint32_t metric_id, uint32_t encoding_id,
fidl::StringPtr observation,
AddStringObservationCallback callback) override{};
void AddIntObservation(uint32_t metric_id, uint32_t encoding_id,
const int64_t observation,
AddIntObservationCallback callback) override{};
void AddDoubleObservation(uint32_t metric_id, uint32_t encoding_id,
const double observation,
AddDoubleObservationCallback callback) override{};
void AddIndexObservation(uint32_t metric_id, uint32_t encoding_id,
uint32_t index,
AddIndexObservationCallback callback) override{};
void AddIntBucketDistribution(
uint32_t metric_id, uint32_t encoding_id,
fidl::VectorPtr<fuchsia::cobalt::BucketDistributionEntry> distribution,
AddIntBucketDistributionCallback callback) override {}
void StartTimer(uint32_t metric_id, uint32_t encoding_id,
fidl::StringPtr timer_id, uint64_t timestamp,
uint32_t timeout_s, StartTimerCallback callback) override{};
void EndTimer(fidl::StringPtr timer_id, uint64_t timestamp,
uint32_t timeout_s, EndTimerCallback callback) override{};
void EndTimerMultiPart(
fidl::StringPtr timer_id, uint64_t timestamp, fidl::StringPtr part_name,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> observations,
uint32_t timeout_s, EndTimerMultiPartCallback callback) override{};
void AddMultipartObservation(
uint32_t metric_id,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> observation,
AddMultipartObservationCallback callback) override {
RecordCall("AddMultipartObservation", std::move(observation));
callback(fuchsia::cobalt::Status::OK);
}
void SendObservations(SendObservationsCallback callback) override{};
void ExpectCalledOnceWith(const std::string& func,
const fuchsia::cobalt::Value& expected) {
EXPECT_EQ(1U, calls_.count(func));
if (calls_.count(func) > 0) {
EXPECT_EQ(1U, calls_[func].size());
fuchsia::cobalt::Value& actual = calls_[func][0];
EXPECT_EQ(expected.Which(), actual.Which());
EXPECT_TRUE(Equals(actual, expected));
}
}
void ExpectCalledOnceWith(
const std::string& func,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue>& expected_parts) {
EXPECT_EQ(1U, multipart_calls_.count(func));
if (multipart_calls_.count(func) > 0) {
EXPECT_EQ(1U, multipart_calls_[func].size());
fidl::VectorPtr<fuchsia::cobalt::ObservationValue>& actual =
multipart_calls_[func][0];
EXPECT_TRUE(Equals(actual, expected_parts));
}
}
private:
void RecordCall(const std::string& func, fuchsia::cobalt::Value value) {
calls_[func].push_back(std::move(value));
}
void RecordCall(const std::string& func,
fidl::VectorPtr<fuchsia::cobalt::ObservationValue> parts) {
multipart_calls_[func].push_back(std::move(parts));
}
std::map<std::string, std::vector<fuchsia::cobalt::Value>> calls_;
std::map<std::string,
std::vector<fidl::VectorPtr<fuchsia::cobalt::ObservationValue>>>
multipart_calls_;
};
class FakeCobaltEncoderFactoryImpl : public fuchsia::cobalt::EncoderFactory {
public:
FakeCobaltEncoderFactoryImpl() {}
void GetEncoder(
int32_t project_id,
fidl::InterfaceRequest<fuchsia::cobalt::Encoder> request) override {
cobalt_encoder_.reset(new FakeCobaltEncoderImpl());
cobalt_encoder_bindings_.AddBinding(cobalt_encoder_.get(),
std::move(request));
}
void GetEncoderForProject(
fuchsia::cobalt::ProjectProfile profile,
fidl::InterfaceRequest<fuchsia::cobalt::Encoder> request,
GetEncoderForProjectCallback callback) override {
cobalt_encoder_.reset(new FakeCobaltEncoderImpl());
cobalt_encoder_bindings_.AddBinding(cobalt_encoder_.get(),
std::move(request));
callback(fuchsia::cobalt::Status::OK);
}
FakeCobaltEncoderImpl* cobalt_encoder() { return cobalt_encoder_.get(); }
private:
std::unique_ptr<FakeCobaltEncoderImpl> cobalt_encoder_;
fidl::BindingSet<fuchsia::cobalt::Encoder> cobalt_encoder_bindings_;
};
class CobaltTest : public gtest::TestLoopFixture {
public:
CobaltTest() : context_(InitStartupContext()) {}
~CobaltTest() override {}
component::StartupContext* context() { return context_.get(); }
FakeCobaltEncoderImpl* cobalt_encoder() {
return factory_impl_->cobalt_encoder();
}
private:
std::unique_ptr<component::StartupContext> InitStartupContext() {
factory_impl_.reset(new FakeCobaltEncoderFactoryImpl());
service_provider.AddService<fuchsia::cobalt::EncoderFactory>(
[this](
fidl::InterfaceRequest<fuchsia::cobalt::EncoderFactory> request) {
factory_bindings_.AddBinding(factory_impl_.get(), std::move(request));
});
service_provider.AddService<fuchsia::sys::Environment>(
[this](fidl::InterfaceRequest<fuchsia::sys::Environment> request) {
app_environment_request_ = std::move(request);
});
service_provider.AddService<fuchsia::sys::Launcher>(
[this](fidl::InterfaceRequest<fuchsia::sys::Launcher> request) {
launcher_request_ = std::move(request);
});
return std::make_unique<component::StartupContext>(
service_provider.OpenAsDirectory(), zx::channel());
}
component::ServiceProviderBridge service_provider;
std::unique_ptr<FakeCobaltEncoderFactoryImpl> factory_impl_;
std::unique_ptr<FakeCobaltEncoderImpl> cobalt_encoder_;
std::unique_ptr<component::StartupContext> context_;
fidl::BindingSet<fuchsia::cobalt::EncoderFactory> factory_bindings_;
fidl::InterfaceRequest<fuchsia::sys::Launcher> launcher_request_;
fidl::InterfaceRequest<fuchsia::sys::Environment> app_environment_request_;
FXL_DISALLOW_COPY_AND_ASSIGN(CobaltTest);
};
TEST_F(CobaltTest, InitializeCobalt) {
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
EXPECT_NE(cobalt_context, nullptr);
ac.call();
EXPECT_EQ(cobalt_context, nullptr);
}
TEST_F(CobaltTest, ReportIndexObservation) {
fuchsia::cobalt::Value value;
value.set_index_value(123);
CobaltObservation observation(kFakeCobaltMetricId, kFakeCobaltEncodingId,
fidl::Clone(value));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddObservation", value);
}
TEST_F(CobaltTest, ReportIntObservation) {
fuchsia::cobalt::Value value;
value.set_int_value(123);
CobaltObservation observation(kFakeCobaltMetricId, kFakeCobaltEncodingId,
fidl::Clone(value));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddObservation", value);
}
TEST_F(CobaltTest, ReportDoubleObservation) {
fuchsia::cobalt::Value value;
value.set_double_value(1.5);
CobaltObservation observation(kFakeCobaltMetricId, kFakeCobaltEncodingId,
fidl::Clone(value));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddObservation", value);
}
TEST_F(CobaltTest, ReportStringObservation) {
fuchsia::cobalt::Value value;
value.set_string_value("test");
CobaltObservation observation(kFakeCobaltMetricId, kFakeCobaltEncodingId,
fidl::Clone(value));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddObservation", value);
}
TEST_F(CobaltTest, ReportIntBucketObservation) {
fuchsia::cobalt::Value value;
auto distribution =
fidl::VectorPtr<fuchsia::cobalt::BucketDistributionEntry>::New(2);
distribution->at(0).index = 1;
distribution->at(0).count = 2;
distribution->at(1).index = 2;
distribution->at(1).count = 3;
value.set_int_bucket_distribution(std::move(distribution));
CobaltObservation observation(kFakeCobaltMetricId, kFakeCobaltEncodingId,
fidl::Clone(value));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddObservation", value);
}
TEST_F(CobaltTest, ReportMultipartObservation) {
auto parts = fidl::VectorPtr<fuchsia::cobalt::ObservationValue>::New(2);
parts->at(0).name = "part1";
parts->at(0).encoding_id = kFakeCobaltEncodingId;
parts->at(0).value.set_string_value("test");
parts->at(1).name = "part2";
parts->at(1).encoding_id = kFakeCobaltEncodingId;
parts->at(1).value.set_int_value(2);
CobaltObservation observation(static_cast<uint32_t>(kFakeCobaltMetricId),
fidl::Clone(parts));
CobaltContext* cobalt_context = nullptr;
fsl::SizedVmo fake_cobalt_config;
ASSERT_TRUE(fsl::VmoFromString(kFakeCobaltConfig, &fake_cobalt_config));
auto ac = InitializeCobalt(async_get_default_dispatcher(), context(),
std::move(fake_cobalt_config), &cobalt_context);
RunLoopUntilIdle();
ReportObservation(observation, cobalt_context);
RunLoopUntilIdle();
cobalt_encoder()->ExpectCalledOnceWith("AddMultipartObservation", parts);
}
} // namespace
} // namespace cobalt