blob: 4edb7e0624327177aea025831d78ff5ddd93e4c3 [file] [log] [blame]
// Copyright 2021 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 <fuchsia/debugdata/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_ptr.h>
#include <lib/zx/time.h>
#include <zircon/errors.h>
#include <zircon/rights.h>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <src/lib/fxl/strings/string_printf.h>
#include <src/lib/testing/loop_fixture/real_loop_fixture.h>
#include "abstract_data_processor.h"
#include "common.h"
#include "event_stream.h"
using EventStreamTest = gtest::RealLoopFixture;
class TestDataProcessor : public AbstractDataProcessor {
public:
explicit TestDataProcessor(
std::shared_ptr<std::vector<std::pair<std::string, std::vector<DataSinkDump>>>> vec)
: vec_(std::move(vec)) {}
void ProcessData(std::string test_url, std::vector<DataSinkDump> data_sink_vec) override {
vec_->emplace_back(std::move(test_url), std::move(data_sink_vec));
}
std::shared_ptr<std::vector<std::pair<std::string, std::vector<DataSinkDump>>>> vec_;
};
class TestInfo : public fuchsia::test::internal::Info {
public:
TestInfo() = default;
explicit TestInfo(std::map<std::string, std::string> map) : map_(std::move(map)) {}
fidl::InterfacePtr<fuchsia::test::internal::Info> GetPtr() {
fidl::InterfacePtr<fuchsia::test::internal::Info> info;
bindings_.AddBinding(this, info.NewRequest());
return info;
}
void AddMapping(std::string moniker, std::string test_url) {
map_[std::move(moniker)] = std::move(test_url);
}
void GetTestUrl(std::string moniker, GetTestUrlCallback callback) override {
fuchsia::test::internal::Info_GetTestUrl_Result result;
auto it = map_.find(moniker);
if (it != map_.end()) {
result.set_response(fuchsia::test::internal::Info_GetTestUrl_Response(it->second));
} else {
result.set_err(ZX_ERR_NOT_FOUND);
}
callback(std::move(result));
}
private:
std::map<std::string, std::string> map_;
fidl::BindingSet<fuchsia::test::internal::Info> bindings_;
};
fuchsia::debugdata::DebugDataPtr SendCapabilityRequestedEvent(
const fidl::InterfacePtr<fuchsia::sys2::EventStream>& event_stream_ptr, std::string moniker) {
fuchsia::debugdata::DebugDataPtr debug_data_ptr;
fuchsia::sys2::Event event;
fuchsia::sys2::EventHeader header;
header.set_moniker(std::move(moniker));
header.set_event_type(fuchsia::sys2::EventType::CAPABILITY_REQUESTED);
event.set_header(std::move(header));
fuchsia::sys2::EventResult event_result;
fuchsia::sys2::EventPayload payload;
fuchsia::sys2::CapabilityRequestedPayload p;
p.set_capability(debug_data_ptr.NewRequest().TakeChannel());
payload.set_capability_requested(std::move(p));
event_result.set_payload(std::move(payload));
event.set_event_result(std::move(event_result));
event_stream_ptr->OnEvent(std::move(event));
return debug_data_ptr;
}
void SendComponentStopEvent(const fidl::InterfacePtr<fuchsia::sys2::EventStream>& event_stream_ptr,
std::string moniker) {
fuchsia::sys2::Event event;
fuchsia::sys2::EventHeader header;
header.set_moniker(std::move(moniker));
header.set_event_type(fuchsia::sys2::EventType::STOPPED);
event.set_header(std::move(header));
event_stream_ptr->OnEvent(std::move(event));
}
zx::vmo GetVmo() {
zx::vmo vmo;
zx::vmo::create(100, 0, &vmo);
return vmo;
}
TEST_F(EventStreamTest, Test) {
auto shared_vec =
std::make_shared<std::vector<std::pair<std::string, std::vector<DataSinkDump>>>>();
std::unique_ptr<AbstractDataProcessor> data_sink_processor =
std::make_unique<TestDataProcessor>(shared_vec);
std::map<std::string, std::string> moniker_url_map = {
{"foo/bar", "foo_bar.cm"}, {"foo", "foo.cm"}, {"bar/foo", "bar_foo.cm"}};
TestInfo info(moniker_url_map);
fidl::InterfacePtr<fuchsia::sys2::EventStream> event_stream_ptr;
EventStreamImpl event_stream(event_stream_ptr.NewRequest(), info.GetPtr(),
std::move(data_sink_processor), dispatcher());
// Test simple case, where events are in order
auto foo_bar_ptr = SendCapabilityRequestedEvent(event_stream_ptr, "foo/bar");
foo_bar_ptr->Publish("foo_bar_sink1", GetVmo());
foo_bar_ptr->Publish("foo_bar_sink2", GetVmo());
foo_bar_ptr->Publish("foo_bar_sink3", GetVmo());
RunLoopUntilIdle();
// as we have not closed the connection, we should not get the VMOs
ASSERT_EQ(shared_vec->size(), 0u);
foo_bar_ptr.Unbind();
SendComponentStopEvent(event_stream_ptr, "foo/bar");
RunLoopUntilIdle();
ASSERT_EQ(shared_vec->size(), 1u);
ASSERT_EQ(shared_vec->at(0).second.size(), 3u);
ASSERT_EQ(shared_vec->at(0).first, "foo_bar.cm");
shared_vec->clear();
// Test case, where events are out of order
foo_bar_ptr = SendCapabilityRequestedEvent(event_stream_ptr, "foo/bar");
foo_bar_ptr->Publish("foo_bar_sink1", GetVmo());
foo_bar_ptr->Publish("foo_bar_sink2", GetVmo());
foo_bar_ptr->Publish("foo_bar_sink3", GetVmo());
RunLoopUntilIdle();
// as we have not closed the conenction, we should not get the VMOs
ASSERT_EQ(shared_vec->size(), 0u);
SendComponentStopEvent(event_stream_ptr, "foo/bar");
RunLoopUntilIdle();
ASSERT_EQ(shared_vec->size(), 1u);
ASSERT_EQ(shared_vec->at(0).second.size(), 3u);
ASSERT_EQ(shared_vec->at(0).first, "foo_bar.cm");
// send publish after stop was sent
foo_bar_ptr->Publish("foo_bar_sink1", GetVmo());
foo_bar_ptr->Publish("foo_bar_sink2", GetVmo());
foo_bar_ptr.Unbind();
// make sure we get those VMOs.
RunLoopUntilIdle();
ASSERT_EQ(shared_vec->size(), 2u);
ASSERT_EQ(shared_vec->at(1).second.size(), 2u);
ASSERT_EQ(shared_vec->at(1).first, "foo_bar.cm");
shared_vec->clear();
// send events on multiple monikers
size_t const SIZE = 4;
std::string monikers[SIZE] = {"foo/bar", "foo", "bar/foo", "some/moniker"};
fidl::InterfacePtr<fuchsia::debugdata::DebugData> ptrs[SIZE];
for (size_t i = 0; i < SIZE; i++) {
ptrs[i] = SendCapabilityRequestedEvent(event_stream_ptr, monikers[i]);
}
shared_vec->clear();
std::map<std::string, size_t> count = {
{monikers[0], 2}, {monikers[1], 4}, {monikers[2], 3}, {monikers[3], 5}};
for (size_t i = 0; i < SIZE; i++) {
for (size_t j = 0; j < count[monikers[i]]; j++) {
auto data_sink = fxl::StringPrintf("ds_%zu_%zu", i, j);
ptrs[i]->Publish(data_sink, GetVmo());
}
}
RunLoopUntilIdle();
ASSERT_EQ(shared_vec->size(), 0u);
for (auto& moniker : monikers) {
SendComponentStopEvent(event_stream_ptr, moniker);
}
RunLoopUntilIdle();
ASSERT_EQ(shared_vec->size(), SIZE);
// add url->moniker mapping to map
std::map<std::string, std::string> url_moniker_map;
for (auto& x : moniker_url_map) {
url_moniker_map[x.second] = x.first;
}
url_moniker_map[""] = "some/moniker";
for (size_t i = 0; i < SIZE; i++) {
auto moniker = url_moniker_map[shared_vec->at(i).first];
ASSERT_EQ(shared_vec->at(i).second.size(), count[moniker]) << shared_vec->at(i).first;
}
shared_vec->clear();
}