blob: 20c68c3a6905c6ecc92415af7ae01dc5b0f94c35 [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 "debugdata.h"
#include <fidl/fuchsia.debugdata/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/wait.h>
#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/fit/defer.h>
#include <lib/zx/channel.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <zircon/sanitizer.h>
#include <zircon/status.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <fbl/string.h>
#include <fbl/unique_fd.h>
#include <fbl/vector.h>
#include <zxtest/zxtest.h>
#include "../sanitizers/fuchsia-io-constants.h"
#include "src/storage/lib/vfs/cpp/pseudo_dir.h"
#include "src/storage/lib/vfs/cpp/service.h"
#include "src/storage/lib/vfs/cpp/synchronous_vfs.h"
#include "src/storage/lib/vfs/cpp/vfs_types.h"
namespace {
constexpr char kTestHelper[] = "/pkg/bin/debugdata-test-helper";
struct Publisher : public fidl::WireServer<fuchsia_debugdata::Publisher> {
std::unordered_map<std::string, zx::vmo> data;
void Publish(PublishRequestView request, PublishCompleter::Sync&) override {
std::string name(request->data_sink.data(), request->data_sink.size());
data.emplace(name, std::move(request->data));
}
void Serve(async_dispatcher_t* dispatcher, std::unique_ptr<fs::SynchronousVfs>* vfs,
fidl::ClientEnd<fuchsia_io::Directory>* client_end) {
auto dir = fbl::MakeRefCounted<fs::PseudoDir>();
auto node = fbl::MakeRefCounted<fs::Service>(
[dispatcher, this](fidl::ServerEnd<fuchsia_debugdata::Publisher> server_end) {
fidl::BindServer(dispatcher, std::move(server_end), this);
return ZX_OK;
});
dir->AddEntry(fidl::DiscoverableProtocolName<fuchsia_debugdata::Publisher>, node);
zx::result server_end = fidl::CreateEndpoints(client_end);
ASSERT_OK(server_end.status_value());
*vfs = std::make_unique<fs::SynchronousVfs>(dispatcher);
ASSERT_OK((*vfs)->ServeDirectory(std::move(dir), std::move(server_end.value()),
fs::Rights::ReadWrite()));
}
};
void RunHelper(const char* mode, const size_t action_count, const fdio_spawn_action_t* fdio_actions,
int expected_return_code) {
zx::job test_job;
ASSERT_OK(zx::job::create(*zx::job::default_job(), 0, &test_job));
auto auto_call_kill_job = fit::defer([&test_job]() { test_job.kill(); });
const char* args[] = {kTestHelper, mode, nullptr};
zx::process process;
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
ASSERT_OK(fdio_spawn_etc(test_job.get(), FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_NAMESPACE,
args[0], args, nullptr, action_count, fdio_actions,
process.reset_and_get_address(), err_msg));
ASSERT_OK(process.wait_one(ZX_PROCESS_TERMINATED, zx::time::infinite(), nullptr));
zx_info_process_t proc_info;
ASSERT_OK(process.get_info(ZX_INFO_PROCESS, &proc_info, sizeof(proc_info), nullptr, nullptr));
ASSERT_EQ(expected_return_code, proc_info.return_code);
}
void RunHelperWithSvc(const char* mode, fidl::ClientEnd<fuchsia_io::Directory> client_end,
int expected_return_code) {
fdio_spawn_action_t fdio_actions[] = {
fdio_spawn_action_t{
.action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY,
.ns =
{
.prefix = "/svc",
.handle = client_end.TakeChannel().release(),
},
},
};
RunHelper(mode, 1, fdio_actions, expected_return_code);
}
void RunHelperWithoutSvc(const char* mode, int expected_return_code) {
RunHelper(mode, 0, nullptr, expected_return_code);
}
TEST(DebugDataTests, PublishData) {
async::Loop loop{&kAsyncLoopConfigNoAttachToCurrentThread};
std::unique_ptr<fs::SynchronousVfs> vfs;
fidl::ClientEnd<fuchsia_io::Directory> client_end;
Publisher svc;
ASSERT_NO_FATAL_FAILURE(svc.Serve(loop.dispatcher(), &vfs, &client_end));
ASSERT_NO_FATAL_FAILURE(RunHelperWithSvc("publish_data", std::move(client_end), 0));
ASSERT_OK(loop.RunUntilIdle());
loop.Shutdown();
vfs.reset();
auto it = svc.data.find(kTestName);
ASSERT_TRUE(it != svc.data.end());
char content[sizeof(kTestData)];
ASSERT_OK(it->second.read(content, 0, sizeof(content)));
ASSERT_EQ(memcmp(content, kTestData, sizeof(kTestData)), 0);
}
TEST(DebugDataTests, PublishDataWithoutSvc) {
ASSERT_NO_FATAL_FAILURE(RunHelperWithoutSvc("publish_data", 0));
}
// debugdata.cc cannot use LLCPP (because it allocates with new/delete) so
// instead defines a local set of a few constants and structure definition in
// fuchsia-io-constants.h to call fuchsia.io.Directory/Open(). Confirm that the
// local copy matches the canonical definition here.
static_assert(fuchsia_io_DirectoryOpenOrdinal ==
fidl::internal::WireOrdinal<fuchsia_io::Directory::Open>::value);
static_assert(fidl::TypeTraits<fidl::internal::TransactionalRequest<fuchsia_io::Directory::Open>>::
kPrimarySize == sizeof(fuchsia_io_DirectoryOpenRequest));
} // anonymous namespace