blob: 57ab143070e95bfa5cc2cbae04f851cc31913c36 [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_BRINGUP_BIN_NETSVC_TEST_PAVER_TEST_COMMON_H_
#define SRC_BRINGUP_BIN_NETSVC_TEST_PAVER_TEST_COMMON_H_
#include <fidl/fuchsia.device/cpp/wire.h>
#include <fidl/fuchsia.fshost/cpp/wire.h>
#include <fidl/fuchsia.fshost/cpp/wire_test_base.h>
#include <fidl/fuchsia.paver/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/async/dispatcher.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/devmgr-integration-test/fixture.h>
#include <lib/fdio/fd.h>
#include <lib/netboot/netboot.h>
#include <lib/sync/completion.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/channel.h>
#include <lib/zx/time.h>
#include <threads.h>
#include <zircon/errors.h>
#include <zircon/time.h>
#include <algorithm>
#include <memory>
#include <vector>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include <ramdevice-client/ramdisk.h>
#include <zxtest/zxtest.h>
#include "src/bringup/bin/netsvc/paver.h"
#include "src/storage/testing/fake-paver.h"
class FakeFshost : public fidl::testing::WireTestBase<fuchsia_fshost::Admin> {
public:
FakeFshost() = default;
FakeFshost(const FakeFshost&) = delete;
FakeFshost& operator=(const FakeFshost&) = delete;
void WriteDataFile(WriteDataFileRequestView request,
WriteDataFileCompleter::Sync& completer) override {
data_file_path_ = request->filename.get();
completer.ReplySuccess();
}
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
FAIL("Unexpected call to fuchsia.fshost.Admin: %s", name.c_str());
}
const std::string& data_file_path() const { return data_file_path_; }
private:
std::string data_file_path_;
};
class FakeSvc {
public:
explicit FakeSvc(async_dispatcher_t* dispatcher) {
zx::result server_end = fidl::CreateEndpoints(&root_);
ASSERT_OK(server_end);
async::PostTask(dispatcher, [dispatcher, &fake_paver = fake_paver_, &fake_fshost = fake_fshost_,
server_end = std::move(server_end.value())]() mutable {
component::OutgoingDirectory outgoing{dispatcher};
ASSERT_OK(outgoing.AddUnmanagedProtocol<fuchsia_paver::Paver>(
[&fake_paver, dispatcher](fidl::ServerEnd<fuchsia_paver::Paver> server_end) mutable {
fake_paver.Connect(dispatcher, std::move(server_end));
}));
ASSERT_OK(outgoing.AddUnmanagedProtocol<fuchsia_fshost::Admin>(
[&fake_fshost, dispatcher](fidl::ServerEnd<fuchsia_fshost::Admin> server_end) {
fidl::BindServer(dispatcher, std::move(server_end), &fake_fshost);
}));
zx::result result = outgoing.Serve(std::move(server_end));
ASSERT_OK(result);
// Stash the outgoing directory on the dispatcher so that the dtor runs on the dispatcher
// thread.
async::PostDelayedTask(
dispatcher, [outgoing = std::move(outgoing)]() {}, zx::duration::infinite());
});
}
paver_test::FakePaver& fake_paver() { return fake_paver_; }
FakeFshost& fake_fshost() { return fake_fshost_; }
zx::result<fidl::ClientEnd<fuchsia_io::Directory>> svc() {
return component::ConnectAt<fuchsia_io::Directory>(
root_, component::OutgoingDirectory::kServiceDirectory);
}
private:
paver_test::FakePaver fake_paver_;
FakeFshost fake_fshost_;
fidl::ClientEnd<fuchsia_io::Directory> root_;
};
class FakeDev {
public:
explicit FakeDev(async_dispatcher_t* dispatcher) {
auto args = devmgr_integration_test::IsolatedDevmgr::DefaultArgs();
args.root_device_driver = "fuchsia-boot:///platform-bus#meta/platform-bus.cm";
zx::result devmgr =
devmgr_integration_test::IsolatedDevmgr::Create(std::move(args), dispatcher);
ASSERT_OK(devmgr.status_value());
devmgr_ = std::move(devmgr.value());
// TODO(https://fxbug.dev/42161201): Stop requiring this recursive wait.
ASSERT_OK(device_watcher::RecursiveWaitForFile(devmgr_.devfs_root().get(),
"sys/platform/ram-disk/ramctl")
.status_value());
}
devmgr_integration_test::IsolatedDevmgr devmgr_;
};
class PaverTest : public zxtest::Test {
protected:
PaverTest()
: loop_(&kAsyncLoopConfigNeverAttachToThread),
paver_(
[this]() {
zx::channel client;
EXPECT_OK(fdio_fd_clone(fake_dev_.devmgr_.devfs_root().get(),
client.reset_and_get_address()));
return fidl::ClientEnd<fuchsia_io::Directory>{std::move(client)};
}(),
[this]() {
zx::result svc = fake_svc_.svc();
EXPECT_OK(svc);
return std::move(svc.value());
}()) {}
~PaverTest() override {
// Need to make sure paver thread exits.
paver_.exit_code().wait();
if (ramdisk_ != nullptr) {
ramdisk_destroy(ramdisk_);
ramdisk_ = nullptr;
}
}
void SpawnBlockDevice() {
ASSERT_OK(device_watcher::RecursiveWaitForFile(fake_dev_.devmgr_.devfs_root().get(),
"sys/platform/ram-disk/ramctl")
.status_value());
ASSERT_OK(ramdisk_create_at(fake_dev_.devmgr_.devfs_root().get(), zx_system_get_page_size(),
100, &ramdisk_));
std::string expected = std::string("/dev/") + ramdisk_get_path(ramdisk_);
fake_svc_.fake_paver().set_expected_device(expected);
}
async::Loop loop_;
ramdisk_client_t* ramdisk_ = nullptr;
FakeSvc fake_svc_{loop_.dispatcher()};
FakeDev fake_dev_{loop_.dispatcher()};
netsvc::Paver paver_;
};
#endif // SRC_BRINGUP_BIN_NETSVC_TEST_PAVER_TEST_COMMON_H_