1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_channel/loopback_channel.h"
16
17 #include "pw_allocator/testing.h"
18 #include "pw_assert/check.h"
19 #include "pw_async2/dispatcher.h"
20 #include "pw_bytes/suffix.h"
21 #include "pw_channel/channel.h"
22 #include "pw_multibuf/simple_allocator_for_test.h"
23 #include "pw_status/status.h"
24
25 namespace {
26
27 using ::pw::async2::Context;
28 using ::pw::async2::Dispatcher;
29 using ::pw::async2::Pending;
30 using ::pw::async2::Poll;
31 using ::pw::async2::Ready;
32 using ::pw::async2::Task;
33 using ::pw::operator""_b;
34 using ::pw::channel::DatagramReader;
35 using ::pw::channel::LoopbackByteChannel;
36 using ::pw::channel::LoopbackDatagramChannel;
37 using ::pw::channel::ReliableByteReader;
38 using ::pw::multibuf::test::SimpleAllocatorForTest;
39
40 template <typename ChannelKind>
41 class ReaderTask : public Task {
42 public:
ReaderTask(ChannelKind & channel)43 ReaderTask(ChannelKind& channel) : channel_(channel) {}
44
45 int poll_count = 0;
46 int read_count = 0;
47 int bytes_read_count = 0;
48
49 private:
DoPend(Context & cx)50 Poll<> DoPend(Context& cx) final {
51 ++poll_count;
52 while (true) {
53 auto result = channel_.PendRead(cx);
54 if (result.IsPending()) {
55 return Pending();
56 }
57 if (!result->ok()) {
58 // We hit an error-- call it quits.
59 return Ready();
60 }
61 ++read_count;
62 bytes_read_count += (**result).size();
63 }
64 }
65
66 ChannelKind& channel_;
67 };
68
TEST(LoopbackDatagramChannel,LoopsEmptyDatagrams)69 TEST(LoopbackDatagramChannel, LoopsEmptyDatagrams) {
70 SimpleAllocatorForTest alloc;
71 LoopbackDatagramChannel channel(alloc);
72 ReaderTask<DatagramReader> read_task(channel.channel());
73
74 Dispatcher dispatcher;
75 dispatcher.Post(read_task);
76 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
77 EXPECT_EQ(read_task.poll_count, 1);
78 EXPECT_EQ(read_task.read_count, 0);
79 EXPECT_EQ(read_task.bytes_read_count, 0);
80
81 PW_TEST_EXPECT_OK(channel.StageWrite(alloc.BufWith({})));
82
83 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
84 EXPECT_EQ(read_task.poll_count, 2);
85 EXPECT_EQ(read_task.read_count, 1);
86 EXPECT_EQ(read_task.bytes_read_count, 0);
87 }
88
TEST(LoopbackDatagramChannel,LoopsDatagrams)89 TEST(LoopbackDatagramChannel, LoopsDatagrams) {
90 SimpleAllocatorForTest alloc;
91 LoopbackDatagramChannel channel(alloc);
92 ReaderTask<DatagramReader> read_task(channel.channel());
93
94 Dispatcher dispatcher;
95 dispatcher.Post(read_task);
96 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
97 EXPECT_EQ(read_task.poll_count, 1);
98 EXPECT_EQ(read_task.read_count, 0);
99 EXPECT_EQ(read_task.bytes_read_count, 0);
100
101 PW_TEST_EXPECT_OK(channel.StageWrite(alloc.BufWith({1_b, 2_b, 3_b})));
102
103 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
104 EXPECT_EQ(read_task.poll_count, 2);
105 EXPECT_EQ(read_task.read_count, 1);
106 EXPECT_EQ(read_task.bytes_read_count, 3);
107 }
108
TEST(LoopbackByteChannel,IgnoresEmptyWrites)109 TEST(LoopbackByteChannel, IgnoresEmptyWrites) {
110 SimpleAllocatorForTest alloc;
111 LoopbackByteChannel channel(alloc);
112 ReaderTask<ReliableByteReader> read_task(channel.channel());
113
114 Dispatcher dispatcher;
115 dispatcher.Post(read_task);
116 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
117 EXPECT_EQ(read_task.poll_count, 1);
118 EXPECT_EQ(read_task.read_count, 0);
119 EXPECT_EQ(read_task.bytes_read_count, 0);
120
121 PW_TEST_EXPECT_OK(channel.StageWrite(alloc.BufWith({})));
122
123 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
124 EXPECT_EQ(read_task.poll_count, 1);
125 EXPECT_EQ(read_task.read_count, 0);
126 EXPECT_EQ(read_task.bytes_read_count, 0);
127 }
128
TEST(LoopbackByteChannel,LoopsData)129 TEST(LoopbackByteChannel, LoopsData) {
130 SimpleAllocatorForTest alloc;
131 LoopbackByteChannel channel(alloc);
132 ReaderTask<ReliableByteReader> read_task(channel.channel());
133
134 Dispatcher dispatcher;
135 dispatcher.Post(read_task);
136 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
137 EXPECT_EQ(read_task.poll_count, 1);
138 EXPECT_EQ(read_task.read_count, 0);
139 EXPECT_EQ(read_task.bytes_read_count, 0);
140
141 PW_TEST_EXPECT_OK(channel.StageWrite(alloc.BufWith({1_b, 2_b, 3_b})));
142
143 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
144 EXPECT_EQ(read_task.poll_count, 2);
145 EXPECT_EQ(read_task.read_count, 1);
146 EXPECT_EQ(read_task.bytes_read_count, 3);
147 }
148
149 } // namespace
150