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