blob: a225ac9ee76b82cd3af3785b08223df3804cc483 [file] [log] [blame]
// Copyright 2019 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 "src/sys/appmgr/log_connector_impl.h"
#include <lib/fit/function.h>
#include <lib/gtest/real_loop_fixture.h>
#include <lib/syslog/cpp/macros.h>
#include <gtest/gtest.h>
namespace component {
namespace {
class LogConnectorImplTest : public gtest::RealLoopFixture {
protected:
LogConnectorImplTest() {}
};
// A LogConnectionListener utility used for testing. Upon construction, takes the consumer using
// thet log connector and forwards any new connections.
class FakeLogConnectionListener : fuchsia::sys::internal::LogConnectionListener {
public:
FakeLogConnectionListener(
LogConnectorImpl* connector_impl,
fit::function<void(fuchsia::sys::internal::LogConnection)> on_new_connection)
: binding_(this), on_new_connection_(std::move(on_new_connection)) {
connector_impl->AddConnectorClient(connector_.NewRequest());
connector_->TakeLogConnectionListener(
[&](fidl::InterfaceRequest<fuchsia::sys::internal::LogConnectionListener> req) {
binding_.Bind(std::move(req));
});
}
private:
// |fuchsia::sys::internal::LogConnectionListener|
void OnNewConnection(fuchsia::sys::internal::LogConnection connection) override {
on_new_connection_(std::move(connection));
}
fidl::Binding<fuchsia::sys::internal::LogConnectionListener> binding_;
fit::function<void(fuchsia::sys::internal::LogConnection)> on_new_connection_;
fuchsia::sys::internal::LogConnectorPtr connector_;
};
// Test that there can only be one LogConnectionListener connection for a LogConnectorImpl
// per-realm.
TEST_F(LogConnectorImplTest, OneConsumerPerRealm) {
LogConnectorImpl log_conn_impl("realm1");
fuchsia::sys::internal::LogConnectorPtr log_conn;
log_conn_impl.AddConnectorClient(log_conn.NewRequest());
fidl::InterfaceRequest<fuchsia::sys::internal::LogConnectionListener> consumer_req;
log_conn->TakeLogConnectionListener(
[&](fidl::InterfaceRequest<fuchsia::sys::internal::LogConnectionListener> req) {
consumer_req = std::move(req);
});
// Wait until the above TakeLogConnectionListener call responds.
RunLoopUntil([&] { return consumer_req.is_valid(); });
// Calling TakeLogConnectionListener() again should return a null request<LogConnectionListener>
// since we already received a valid one above.
bool response_received = false;
fidl::InterfaceRequest<fuchsia::sys::internal::LogConnectionListener> consumer_req2;
log_conn->TakeLogConnectionListener(
[&](fidl::InterfaceRequest<fuchsia::sys::internal::LogConnectionListener> req) {
response_received = true;
consumer_req2 = std::move(req);
});
RunLoopUntil([&] { return response_received; });
EXPECT_FALSE(consumer_req2.is_valid());
}
// Test that log sinks are attributed per connection, and attributed to a component's identity
// (realm path and component URL).
TEST_F(LogConnectorImplTest, AttributedSourceIdentity) {
const char kRootRealm[] = "root_realm";
LogConnectorImpl root(kRootRealm);
std::vector<fuchsia::sys::internal::LogConnection> connections;
FakeLogConnectionListener root_log_consumer(
&root, /* on_new_connection */ [&](fuchsia::sys::internal::LogConnection conn) {
connections.push_back(std::move(conn));
});
const char kChildRealm[] = "child_realm";
const char kGrandChildRealm[] = "grandchild_realm";
auto child = root.NewChild(kChildRealm);
auto grandchild = child->NewChild(kGrandChildRealm);
fuchsia::logger::LogSinkPtr child_log_sink;
const char kFakeComponentUrl[] = "fuchsia-pkg://fuchsia.com/test#meta/test.cmx";
// Add connection and wait until we intercept it
grandchild->AddLogConnection(kFakeComponentUrl, "-1", child_log_sink.NewRequest());
RunLoopUntil([&] { return connections.size() == 1; });
EXPECT_EQ(kFakeComponentUrl, connections[0].source_identity.component_url());
EXPECT_EQ("test.cmx", connections[0].source_identity.component_name());
EXPECT_EQ(std::vector<std::string>({kChildRealm, kGrandChildRealm}),
connections[0].source_identity.realm_path());
}
} // namespace
} // namespace component