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