blob: 0032caf77cae2caddb6fa3d9b361e83d8e4f59d1 [file] [log] [blame]
Alexei Frolovf93cb262021-07-14 16:05:15 -07001// Copyright 2021 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_transfer/transfer.h"
16
17#include "gtest/gtest.h"
18#include "pw_bytes/array.h"
19#include "pw_rpc/raw/test_method_context.h"
20#include "pw_transfer/transfer.pwpb.h"
21#include "pw_transfer_private/chunk.h"
22
23namespace pw::transfer {
24namespace {
25
26PW_MODIFY_DIAGNOSTICS_PUSH();
27PW_MODIFY_DIAGNOSTIC(ignored, "-Wmissing-field-initializers");
28
29using internal::Chunk;
30
31Vector<std::byte, 64> EncodeChunk(const Chunk& chunk) {
32 Vector<std::byte, 64> buffer(64);
33 auto result = internal::EncodeChunk(chunk, buffer);
34 EXPECT_EQ(result.status(), OkStatus());
35 buffer.resize(result.value().size());
36 return buffer;
37}
38
39Chunk DecodeChunk(ConstByteSpan buffer) {
40 Chunk chunk = {};
41 EXPECT_EQ(internal::DecodeChunk(buffer, chunk), OkStatus());
42 return chunk;
43}
44
45class SimpleReadTransfer final : public ReadOnlyHandler {
46 public:
47 SimpleReadTransfer(uint32_t transfer_id, ConstByteSpan data)
48 : ReadOnlyHandler(transfer_id),
49 prepare_read_called(false),
50 finalize_read_called(false),
51 finalize_read_status(Status::Unknown()),
52 reader_(data) {}
53
54 Status PrepareRead() final {
55 // reader_.Seek(0);
56 set_reader(reader_);
57 prepare_read_called = true;
58 return OkStatus();
59 }
60
61 void FinalizeRead(Status status) final {
62 finalize_read_called = true;
63 finalize_read_status = status;
64 }
65
66 bool prepare_read_called;
67 bool finalize_read_called;
68 Status finalize_read_status;
69
70 private:
71 stream::MemoryReader reader_;
72};
73
74TEST(Tranfser, Read_SingleChunk) {
75 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
76 SimpleReadTransfer handler(3, data);
77
Alexei Frolov563946f2021-08-05 18:58:48 -070078 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -070079 ctx.service().RegisterHandler(handler);
80
81 ctx.call();
82 EXPECT_FALSE(handler.prepare_read_called);
83 EXPECT_FALSE(handler.finalize_read_called);
84
85 ctx.SendClientStream(
86 EncodeChunk({.transfer_id = 3, .pending_bytes = 64, .offset = 0}));
87 EXPECT_TRUE(handler.prepare_read_called);
88 EXPECT_FALSE(handler.finalize_read_called);
89
90 ASSERT_EQ(ctx.total_responses(), 2u);
91 Chunk c0 = DecodeChunk(ctx.responses()[0]);
92 Chunk c1 = DecodeChunk(ctx.responses()[1]);
93
94 // First chunk should have all the read data.
95 EXPECT_EQ(c0.transfer_id, 3u);
96 EXPECT_EQ(c0.offset, 0u);
97 ASSERT_EQ(c0.data.size(), data.size());
98 EXPECT_EQ(std::memcmp(c0.data.data(), data.data(), c0.data.size()), 0);
99
100 // Second chunk should be empty and set remaining_bytes = 0.
101 EXPECT_EQ(c1.transfer_id, 3u);
102 EXPECT_EQ(c1.data.size(), 0u);
103 ASSERT_TRUE(c1.remaining_bytes.has_value());
104 EXPECT_EQ(c1.remaining_bytes.value(), 0u);
105
106 ctx.SendClientStream(EncodeChunk({.transfer_id = 3, .status = OkStatus()}));
107 EXPECT_TRUE(handler.finalize_read_called);
108 EXPECT_EQ(handler.finalize_read_status, OkStatus());
109}
110
111TEST(Tranfser, Read_MultiChunk) {
112 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
113 SimpleReadTransfer handler(3, data);
114
Alexei Frolov563946f2021-08-05 18:58:48 -0700115 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -0700116 ctx.service().RegisterHandler(handler);
117
118 ctx.call();
119 EXPECT_FALSE(handler.prepare_read_called);
120 EXPECT_FALSE(handler.finalize_read_called);
121
122 ctx.SendClientStream(
123 EncodeChunk({.transfer_id = 3, .pending_bytes = 16, .offset = 0}));
124 EXPECT_TRUE(handler.prepare_read_called);
125 EXPECT_FALSE(handler.finalize_read_called);
126
127 ASSERT_EQ(ctx.total_responses(), 1u);
128 Chunk c0 = DecodeChunk(ctx.responses()[0]);
129
130 EXPECT_EQ(c0.transfer_id, 3u);
131 EXPECT_EQ(c0.offset, 0u);
132 ASSERT_EQ(c0.data.size(), 16u);
133 EXPECT_EQ(std::memcmp(c0.data.data(), data.data(), c0.data.size()), 0);
134
135 ctx.SendClientStream(
136 EncodeChunk({.transfer_id = 3, .pending_bytes = 16, .offset = 16}));
137 ASSERT_EQ(ctx.total_responses(), 2u);
138 Chunk c1 = DecodeChunk(ctx.responses()[1]);
139
140 EXPECT_EQ(c1.transfer_id, 3u);
141 EXPECT_EQ(c1.offset, 16u);
142 ASSERT_EQ(c1.data.size(), 16u);
143 EXPECT_EQ(std::memcmp(c1.data.data(), data.data() + 16, c1.data.size()), 0);
144
145 ctx.SendClientStream(
146 EncodeChunk({.transfer_id = 3, .pending_bytes = 16, .offset = 32}));
147 ASSERT_EQ(ctx.total_responses(), 3u);
148 Chunk c2 = DecodeChunk(ctx.responses()[2]);
149
150 EXPECT_EQ(c2.transfer_id, 3u);
151 EXPECT_EQ(c2.data.size(), 0u);
152 ASSERT_TRUE(c2.remaining_bytes.has_value());
153 EXPECT_EQ(c2.remaining_bytes.value(), 0u);
154
155 ctx.SendClientStream(EncodeChunk({.transfer_id = 3, .status = OkStatus()}));
156 EXPECT_TRUE(handler.finalize_read_called);
157 EXPECT_EQ(handler.finalize_read_status, OkStatus());
158}
159
Alexei Frolov563946f2021-08-05 18:58:48 -0700160TEST(Tranfser, Read_MaxChunkSize_Client) {
Alexei Frolovf93cb262021-07-14 16:05:15 -0700161 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
162 SimpleReadTransfer handler(3, data);
163
Alexei Frolov563946f2021-08-05 18:58:48 -0700164 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read, 5, 64) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -0700165 ctx.service().RegisterHandler(handler);
166
167 ctx.call();
168 EXPECT_FALSE(handler.prepare_read_called);
169 EXPECT_FALSE(handler.finalize_read_called);
170
171 ctx.SendClientStream(EncodeChunk({.transfer_id = 3,
172 .pending_bytes = 64,
173 .max_chunk_size_bytes = 8,
174 .offset = 0}));
175 EXPECT_TRUE(handler.prepare_read_called);
176 EXPECT_FALSE(handler.finalize_read_called);
177
178 ASSERT_EQ(ctx.total_responses(), 5u);
179 Chunk c0 = DecodeChunk(ctx.responses()[0]);
180 Chunk c1 = DecodeChunk(ctx.responses()[1]);
181 Chunk c2 = DecodeChunk(ctx.responses()[2]);
182 Chunk c3 = DecodeChunk(ctx.responses()[3]);
183 Chunk c4 = DecodeChunk(ctx.responses()[4]);
184
185 EXPECT_EQ(c0.transfer_id, 3u);
186 EXPECT_EQ(c0.offset, 0u);
187 ASSERT_EQ(c0.data.size(), 8u);
188 EXPECT_EQ(std::memcmp(c0.data.data(), data.data(), c0.data.size()), 0);
189
190 EXPECT_EQ(c1.transfer_id, 3u);
191 EXPECT_EQ(c1.offset, 8u);
192 ASSERT_EQ(c1.data.size(), 8u);
193 EXPECT_EQ(std::memcmp(c1.data.data(), data.data() + 8, c1.data.size()), 0);
194
195 EXPECT_EQ(c2.transfer_id, 3u);
196 EXPECT_EQ(c2.offset, 16u);
197 ASSERT_EQ(c2.data.size(), 8u);
198 EXPECT_EQ(std::memcmp(c2.data.data(), data.data() + 16, c2.data.size()), 0);
199
200 EXPECT_EQ(c3.transfer_id, 3u);
201 EXPECT_EQ(c3.offset, 24u);
202 ASSERT_EQ(c3.data.size(), 8u);
203 EXPECT_EQ(std::memcmp(c3.data.data(), data.data() + 24, c3.data.size()), 0);
204
205 EXPECT_EQ(c4.transfer_id, 3u);
206 EXPECT_EQ(c4.data.size(), 0u);
207 ASSERT_TRUE(c4.remaining_bytes.has_value());
208 EXPECT_EQ(c4.remaining_bytes.value(), 0u);
209
210 ctx.SendClientStream(EncodeChunk({.transfer_id = 3, .status = OkStatus()}));
211 EXPECT_TRUE(handler.finalize_read_called);
212 EXPECT_EQ(handler.finalize_read_status, OkStatus());
213}
214
Alexei Frolov563946f2021-08-05 18:58:48 -0700215TEST(Tranfser, Read_MaxChunkSize_Server) {
216 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
217 SimpleReadTransfer handler(3, data);
218
219 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read, 5, 64)
220 ctx(/*max_chunk_size_bytes=*/8, 64);
221 ctx.service().RegisterHandler(handler);
222
223 ctx.call();
224 EXPECT_FALSE(handler.prepare_read_called);
225 EXPECT_FALSE(handler.finalize_read_called);
226
227 // Client asks for max 16-byte chunks, but service places a limit of 8 bytes.
228 ctx.SendClientStream(EncodeChunk({.transfer_id = 3,
229 .pending_bytes = 64,
230 .max_chunk_size_bytes = 16,
231 .offset = 0}));
232 EXPECT_TRUE(handler.prepare_read_called);
233 EXPECT_FALSE(handler.finalize_read_called);
234
235 ASSERT_EQ(ctx.total_responses(), 5u);
236 Chunk c0 = DecodeChunk(ctx.responses()[0]);
237 Chunk c1 = DecodeChunk(ctx.responses()[1]);
238 Chunk c2 = DecodeChunk(ctx.responses()[2]);
239 Chunk c3 = DecodeChunk(ctx.responses()[3]);
240 Chunk c4 = DecodeChunk(ctx.responses()[4]);
241
242 EXPECT_EQ(c0.transfer_id, 3u);
243 EXPECT_EQ(c0.offset, 0u);
244 ASSERT_EQ(c0.data.size(), 8u);
245 EXPECT_EQ(std::memcmp(c0.data.data(), data.data(), c0.data.size()), 0);
246
247 EXPECT_EQ(c1.transfer_id, 3u);
248 EXPECT_EQ(c1.offset, 8u);
249 ASSERT_EQ(c1.data.size(), 8u);
250 EXPECT_EQ(std::memcmp(c1.data.data(), data.data() + 8, c1.data.size()), 0);
251
252 EXPECT_EQ(c2.transfer_id, 3u);
253 EXPECT_EQ(c2.offset, 16u);
254 ASSERT_EQ(c2.data.size(), 8u);
255 EXPECT_EQ(std::memcmp(c2.data.data(), data.data() + 16, c2.data.size()), 0);
256
257 EXPECT_EQ(c3.transfer_id, 3u);
258 EXPECT_EQ(c3.offset, 24u);
259 ASSERT_EQ(c3.data.size(), 8u);
260 EXPECT_EQ(std::memcmp(c3.data.data(), data.data() + 24, c3.data.size()), 0);
261
262 EXPECT_EQ(c4.transfer_id, 3u);
263 EXPECT_EQ(c4.data.size(), 0u);
264 ASSERT_TRUE(c4.remaining_bytes.has_value());
265 EXPECT_EQ(c4.remaining_bytes.value(), 0u);
266
267 ctx.SendClientStream(EncodeChunk({.transfer_id = 3, .status = OkStatus()}));
268 EXPECT_TRUE(handler.finalize_read_called);
269 EXPECT_EQ(handler.finalize_read_status, OkStatus());
270}
271
Alexei Frolovf93cb262021-07-14 16:05:15 -0700272TEST(Tranfser, Read_ClientError) {
273 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
274 SimpleReadTransfer handler(3, data);
275
Alexei Frolov563946f2021-08-05 18:58:48 -0700276 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -0700277 ctx.service().RegisterHandler(handler);
278
279 ctx.call();
280 EXPECT_FALSE(handler.prepare_read_called);
281 EXPECT_FALSE(handler.finalize_read_called);
282
283 ctx.SendClientStream(
284 EncodeChunk({.transfer_id = 3, .pending_bytes = 16, .offset = 0}));
285 EXPECT_TRUE(handler.prepare_read_called);
286 EXPECT_FALSE(handler.finalize_read_called);
287 ASSERT_EQ(ctx.total_responses(), 1u);
288
289 // Send client error.
290 ctx.SendClientStream(
291 EncodeChunk({.transfer_id = 3, .status = Status::OutOfRange()}));
292 ASSERT_EQ(ctx.total_responses(), 1u);
293 EXPECT_TRUE(handler.finalize_read_called);
294 EXPECT_EQ(handler.finalize_read_status, Status::OutOfRange());
295}
296
297TEST(Tranfser, Read_MalformedParametersChunk) {
298 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
299 SimpleReadTransfer handler(3, data);
300
Alexei Frolov563946f2021-08-05 18:58:48 -0700301 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -0700302 ctx.service().RegisterHandler(handler);
303
304 ctx.call();
305 EXPECT_FALSE(handler.prepare_read_called);
306 EXPECT_FALSE(handler.finalize_read_called);
307
308 // pending_bytes is required in a parameters chunk.
309 ctx.SendClientStream(EncodeChunk({.transfer_id = 3}));
310 EXPECT_TRUE(handler.prepare_read_called);
311 EXPECT_TRUE(handler.finalize_read_called);
312 EXPECT_EQ(handler.finalize_read_status, Status::InvalidArgument());
313
314 ASSERT_EQ(ctx.total_responses(), 1u);
315 Chunk chunk = DecodeChunk(ctx.responses()[0]);
316 EXPECT_EQ(chunk.transfer_id, 3u);
317 ASSERT_TRUE(chunk.status.has_value());
318 EXPECT_EQ(chunk.status.value(), Status::InvalidArgument());
319}
320
321TEST(Tranfser, Read_UnregisteredHandler) {
Alexei Frolov563946f2021-08-05 18:58:48 -0700322 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolovf93cb262021-07-14 16:05:15 -0700323
324 ctx.call();
325 ctx.SendClientStream(
326 EncodeChunk({.transfer_id = 11, .pending_bytes = 32, .offset = 0}));
327
328 ASSERT_EQ(ctx.total_responses(), 1u);
329 Chunk chunk = DecodeChunk(ctx.responses()[0]);
330 EXPECT_EQ(chunk.transfer_id, 11u);
331 ASSERT_TRUE(chunk.status.has_value());
332 EXPECT_EQ(chunk.status.value(), Status::NotFound());
333}
334
Alexei Frolov563946f2021-08-05 18:58:48 -0700335class SimpleWriteTransfer final : public WriteOnlyHandler {
336 public:
337 SimpleWriteTransfer(uint32_t transfer_id, ByteSpan data)
338 : WriteOnlyHandler(transfer_id),
339 prepare_write_called(false),
340 finalize_write_called(false),
341 finalize_write_status(Status::Unknown()),
342 writer_(data) {}
343
344 Status PrepareWrite() final {
345 // writer_.Seek(0);
346 set_writer(writer_);
347 prepare_write_called = true;
348 return OkStatus();
349 }
350
351 Status FinalizeWrite(Status status) final {
352 finalize_write_called = true;
353 finalize_write_status = status;
354 return OkStatus();
355 }
356
357 bool prepare_write_called;
358 bool finalize_write_called;
359 Status finalize_write_status;
360
361 private:
362 stream::MemoryWriter writer_;
363};
364
365TEST(Transfer, Write_SingleChunk) {
366 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
367 std::array<std::byte, sizeof(data)> buffer = {};
368 SimpleWriteTransfer handler(7, buffer);
369
370 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
371 ctx.service().RegisterHandler(handler);
372
373 EXPECT_FALSE(handler.prepare_write_called);
374 EXPECT_FALSE(handler.finalize_write_called);
375
376 ctx.call();
377 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
378
379 EXPECT_TRUE(handler.prepare_write_called);
380 EXPECT_FALSE(handler.finalize_write_called);
381
382 ASSERT_EQ(ctx.total_responses(), 1u);
383 Chunk chunk = DecodeChunk(ctx.responses()[0]);
384 EXPECT_EQ(chunk.transfer_id, 7u);
385 ASSERT_TRUE(chunk.pending_bytes.has_value());
386 EXPECT_EQ(chunk.pending_bytes.value(), 32u);
387 ASSERT_TRUE(chunk.max_chunk_size_bytes.has_value());
388 EXPECT_EQ(chunk.max_chunk_size_bytes.value(), 42u);
389
390 ctx.SendClientStream<64>(EncodeChunk({.transfer_id = 7,
391 .offset = 0,
392 .data = std::span(data),
393 .remaining_bytes = 0}));
394 ASSERT_EQ(ctx.total_responses(), 2u);
395 chunk = DecodeChunk(ctx.responses()[1]);
396 EXPECT_EQ(chunk.transfer_id, 7u);
397 ASSERT_TRUE(chunk.status.has_value());
398 EXPECT_EQ(chunk.status.value(), OkStatus());
399
400 EXPECT_TRUE(handler.finalize_write_called);
401 EXPECT_EQ(handler.finalize_write_status, OkStatus());
402 EXPECT_EQ(std::memcmp(buffer.data(), data.data(), data.size()), 0);
403}
404
405TEST(Transfer, Write_MultiChunk) {
406 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
407 std::array<std::byte, sizeof(data)> buffer = {};
408 SimpleWriteTransfer handler(7, buffer);
409
410 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
411 ctx.service().RegisterHandler(handler);
412
413 EXPECT_FALSE(handler.prepare_write_called);
414 EXPECT_FALSE(handler.finalize_write_called);
415
416 ctx.call();
417 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
418
419 EXPECT_TRUE(handler.prepare_write_called);
420 EXPECT_FALSE(handler.finalize_write_called);
421
422 ASSERT_EQ(ctx.total_responses(), 1u);
423 Chunk chunk = DecodeChunk(ctx.responses()[0]);
424 EXPECT_EQ(chunk.transfer_id, 7u);
425 ASSERT_TRUE(chunk.pending_bytes.has_value());
426 EXPECT_EQ(chunk.pending_bytes.value(), 32u);
427
428 ctx.SendClientStream<64>(EncodeChunk(
429 {.transfer_id = 7, .offset = 0, .data = std::span(data).first(16)}));
430 ASSERT_EQ(ctx.total_responses(), 1u);
431
432 ctx.SendClientStream<64>(EncodeChunk({.transfer_id = 7,
433 .offset = 16,
434 .data = std::span(data).subspan(16),
435 .remaining_bytes = 0}));
436 ASSERT_EQ(ctx.total_responses(), 2u);
437 chunk = DecodeChunk(ctx.responses()[1]);
438 EXPECT_EQ(chunk.transfer_id, 7u);
439 ASSERT_TRUE(chunk.status.has_value());
440 EXPECT_EQ(chunk.status.value(), OkStatus());
441
442 EXPECT_TRUE(handler.finalize_write_called);
443 EXPECT_EQ(handler.finalize_write_status, OkStatus());
444 EXPECT_EQ(std::memcmp(buffer.data(), data.data(), data.size()), 0);
445}
446
447TEST(Transfer, Write_MultipleParameters) {
448 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
449 std::array<std::byte, sizeof(data)> buffer = {};
450 SimpleWriteTransfer handler(7, buffer);
451
452 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 16);
453 ctx.service().RegisterHandler(handler);
454
455 EXPECT_FALSE(handler.prepare_write_called);
456 EXPECT_FALSE(handler.finalize_write_called);
457
458 ctx.call();
459 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
460
461 EXPECT_TRUE(handler.prepare_write_called);
462 EXPECT_FALSE(handler.finalize_write_called);
463
464 ASSERT_EQ(ctx.total_responses(), 1u);
465 Chunk chunk = DecodeChunk(ctx.responses()[0]);
466 EXPECT_EQ(chunk.transfer_id, 7u);
467 ASSERT_TRUE(chunk.pending_bytes.has_value());
468 EXPECT_EQ(chunk.pending_bytes.value(), 16u);
469
470 ctx.SendClientStream<64>(EncodeChunk(
471 {.transfer_id = 7, .offset = 0, .data = std::span(data).first(8)}));
472 ASSERT_EQ(ctx.total_responses(), 1u);
473
474 ctx.SendClientStream<64>(EncodeChunk(
475 {.transfer_id = 7, .offset = 8, .data = std::span(data).subspan(8, 8)}));
476 ASSERT_EQ(ctx.total_responses(), 2u);
477 chunk = DecodeChunk(ctx.responses()[1]);
478 EXPECT_EQ(chunk.transfer_id, 7u);
479 ASSERT_TRUE(chunk.pending_bytes.has_value());
480 EXPECT_EQ(chunk.pending_bytes.value(), 16u);
481
482 ctx.SendClientStream<64>(
483 EncodeChunk({.transfer_id = 7,
484 .offset = 16,
485 .data = std::span(data).subspan(16, 8)}));
486 ASSERT_EQ(ctx.total_responses(), 2u);
487
488 ctx.SendClientStream<64>(EncodeChunk({.transfer_id = 7,
489 .offset = 24,
490 .data = std::span(data).subspan(24),
491 .remaining_bytes = 0}));
492 ASSERT_EQ(ctx.total_responses(), 3u);
493 chunk = DecodeChunk(ctx.responses()[2]);
494 EXPECT_EQ(chunk.transfer_id, 7u);
495 ASSERT_TRUE(chunk.status.has_value());
496 EXPECT_EQ(chunk.status.value(), OkStatus());
497
498 EXPECT_TRUE(handler.finalize_write_called);
499 EXPECT_EQ(handler.finalize_write_status, OkStatus());
500 EXPECT_EQ(std::memcmp(buffer.data(), data.data(), data.size()), 0);
501}
502
503TEST(Transfer, Write_SetsDefaultPendingBytes) {
504 // Constructor's default max bytes is smaller than buffer.
505 std::array<std::byte, 32> buffer = {};
506 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 16);
507
508 SimpleWriteTransfer handler(7, buffer);
509 ctx.service().RegisterHandler(handler);
510
511 ctx.call();
512 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
513 Chunk chunk = DecodeChunk(ctx.responses()[0]);
514 EXPECT_EQ(chunk.transfer_id, 7u);
515 EXPECT_EQ(chunk.pending_bytes.value(), 16u);
516}
517
518TEST(Transfer, Write_SetsWriterPendingBytes) {
519 // Buffer is smaller than constructor's default max bytes.
520 std::array<std::byte, 8> buffer = {};
521 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
522
523 SimpleWriteTransfer handler(7, buffer);
524 ctx.service().RegisterHandler(handler);
525
526 ctx.call();
527 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
528 Chunk chunk = DecodeChunk(ctx.responses()[0]);
529 EXPECT_EQ(chunk.transfer_id, 7u);
530 EXPECT_EQ(chunk.pending_bytes.value(), 8u);
531}
532
533TEST(Transfer, Write_UnexpectedOffset) {
534 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
535 std::array<std::byte, sizeof(data)> buffer = {};
536 SimpleWriteTransfer handler(7, buffer);
537
538 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
539 ctx.service().RegisterHandler(handler);
540
541 EXPECT_FALSE(handler.prepare_write_called);
542 EXPECT_FALSE(handler.finalize_write_called);
543
544 ctx.call();
545 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
546
547 EXPECT_TRUE(handler.prepare_write_called);
548 EXPECT_FALSE(handler.finalize_write_called);
549
550 ASSERT_EQ(ctx.total_responses(), 1u);
551 Chunk chunk = DecodeChunk(ctx.responses()[0]);
552 EXPECT_EQ(chunk.transfer_id, 7u);
553 EXPECT_EQ(chunk.offset, 0u);
554 ASSERT_TRUE(chunk.pending_bytes.has_value());
555 EXPECT_EQ(chunk.pending_bytes.value(), 32u);
556
557 ctx.SendClientStream<64>(EncodeChunk(
558 {.transfer_id = 7, .offset = 0, .data = std::span(data).first(16)}));
559 ASSERT_EQ(ctx.total_responses(), 1u);
560
561 ctx.SendClientStream<64>(EncodeChunk({.transfer_id = 7,
562 .offset = 8, // incorrect
563 .data = std::span(data).subspan(16),
564 .remaining_bytes = 0}));
565 ASSERT_EQ(ctx.total_responses(), 2u);
566 chunk = DecodeChunk(ctx.responses()[1]);
567 EXPECT_EQ(chunk.transfer_id, 7u);
568 EXPECT_EQ(chunk.offset, 16u);
569 ASSERT_TRUE(chunk.pending_bytes.has_value());
570 EXPECT_EQ(chunk.pending_bytes.value(), 16u);
571
572 ctx.SendClientStream<64>(EncodeChunk({.transfer_id = 7,
573 .offset = 16, // incorrect
574 .data = std::span(data).subspan(16),
575 .remaining_bytes = 0}));
576 ASSERT_EQ(ctx.total_responses(), 3u);
577 chunk = DecodeChunk(ctx.responses()[2]);
578 EXPECT_EQ(chunk.transfer_id, 7u);
579 ASSERT_TRUE(chunk.status.has_value());
580 EXPECT_EQ(chunk.status.value(), OkStatus());
581
582 EXPECT_TRUE(handler.finalize_write_called);
583 EXPECT_EQ(handler.finalize_write_status, OkStatus());
584 EXPECT_EQ(std::memcmp(buffer.data(), data.data(), data.size()), 0);
585}
586
587TEST(Transfer, Write_UnregisteredHandler) {
588 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
589
590 ctx.call();
591 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
592
593 ASSERT_EQ(ctx.total_responses(), 1u);
594 Chunk chunk = DecodeChunk(ctx.responses()[0]);
595 EXPECT_EQ(chunk.transfer_id, 7u);
596 ASSERT_TRUE(chunk.status.has_value());
597 EXPECT_EQ(chunk.status.value(), Status::NotFound());
598}
599
600TEST(Transfer, Write_ClientError) {
601 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
602 std::array<std::byte, sizeof(data)> buffer = {};
603 SimpleWriteTransfer handler(7, buffer);
604
605 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx(64, 64);
606 ctx.service().RegisterHandler(handler);
607
608 EXPECT_FALSE(handler.prepare_write_called);
609 EXPECT_FALSE(handler.finalize_write_called);
610
611 ctx.call();
612 ctx.SendClientStream(EncodeChunk({.transfer_id = 7}));
613
614 EXPECT_TRUE(handler.prepare_write_called);
615 EXPECT_FALSE(handler.finalize_write_called);
616
617 ASSERT_EQ(ctx.total_responses(), 1u);
618 Chunk chunk = DecodeChunk(ctx.responses()[0]);
619 EXPECT_EQ(chunk.transfer_id, 7u);
620 ASSERT_TRUE(chunk.pending_bytes.has_value());
621 EXPECT_EQ(chunk.pending_bytes.value(), 32u);
622
623 ctx.SendClientStream<64>(
624 EncodeChunk({.transfer_id = 7, .status = Status::DataLoss()}));
625 EXPECT_EQ(ctx.total_responses(), 1u);
626
627 EXPECT_TRUE(handler.finalize_write_called);
628 EXPECT_EQ(handler.finalize_write_status, Status::DataLoss());
629}
630
Alexei Frolov32a875d2021-08-02 15:48:44 -0700631class SometimesUnavailableReadHandler final : public ReadOnlyHandler {
632 public:
633 SometimesUnavailableReadHandler(uint32_t transfer_id, ConstByteSpan data)
634 : ReadOnlyHandler(transfer_id), reader_(data), call_count_(0) {}
635
636 Status PrepareRead() final {
637 if ((call_count_++ % 2) == 0) {
638 return Status::Unavailable();
639 }
640
641 set_reader(reader_);
642 return OkStatus();
643 }
644
645 private:
646 stream::MemoryReader reader_;
647 int call_count_;
648};
649
650TEST(Tranfser, PrepareError) {
651 constexpr auto data = bytes::Initialized<32>([](size_t i) { return i; });
652 SometimesUnavailableReadHandler handler(3, data);
653
Alexei Frolov563946f2021-08-05 18:58:48 -0700654 PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read) ctx(64, 64);
Alexei Frolov32a875d2021-08-02 15:48:44 -0700655 ctx.service().RegisterHandler(handler);
656
657 ctx.call();
658 ctx.SendClientStream(
659 EncodeChunk({.transfer_id = 3, .pending_bytes = 128, .offset = 0}));
660
661 ASSERT_EQ(ctx.total_responses(), 1u);
662 Chunk chunk = DecodeChunk(ctx.responses()[0]);
663 EXPECT_EQ(chunk.transfer_id, 3u);
664 ASSERT_TRUE(chunk.status.has_value());
665 EXPECT_EQ(chunk.status.value(), Status::Unavailable());
666
667 // Try starting the transfer again. It should work this time.
668 ctx.SendClientStream(
669 EncodeChunk({.transfer_id = 3, .pending_bytes = 128, .offset = 0}));
670 ASSERT_EQ(ctx.total_responses(), 3u);
671 chunk = DecodeChunk(ctx.responses()[1]);
672 EXPECT_EQ(chunk.transfer_id, 3u);
673 ASSERT_EQ(chunk.data.size(), data.size());
674 EXPECT_EQ(std::memcmp(chunk.data.data(), data.data(), chunk.data.size()), 0);
675}
676
Alexei Frolovf93cb262021-07-14 16:05:15 -0700677PW_MODIFY_DIAGNOSTICS_POP();
678
679} // namespace
680} // namespace pw::transfer