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);
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 EXPECT_EQ(channel.Write(alloc.BufWith({})).status(), pw::OkStatus());
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);
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 EXPECT_EQ(channel.Write(alloc.BufWith({1_b, 2_b, 3_b})).status(),
102 pw::OkStatus());
103
104 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
105 EXPECT_EQ(read_task.poll_count, 2);
106 EXPECT_EQ(read_task.read_count, 1);
107 EXPECT_EQ(read_task.bytes_read_count, 3);
108 }
109
TEST(LoopbackByteChannel,IgnoresEmptyWrites)110 TEST(LoopbackByteChannel, IgnoresEmptyWrites) {
111 SimpleAllocatorForTest alloc;
112 LoopbackByteChannel channel(alloc);
113 ReaderTask<ReliableByteReader> read_task(channel);
114
115 Dispatcher dispatcher;
116 dispatcher.Post(read_task);
117 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
118 EXPECT_EQ(read_task.poll_count, 1);
119 EXPECT_EQ(read_task.read_count, 0);
120 EXPECT_EQ(read_task.bytes_read_count, 0);
121
122 EXPECT_EQ(channel.Write(alloc.BufWith({})).status(), pw::OkStatus());
123
124 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
125 EXPECT_EQ(read_task.poll_count, 1);
126 EXPECT_EQ(read_task.read_count, 0);
127 EXPECT_EQ(read_task.bytes_read_count, 0);
128 }
129
TEST(LoopbackByteChannel,LoopsData)130 TEST(LoopbackByteChannel, LoopsData) {
131 SimpleAllocatorForTest alloc;
132 LoopbackByteChannel channel(alloc);
133 ReaderTask<ReliableByteReader> read_task(channel);
134
135 Dispatcher dispatcher;
136 dispatcher.Post(read_task);
137 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
138 EXPECT_EQ(read_task.poll_count, 1);
139 EXPECT_EQ(read_task.read_count, 0);
140 EXPECT_EQ(read_task.bytes_read_count, 0);
141
142 EXPECT_EQ(channel.Write(alloc.BufWith({1_b, 2_b, 3_b})).status(),
143 pw::OkStatus());
144
145 EXPECT_EQ(dispatcher.RunUntilStalled(), Pending());
146 EXPECT_EQ(read_task.poll_count, 2);
147 EXPECT_EQ(read_task.read_count, 1);
148 EXPECT_EQ(read_task.bytes_read_count, 3);
149 }
150
151 } // namespace
152