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