• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
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 "base/fuchsia/scoped_service_binding.h"
6 
7 #include <lib/async/default.h>
8 #include <lib/sys/cpp/component_context.h>
9 
10 #include "base/fuchsia/process_context.h"
11 #include "base/fuchsia/test_component_context_for_process.h"
12 #include "base/fuchsia/test_interface_natural_impl.h"
13 #include "base/run_loop.h"
14 #include "base/test/bind.h"
15 #include "base/test/task_environment.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace base {
19 
20 class ScopedNaturalServiceBindingTest : public testing::Test {
21  protected:
22   ScopedNaturalServiceBindingTest() = default;
23   ~ScopedNaturalServiceBindingTest() override = default;
24 
25   const base::test::SingleThreadTaskEnvironment task_environment_{
26       base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
27 
28   TestComponentContextForProcess test_context_;
29   TestInterfaceNaturalImpl test_service_;
30 };
31 
32 // Verifies that ScopedNaturalServiceBinding allows more than one simultaneous
33 // client.
TEST_F(ScopedNaturalServiceBindingTest,ConnectTwice)34 TEST_F(ScopedNaturalServiceBindingTest, ConnectTwice) {
35   ScopedNaturalServiceBinding<base_testfidl::TestInterface> binding(
36       ComponentContextForProcess()->outgoing().get(), &test_service_);
37 
38   auto stub =
39       CreateTestInterfaceClient(test_context_.published_services_natural());
40   auto stub2 =
41       CreateTestInterfaceClient(test_context_.published_services_natural());
42   EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
43   EXPECT_EQ(VerifyTestInterface(stub2), ZX_OK);
44 }
45 
46 // Verifies that ScopedNaturalServiceBinding allows more than one simultaneous
47 // client with a non-default discovery name.
TEST_F(ScopedNaturalServiceBindingTest,ConnectTwiceNameOverride)48 TEST_F(ScopedNaturalServiceBindingTest, ConnectTwiceNameOverride) {
49   const char kInterfaceName[] = "fuchsia.TestInterface2";
50 
51   ScopedNaturalServiceBinding<base_testfidl::TestInterface> new_service_binding(
52       ComponentContextForProcess()->outgoing().get(), &test_service_,
53       kInterfaceName);
54 
55   auto stub = CreateTestInterfaceClient(
56       test_context_.published_services_natural(), kInterfaceName);
57   auto stub2 = CreateTestInterfaceClient(
58       test_context_.published_services_natural(), kInterfaceName);
59   EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
60   EXPECT_EQ(VerifyTestInterface(stub2), ZX_OK);
61 }
62 
63 // Verify that we can publish a debug `TestInterface` service.
TEST_F(ScopedNaturalServiceBindingTest,ConnectDebugService)64 TEST_F(ScopedNaturalServiceBindingTest, ConnectDebugService) {
65   vfs::PseudoDir* const debug_dir =
66       ComponentContextForProcess()->outgoing()->debug_dir();
67 
68   // Publish the test service to the "debug" directory.
69   ScopedNaturalServiceBinding<base_testfidl::TestInterface>
70       debug_service_binding(debug_dir, &test_service_);
71 
72   // Connect a `ClientEnd` to the "debug" subdirectory.
73   auto debug_directory_endpoints =
74       fidl::CreateEndpoints<fuchsia_io::Directory>();
75   ASSERT_TRUE(debug_directory_endpoints.is_ok())
76       << debug_directory_endpoints.status_string();
77   debug_dir->Serve(fuchsia::io::OpenFlags::RIGHT_READABLE |
78                        fuchsia::io::OpenFlags::RIGHT_WRITABLE,
79                    debug_directory_endpoints->server.TakeChannel());
80 
81   // Attempt to connect via the "debug" directory.
82   auto debug_stub =
83       CreateTestInterfaceClient(std::move(debug_directory_endpoints->client));
84   EXPECT_EQ(VerifyTestInterface(debug_stub), ZX_OK);
85 
86   // Verify that the `TestInterface` service does not appear in the outgoing
87   // service directory.
88   auto release_stub =
89       CreateTestInterfaceClient(test_context_.published_services_natural());
90   EXPECT_EQ(VerifyTestInterface(release_stub), ZX_ERR_NOT_FOUND);
91 }
92 
93 // Test the last client callback is called every time the number of active
94 // clients reaches 0.
TEST_F(ScopedNaturalServiceBindingTest,MultipleLastClientCallback)95 TEST_F(ScopedNaturalServiceBindingTest, MultipleLastClientCallback) {
96   ScopedNaturalServiceBinding<base_testfidl::TestInterface> binding(
97       ComponentContextForProcess()->outgoing().get(), &test_service_);
98   int disconnect_count = 0;
99   binding.SetOnLastClientCallback(
100       BindLambdaForTesting([&disconnect_count] { ++disconnect_count; }));
101 
102   // Connect a client, verify it is functional.
103   {
104     auto stub =
105         CreateTestInterfaceClient(test_context_.published_services_natural());
106     EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
107   }
108 
109   // Client disconnected on going out of scope, the callback should have been
110   // called once.
111   RunLoop().RunUntilIdle();
112   EXPECT_EQ(disconnect_count, 1);
113 
114   // Connect another client, verify it is functional.
115   {
116     auto stub =
117         CreateTestInterfaceClient(test_context_.published_services_natural());
118     EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
119   }
120 
121   // Client disconnected on going out of scope, the callback should have been
122   // called a second time.
123   RunLoop().RunUntilIdle();
124   EXPECT_EQ(disconnect_count, 2);
125 }
126 
127 // Test the last client callback is called every time the number of active
128 // clients reaches 0.
TEST_F(ScopedNaturalServiceBindingTest,LastClientCallbackOnlyForLastClient)129 TEST_F(ScopedNaturalServiceBindingTest, LastClientCallbackOnlyForLastClient) {
130   ScopedNaturalServiceBinding<base_testfidl::TestInterface> binding(
131       ComponentContextForProcess()->outgoing().get(), &test_service_);
132   int disconnect_count = 0;
133   binding.SetOnLastClientCallback(
134       BindLambdaForTesting([&disconnect_count] { ++disconnect_count; }));
135 
136   {
137     // Connect a long lived client, verify it is functional.
138     auto long_lived_stub =
139         CreateTestInterfaceClient(test_context_.published_services_natural());
140     EXPECT_EQ(VerifyTestInterface(long_lived_stub), ZX_OK);
141 
142     // Connect a client, verify it is functional.
143     {
144       auto stub =
145           CreateTestInterfaceClient(test_context_.published_services_natural());
146       EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
147     }
148 
149     // Client disconnected on going out of scope, the callback should not have
150     // been called because the long-lived client is still connected.
151     RunLoop().RunUntilIdle();
152     EXPECT_EQ(disconnect_count, 0);
153 
154     // Connect another client, verify it is functional.
155     {
156       auto stub =
157           CreateTestInterfaceClient(test_context_.published_services_natural());
158       EXPECT_EQ(VerifyTestInterface(stub), ZX_OK);
159     }
160 
161     // Client disconnected on going out of scope, the callback should not have
162     // been called because the long-lived client is still connected.
163     RunLoop().RunUntilIdle();
164     EXPECT_EQ(disconnect_count, 0);
165   }
166 
167   // Long lived client disconnected on going out of scope, the callback should
168   // have been called a third time.
169   RunLoop().RunUntilIdle();
170   EXPECT_EQ(disconnect_count, 1);
171 }
172 
173 }  // namespace base
174