| // 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 |