1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <lib/async-loop/cpp/loop.h> 6#include <lib/fdio/util.h> 7#include <fs/synchronous-vfs.h> 8#include <fs/pseudo-dir.h> 9#include <fs/service.h> 10 11#include <unittest/unittest.h> 12 13namespace { 14 15bool test_service() { 16 BEGIN_TEST; 17 18 // set up a service which can only be bound once (to make it easy to 19 // simulate an error to test error reporting behavior from the connector) 20 zx::channel bound_channel; 21 auto svc = fbl::AdoptRef<fs::Service>(new fs::Service( 22 [&bound_channel](zx::channel channel) { 23 if (bound_channel) 24 return ZX_ERR_IO; 25 bound_channel = fbl::move(channel); 26 return ZX_OK; 27 })); 28 29 // open 30 fbl::RefPtr<fs::Vnode> redirect; 31 EXPECT_EQ(ZX_OK, svc->ValidateFlags(ZX_FS_RIGHT_READABLE)); 32 EXPECT_EQ(ZX_OK, svc->Open(ZX_FS_RIGHT_READABLE, &redirect)); 33 EXPECT_NULL(redirect); 34 EXPECT_EQ(ZX_ERR_NOT_DIR, svc->ValidateFlags(ZX_FS_FLAG_DIRECTORY)); 35 36 // get attr 37 vnattr_t attr; 38 EXPECT_EQ(ZX_OK, svc->Getattr(&attr)); 39 EXPECT_EQ(V_TYPE_FILE, attr.mode); 40 EXPECT_EQ(1, attr.nlink); 41 42 // make some channels we can use for testing 43 zx::channel c1, c2; 44 EXPECT_EQ(ZX_OK, zx::channel::create(0u, &c1, &c2)); 45 zx_handle_t hc1 = c1.get(); 46 47 // serve, the connector will return success the first time 48 fs::SynchronousVfs vfs; 49 EXPECT_EQ(ZX_OK, svc->Serve(&vfs, fbl::move(c1), ZX_FS_RIGHT_READABLE)); 50 EXPECT_EQ(hc1, bound_channel.get()); 51 52 // the connector will return failure because bound_channel is still valid 53 // we test that the error is propagated back up through Serve 54 EXPECT_EQ(ZX_ERR_IO, svc->Serve(&vfs, fbl::move(c2), ZX_FS_RIGHT_READABLE)); 55 EXPECT_EQ(hc1, bound_channel.get()); 56 57 END_TEST; 58} 59 60bool test_serve_directory() { 61 BEGIN_TEST; 62 63 zx::channel client, server; 64 EXPECT_EQ(ZX_OK, zx::channel::create(0u, &client, &server)); 65 66 // open client 67 zx::channel c1, c2; 68 EXPECT_EQ(ZX_OK, zx::channel::create(0u, &c1, &c2)); 69 EXPECT_EQ(ZX_OK, 70 fdio_service_connect_at(client.get(), "abc", c2.release())); 71 72 // close client 73 // We test the semantic that a pending open is processed even if the client 74 // has been closed. 75 client.reset(); 76 77 // serve 78 async::Loop loop(&kAsyncLoopConfigNoAttachToThread); 79 fs::SynchronousVfs vfs(loop.dispatcher()); 80 81 auto directory = fbl::AdoptRef<fs::PseudoDir>(new fs::PseudoDir()); 82 auto vnode = fbl::AdoptRef<fs::Service>(new fs::Service( 83 [&loop](zx::channel channel) { 84 loop.Shutdown(); 85 return ZX_OK; 86 })); 87 directory->AddEntry("abc", vnode); 88 89 EXPECT_EQ(ZX_OK, vfs.ServeDirectory(directory, fbl::move(server))); 90 EXPECT_EQ(ZX_ERR_BAD_STATE, loop.RunUntilIdle()); 91 92 END_TEST; 93} 94 95} // namespace 96 97BEGIN_TEST_CASE(service_tests) 98RUN_TEST(test_service) 99RUN_TEST(test_serve_directory) 100END_TEST_CASE(service_tests) 101