Upload upstream chromium 108.0.5359.1
[platform/framework/web/chromium-efl.git] / services / device / serial / serial_port_impl_unittest.cc
1 // Copyright 2017 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 "services/device/serial/serial_port_impl.h"
6
7 #include "base/test/bind.h"
8 #include "mojo/public/cpp/bindings/pending_remote.h"
9 #include "mojo/public/cpp/bindings/remote.h"
10 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
11 #include "mojo/public/cpp/system/data_pipe.h"
12 #include "mojo/public/cpp/system/simple_watcher.h"
13 #include "services/device/device_service_test_base.h"
14 #include "services/device/public/mojom/serial.mojom.h"
15 #include "services/device/serial/serial_io_handler.h"
16
17 namespace device {
18
19 namespace {
20
21 class FakeSerialIoHandler : public SerialIoHandler {
22  public:
23   FakeSerialIoHandler()
24       : SerialIoHandler(base::FilePath(), /*ui_thread_task_runner=*/nullptr) {}
25
26   void SimulateOpenFailure(bool fail) { fail_open_ = fail; }
27
28   void SimulateGetControlSignalsFailure(bool fail) {
29     fail_get_control_signals_ = fail;
30   }
31
32   void SimulateSetControlSignalsFailure(bool fail) {
33     fail_set_control_signals_ = fail;
34   }
35
36   // SerialIoHandler implementation
37   void Open(const mojom::SerialConnectionOptions& options,
38             OpenCompleteCallback callback) override {
39     std::move(callback).Run(!fail_open_);
40   }
41
42   void Flush(mojom::SerialPortFlushMode mode) const override {}
43   void Drain() override {}
44
45   mojom::SerialPortControlSignalsPtr GetControlSignals() const override {
46     if (fail_get_control_signals_)
47       return nullptr;
48
49     return input_signals_.Clone();
50   }
51
52   bool SetControlSignals(
53       const mojom::SerialHostControlSignals& control_signals) override {
54     if (fail_set_control_signals_)
55       return false;
56
57     output_signals_ = control_signals;
58     return true;
59   }
60
61   mojom::SerialConnectionInfoPtr GetPortInfo() const override {
62     return mojom::SerialConnectionInfo::New();
63   }
64
65   void ReadImpl() override {}
66
67   void WriteImpl() override {}
68
69   void CancelReadImpl() override {
70     ReadCompleted(/*bytes_read=*/0, mojom::SerialReceiveError::NONE);
71   }
72
73   void CancelWriteImpl() override {
74     WriteCompleted(/*bytes_written=*/0, mojom::SerialSendError::NONE);
75   }
76
77   bool ConfigurePortImpl() override {
78     // Open() is overridden so this should never be called.
79     ADD_FAILURE() << "ConfigurePortImpl() should not be reached.";
80     return false;
81   }
82
83  private:
84   ~FakeSerialIoHandler() override = default;
85
86   mojom::SerialPortControlSignals input_signals_;
87   mojom::SerialHostControlSignals output_signals_;
88   bool fail_open_ = false;
89   bool fail_get_control_signals_ = false;
90   bool fail_set_control_signals_ = false;
91 };
92
93 }  // namespace
94
95 class SerialPortImplTest : public DeviceServiceTestBase {
96  public:
97   SerialPortImplTest() = default;
98   SerialPortImplTest(const SerialPortImplTest& other) = delete;
99   void operator=(const SerialPortImplTest& other) = delete;
100   ~SerialPortImplTest() override = default;
101
102   scoped_refptr<FakeSerialIoHandler> CreatePort(
103       mojo::Remote<mojom::SerialPort>* port,
104       mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher>* watcher) {
105     auto io_handler = base::MakeRefCounted<FakeSerialIoHandler>();
106     mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher_remote;
107     *watcher = mojo::MakeSelfOwnedReceiver(
108         std::make_unique<mojom::SerialPortConnectionWatcher>(),
109         watcher_remote.InitWithNewPipeAndPassReceiver());
110     base::RunLoop loop;
111     SerialPortImpl::OpenForTesting(
112         io_handler, mojom::SerialConnectionOptions::New(), mojo::NullRemote(),
113         std::move(watcher_remote),
114         base::BindLambdaForTesting(
115             [&](mojo::PendingRemote<mojom::SerialPort> pending_remote) {
116               EXPECT_TRUE(pending_remote.is_valid());
117               port->Bind(std::move(pending_remote));
118               loop.Quit();
119             }));
120     loop.Run();
121     return io_handler;
122   }
123
124   void CreateDataPipe(mojo::ScopedDataPipeProducerHandle* producer,
125                       mojo::ScopedDataPipeConsumerHandle* consumer) {
126     MojoCreateDataPipeOptions options;
127     options.struct_size = sizeof(MojoCreateDataPipeOptions);
128     options.flags = MOJO_CREATE_DATA_PIPE_FLAG_NONE;
129     options.element_num_bytes = 1;
130     options.capacity_num_bytes = 64;
131
132     MojoResult result = mojo::CreateDataPipe(&options, *producer, *consumer);
133     DCHECK_EQ(result, MOJO_RESULT_OK);
134   }
135
136   mojo::ScopedDataPipeConsumerHandle StartReading(
137       mojom::SerialPort* serial_port) {
138     mojo::ScopedDataPipeProducerHandle producer;
139     mojo::ScopedDataPipeConsumerHandle consumer;
140     CreateDataPipe(&producer, &consumer);
141     serial_port->StartReading(std::move(producer));
142     return consumer;
143   }
144
145   mojo::ScopedDataPipeProducerHandle StartWriting(
146       mojom::SerialPort* serial_port) {
147     mojo::ScopedDataPipeProducerHandle producer;
148     mojo::ScopedDataPipeConsumerHandle consumer;
149     CreateDataPipe(&producer, &consumer);
150     serial_port->StartWriting(std::move(consumer));
151     return producer;
152   }
153 };
154
155 TEST_F(SerialPortImplTest, WatcherClosedWhenPortClosed) {
156   mojo::Remote<mojom::SerialPort> serial_port;
157   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
158   CreatePort(&serial_port, &watcher);
159
160   // To start with both the serial port connection and the connection watcher
161   // connection should remain open.
162   serial_port.FlushForTesting();
163   EXPECT_TRUE(serial_port.is_connected());
164   watcher->FlushForTesting();
165   EXPECT_TRUE(watcher);
166
167   // When the serial port connection is closed the watcher connection should be
168   // closed.
169   serial_port.reset();
170   watcher->FlushForTesting();
171   EXPECT_FALSE(watcher);
172 }
173
174 TEST_F(SerialPortImplTest, PortClosedWhenWatcherClosed) {
175   mojo::Remote<mojom::SerialPort> serial_port;
176   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
177   CreatePort(&serial_port, &watcher);
178
179   // To start with both the serial port connection and the connection watcher
180   // connection should remain open.
181   serial_port.FlushForTesting();
182   EXPECT_TRUE(serial_port.is_connected());
183   watcher->FlushForTesting();
184   EXPECT_TRUE(watcher);
185
186   // When the watcher connection is closed, for safety, the serial port
187   // connection should also be closed.
188   watcher->Close();
189   serial_port.FlushForTesting();
190   EXPECT_FALSE(serial_port.is_connected());
191 }
192
193 TEST_F(SerialPortImplTest, FlushRead) {
194   mojo::Remote<mojom::SerialPort> serial_port;
195   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
196   CreatePort(&serial_port, &watcher);
197
198   mojo::ScopedDataPipeConsumerHandle consumer = StartReading(serial_port.get());
199
200   // Calling Flush(kReceive) should cause the data pipe to close.
201   base::RunLoop watcher_loop;
202   mojo::SimpleWatcher pipe_watcher(
203       FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
204   EXPECT_EQ(pipe_watcher.Watch(consumer.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
205                                MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
206                                base::BindLambdaForTesting(
207                                    [&](MojoResult result,
208                                        const mojo::HandleSignalsState& state) {
209                                      EXPECT_EQ(result, MOJO_RESULT_OK);
210                                      EXPECT_TRUE(state.peer_closed());
211                                      watcher_loop.Quit();
212                                    })),
213             MOJO_RESULT_OK);
214
215   base::RunLoop loop;
216   serial_port->Flush(mojom::SerialPortFlushMode::kReceive, loop.QuitClosure());
217   loop.Run();
218   watcher_loop.Run();
219 }
220
221 TEST_F(SerialPortImplTest, OpenFailure) {
222   auto io_handler = base::MakeRefCounted<FakeSerialIoHandler>();
223   io_handler->SimulateOpenFailure(true);
224
225   mojo::PendingRemote<mojom::SerialPortConnectionWatcher> watcher_remote;
226   mojo::MakeSelfOwnedReceiver(
227       std::make_unique<mojom::SerialPortConnectionWatcher>(),
228       watcher_remote.InitWithNewPipeAndPassReceiver());
229   base::RunLoop loop;
230   SerialPortImpl::OpenForTesting(
231       io_handler, mojom::SerialConnectionOptions::New(), mojo::NullRemote(),
232       std::move(watcher_remote),
233       base::BindLambdaForTesting(
234           [&](mojo::PendingRemote<mojom::SerialPort> pending_remote) {
235             EXPECT_FALSE(pending_remote.is_valid());
236             loop.Quit();
237           }));
238   loop.Run();
239 }
240
241 TEST_F(SerialPortImplTest, GetControlSignalsFailure) {
242   mojo::Remote<mojom::SerialPort> serial_port;
243   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
244   scoped_refptr<FakeSerialIoHandler> io_handler =
245       CreatePort(&serial_port, &watcher);
246   io_handler->SimulateGetControlSignalsFailure(true);
247
248   base::RunLoop loop;
249   serial_port->GetControlSignals(base::BindLambdaForTesting(
250       [&](mojom::SerialPortControlSignalsPtr signals) {
251         EXPECT_FALSE(signals);
252         loop.Quit();
253       }));
254   loop.Run();
255 }
256
257 TEST_F(SerialPortImplTest, SetControlSignalsFailure) {
258   mojo::Remote<mojom::SerialPort> serial_port;
259   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
260   scoped_refptr<FakeSerialIoHandler> io_handler =
261       CreatePort(&serial_port, &watcher);
262   io_handler->SimulateSetControlSignalsFailure(true);
263
264   base::RunLoop loop;
265   auto signals = mojom::SerialHostControlSignals::New();
266   signals->has_dtr = true;
267   signals->dtr = true;
268   serial_port->SetControlSignals(std::move(signals),
269                                  base::BindLambdaForTesting([&](bool success) {
270                                    EXPECT_FALSE(success);
271                                    loop.Quit();
272                                  }));
273   loop.Run();
274 }
275
276 TEST_F(SerialPortImplTest, FlushWrite) {
277   mojo::Remote<mojom::SerialPort> serial_port;
278   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
279   CreatePort(&serial_port, &watcher);
280
281   mojo::ScopedDataPipeProducerHandle producer = StartWriting(serial_port.get());
282
283   // Calling Flush(kTransmit) should cause the data pipe to close.
284   base::RunLoop watcher_loop;
285   mojo::SimpleWatcher pipe_watcher(
286       FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
287   EXPECT_EQ(pipe_watcher.Watch(producer.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
288                                MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
289                                base::BindLambdaForTesting(
290                                    [&](MojoResult result,
291                                        const mojo::HandleSignalsState& state) {
292                                      EXPECT_EQ(result, MOJO_RESULT_OK);
293                                      EXPECT_TRUE(state.peer_closed());
294                                      watcher_loop.Quit();
295                                    })),
296             MOJO_RESULT_OK);
297
298   base::RunLoop loop;
299   serial_port->Flush(mojom::SerialPortFlushMode::kTransmit, loop.QuitClosure());
300   loop.Run();
301   watcher_loop.Run();
302 }
303
304 TEST_F(SerialPortImplTest, Drain) {
305   mojo::Remote<mojom::SerialPort> serial_port;
306   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
307   CreatePort(&serial_port, &watcher);
308
309   mojo::ScopedDataPipeProducerHandle producer = StartWriting(serial_port.get());
310
311   // Drain() will wait for the data pipe to close before replying.
312   producer.reset();
313
314   base::RunLoop loop;
315   serial_port->Drain(loop.QuitClosure());
316   loop.Run();
317 }
318
319 TEST_F(SerialPortImplTest, Close) {
320   mojo::Remote<mojom::SerialPort> serial_port;
321   mojo::SelfOwnedReceiverRef<mojom::SerialPortConnectionWatcher> watcher;
322   CreatePort(&serial_port, &watcher);
323
324   base::RunLoop loop;
325   serial_port->Close(/*flush=*/true, loop.QuitClosure());
326   loop.Run();
327 }
328
329 }  // namespace device