blob: 7de848a0ab2fe8b3bc2abe26d6facd9a3301d77b [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 "system_instance.h"
#include <fuchsia/io/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/namespace.h>
#include <lib/fidl-async/bind.h>
#include <memory>
#include <zxtest/zxtest.h>
namespace {
// Create a subclass to access the protected test-only constructor on SystemInstance.
class SystemInstanceForTest : public SystemInstance {
public:
SystemInstanceForTest(fdio_ns_t* default_ns_) : SystemInstance(default_ns_) {}
};
struct Context {
uint32_t open_flags;
uint32_t open_count;
char path[PATH_MAX + 1];
};
static zx_status_t DirectoryOpen(void* ctx, uint32_t flags, uint32_t mode, const char* path_data,
size_t path_size, zx_handle_t object) {
Context* context = reinterpret_cast<Context*>(ctx);
context->open_flags = flags;
context->open_count += 1;
memcpy(context->path, path_data, path_size);
context->path[path_size] = '\0';
// Having this handle still open does not spark joy. Thank it for its
// service, and then let it go.
zx_handle_close(object);
return ZX_OK;
}
static const fuchsia_io_DirectoryAdmin_ops_t kDirectoryAdminOps = []() {
fuchsia_io_DirectoryAdmin_ops_t ops;
ops.Open = DirectoryOpen;
return ops;
}();
class SystemInstanceFsProvider : public zxtest::Test {
protected:
SystemInstanceFsProvider() : loop_(&kAsyncLoopConfigNoAttachToCurrentThread) {
ASSERT_OK(loop_.StartThread());
// We want to create an alternative namespace for this test to use, to keep
// this test hermetic wrt. other running tests.
zx_status_t status = fdio_ns_create(&ns_for_test_);
ZX_ASSERT_MSG(status == ZX_OK, "driver_manager: cannot create namespace: %s\n",
zx_status_get_string(status));
// Mock out an object that implements DirectoryOpen and records some state.
// Bind it to the server handle, and provide that to SystemInstance as the fs_root connection.
zx::channel client, server;
ASSERT_OK(zx::channel::create(0, &client, &server));
ASSERT_OK(fidl_bind(loop_.dispatcher(), server.release(),
reinterpret_cast<fidl_dispatch_t*>(fuchsia_io_DirectoryAdmin_dispatch),
&context_, &kDirectoryAdminOps));
ASSERT_OK(fdio_ns_bind(ns_for_test_, "/", client.release()));
under_test_.reset(new SystemInstanceForTest(ns_for_test_));
}
void CloneFsAndCheckFlags(const char* path, uint32_t expected_flags) {
uint32_t starting_open_count = context_.open_count;
zx::channel fs_connection = under_test_->CloneFs(path);
// Force a describe call on the target of the Open, to resolve the Open. We expect this to fail
// because our mock just closes the channel after Open.
int fd;
EXPECT_EQ(ZX_ERR_PEER_CLOSED, fdio_fd_create(fs_connection.release(), &fd));
EXPECT_EQ(starting_open_count + 1, context_.open_count);
EXPECT_EQ(expected_flags, context_.open_flags);
EXPECT_STR_EQ(path, context_.path);
}
private:
async::Loop loop_;
fdio_ns_t* ns_for_test_;
Context context_;
std::unique_ptr<SystemInstanceForTest> under_test_;
};
} // namespace