xref: /aosp_15_r20/external/pigweed/pw_transfer/transfer_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <limits>
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_containers/algorithm.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/raw/test_method_context.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_rpc/test_helpers.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_thread/thread.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_thread_stl/options.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/internal/config.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer/transfer.pwpb.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_transfer_private/chunk_testing.h"
29*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
30*61c4878aSAndroid Build Coastguard Worker 
31*61c4878aSAndroid Build Coastguard Worker namespace pw::transfer::test {
32*61c4878aSAndroid Build Coastguard Worker namespace {
33*61c4878aSAndroid Build Coastguard Worker 
34*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono_literals;
35*61c4878aSAndroid Build Coastguard Worker 
36*61c4878aSAndroid Build Coastguard Worker // TODO(frolv): Have a generic way to obtain a thread for testing on any system.
TransferThreadOptions()37*61c4878aSAndroid Build Coastguard Worker thread::Options& TransferThreadOptions() {
38*61c4878aSAndroid Build Coastguard Worker   static thread::stl::Options options;
39*61c4878aSAndroid Build Coastguard Worker   return options;
40*61c4878aSAndroid Build Coastguard Worker }
41*61c4878aSAndroid Build Coastguard Worker 
42*61c4878aSAndroid Build Coastguard Worker using internal::Chunk;
43*61c4878aSAndroid Build Coastguard Worker 
44*61c4878aSAndroid Build Coastguard Worker class TestMemoryReader : public stream::SeekableReader {
45*61c4878aSAndroid Build Coastguard Worker  public:
TestMemoryReader(span<const std::byte> data)46*61c4878aSAndroid Build Coastguard Worker   constexpr TestMemoryReader(span<const std::byte> data)
47*61c4878aSAndroid Build Coastguard Worker       : memory_reader_(data) {}
48*61c4878aSAndroid Build Coastguard Worker 
DoSeek(ptrdiff_t offset,Whence origin)49*61c4878aSAndroid Build Coastguard Worker   Status DoSeek(ptrdiff_t offset, Whence origin) override {
50*61c4878aSAndroid Build Coastguard Worker     if (seek_status.ok()) {
51*61c4878aSAndroid Build Coastguard Worker       return memory_reader_.Seek(offset, origin);
52*61c4878aSAndroid Build Coastguard Worker     }
53*61c4878aSAndroid Build Coastguard Worker     return seek_status;
54*61c4878aSAndroid Build Coastguard Worker   }
55*61c4878aSAndroid Build Coastguard Worker 
DoRead(ByteSpan dest)56*61c4878aSAndroid Build Coastguard Worker   StatusWithSize DoRead(ByteSpan dest) final {
57*61c4878aSAndroid Build Coastguard Worker     if (!read_status.ok()) {
58*61c4878aSAndroid Build Coastguard Worker       return StatusWithSize(read_status, 0);
59*61c4878aSAndroid Build Coastguard Worker     }
60*61c4878aSAndroid Build Coastguard Worker 
61*61c4878aSAndroid Build Coastguard Worker     auto result = memory_reader_.Read(dest);
62*61c4878aSAndroid Build Coastguard Worker     return result.ok() ? StatusWithSize(result->size())
63*61c4878aSAndroid Build Coastguard Worker                        : StatusWithSize(result.status(), 0);
64*61c4878aSAndroid Build Coastguard Worker   }
65*61c4878aSAndroid Build Coastguard Worker 
66*61c4878aSAndroid Build Coastguard Worker   Status seek_status;
67*61c4878aSAndroid Build Coastguard Worker   Status read_status;
68*61c4878aSAndroid Build Coastguard Worker 
69*61c4878aSAndroid Build Coastguard Worker  private:
70*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader memory_reader_;
71*61c4878aSAndroid Build Coastguard Worker };
72*61c4878aSAndroid Build Coastguard Worker 
73*61c4878aSAndroid Build Coastguard Worker class SimpleReadTransfer : public ReadOnlyHandler {
74*61c4878aSAndroid Build Coastguard Worker  public:
SimpleReadTransfer(uint32_t session_id,ConstByteSpan data)75*61c4878aSAndroid Build Coastguard Worker   SimpleReadTransfer(uint32_t session_id, ConstByteSpan data)
76*61c4878aSAndroid Build Coastguard Worker       : ReadOnlyHandler(session_id),
77*61c4878aSAndroid Build Coastguard Worker         prepare_read_called(false),
78*61c4878aSAndroid Build Coastguard Worker         finalize_read_called(false),
79*61c4878aSAndroid Build Coastguard Worker         finalize_read_status(Status::Unknown()),
80*61c4878aSAndroid Build Coastguard Worker         resource_size_(std::numeric_limits<size_t>::max()),
81*61c4878aSAndroid Build Coastguard Worker         reader_(data) {}
82*61c4878aSAndroid Build Coastguard Worker 
PrepareRead()83*61c4878aSAndroid Build Coastguard Worker   Status PrepareRead() final {
84*61c4878aSAndroid Build Coastguard Worker     prepare_read_called = true;
85*61c4878aSAndroid Build Coastguard Worker 
86*61c4878aSAndroid Build Coastguard Worker     if (!prepare_read_return_status.ok()) {
87*61c4878aSAndroid Build Coastguard Worker       return prepare_read_return_status;
88*61c4878aSAndroid Build Coastguard Worker     }
89*61c4878aSAndroid Build Coastguard Worker 
90*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(reader_.seek_status, reader_.Seek(0));
91*61c4878aSAndroid Build Coastguard Worker     set_reader(reader_);
92*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
93*61c4878aSAndroid Build Coastguard Worker   }
94*61c4878aSAndroid Build Coastguard Worker 
FinalizeRead(Status status)95*61c4878aSAndroid Build Coastguard Worker   void FinalizeRead(Status status) final {
96*61c4878aSAndroid Build Coastguard Worker     finalize_read_called = true;
97*61c4878aSAndroid Build Coastguard Worker     finalize_read_status = status;
98*61c4878aSAndroid Build Coastguard Worker   }
99*61c4878aSAndroid Build Coastguard Worker 
ResourceSize() const100*61c4878aSAndroid Build Coastguard Worker   size_t ResourceSize() const final { return resource_size_; }
101*61c4878aSAndroid Build Coastguard Worker 
set_resource_size(size_t resource_size)102*61c4878aSAndroid Build Coastguard Worker   void set_resource_size(size_t resource_size) {
103*61c4878aSAndroid Build Coastguard Worker     resource_size_ = resource_size;
104*61c4878aSAndroid Build Coastguard Worker   }
set_seek_status(Status status)105*61c4878aSAndroid Build Coastguard Worker   void set_seek_status(Status status) { reader_.seek_status = status; }
set_read_status(Status status)106*61c4878aSAndroid Build Coastguard Worker   void set_read_status(Status status) { reader_.read_status = status; }
107*61c4878aSAndroid Build Coastguard Worker 
108*61c4878aSAndroid Build Coastguard Worker   bool prepare_read_called;
109*61c4878aSAndroid Build Coastguard Worker   bool finalize_read_called;
110*61c4878aSAndroid Build Coastguard Worker   Status prepare_read_return_status;
111*61c4878aSAndroid Build Coastguard Worker   Status finalize_read_status;
112*61c4878aSAndroid Build Coastguard Worker   size_t resource_size_;
113*61c4878aSAndroid Build Coastguard Worker 
114*61c4878aSAndroid Build Coastguard Worker  private:
115*61c4878aSAndroid Build Coastguard Worker   TestMemoryReader reader_;
116*61c4878aSAndroid Build Coastguard Worker };
117*61c4878aSAndroid Build Coastguard Worker 
__anonbff93a0d0202(size_t i) 118*61c4878aSAndroid Build Coastguard Worker constexpr auto kData = bytes::Initialized<32>([](size_t i) { return i; });
119*61c4878aSAndroid Build Coastguard Worker constexpr uint32_t kArbitrarySessionId = 123;
120*61c4878aSAndroid Build Coastguard Worker 
121*61c4878aSAndroid Build Coastguard Worker class ReadTransfer : public ::testing::Test {
122*61c4878aSAndroid Build Coastguard Worker  protected:
ReadTransfer(size_t max_chunk_size_bytes=64)123*61c4878aSAndroid Build Coastguard Worker   ReadTransfer(size_t max_chunk_size_bytes = 64)
124*61c4878aSAndroid Build Coastguard Worker       : handler_(3, kData),
125*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(span(data_buffer_).first(max_chunk_size_bytes),
126*61c4878aSAndroid Build Coastguard Worker                          encode_buffer_),
127*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
128*61c4878aSAndroid Build Coastguard Worker              64,
129*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
130*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1)),
131*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_) {
132*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
133*61c4878aSAndroid Build Coastguard Worker 
134*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_read_called);
135*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_read_called);
136*61c4878aSAndroid Build Coastguard Worker 
137*61c4878aSAndroid Build Coastguard Worker     ctx_.call();  // Open the read stream
138*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
139*61c4878aSAndroid Build Coastguard Worker   }
140*61c4878aSAndroid Build Coastguard Worker 
~ReadTransfer()141*61c4878aSAndroid Build Coastguard Worker   ~ReadTransfer() override {
142*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
143*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
144*61c4878aSAndroid Build Coastguard Worker   }
145*61c4878aSAndroid Build Coastguard Worker 
146*61c4878aSAndroid Build Coastguard Worker   SimpleReadTransfer handler_;
147*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
148*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read, 8) ctx_;
149*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
150*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> data_buffer_;
151*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> encode_buffer_;
152*61c4878aSAndroid Build Coastguard Worker };
153*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,SingleChunk)154*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, SingleChunk) {
155*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 2, [this] {
156*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
157*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
158*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(3)
159*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(64)
160*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
161*61c4878aSAndroid Build Coastguard Worker 
162*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
163*61c4878aSAndroid Build Coastguard Worker   });
164*61c4878aSAndroid Build Coastguard Worker 
165*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
166*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
167*61c4878aSAndroid Build Coastguard Worker 
168*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
169*61c4878aSAndroid Build Coastguard Worker   Chunk c0 = DecodeChunk(ctx_.responses()[0]);
170*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
171*61c4878aSAndroid Build Coastguard Worker 
172*61c4878aSAndroid Build Coastguard Worker   // First chunk should have all the read data.
173*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.session_id(), 3u);
174*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.offset(), 0u);
175*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c0.payload().size(), kData.size());
176*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c0.payload().data(), kData.data(), c0.payload().size()),
177*61c4878aSAndroid Build Coastguard Worker             0);
178*61c4878aSAndroid Build Coastguard Worker 
179*61c4878aSAndroid Build Coastguard Worker   // Second chunk should be empty and set remaining_bytes = 0.
180*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
181*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c1.has_payload());
182*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.remaining_bytes().has_value());
183*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.remaining_bytes().value(), 0u);
184*61c4878aSAndroid Build Coastguard Worker 
185*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
186*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
187*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
188*61c4878aSAndroid Build Coastguard Worker 
189*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
190*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
191*61c4878aSAndroid Build Coastguard Worker }
192*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,MultiChunk)193*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, MultiChunk) {
194*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
195*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
196*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
197*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
198*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
199*61c4878aSAndroid Build Coastguard Worker 
200*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
201*61c4878aSAndroid Build Coastguard Worker 
202*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
203*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
204*61c4878aSAndroid Build Coastguard Worker 
205*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
206*61c4878aSAndroid Build Coastguard Worker   Chunk c0 = DecodeChunk(ctx_.responses().back());
207*61c4878aSAndroid Build Coastguard Worker 
208*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.session_id(), 3u);
209*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.offset(), 0u);
210*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c0.payload().size(), 16u);
211*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c0.payload().data(), kData.data(), c0.payload().size()),
212*61c4878aSAndroid Build Coastguard Worker             0);
213*61c4878aSAndroid Build Coastguard Worker 
214*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
215*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersContinue)
216*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
217*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(32)
218*61c4878aSAndroid Build Coastguard Worker           .set_offset(16)));
219*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
220*61c4878aSAndroid Build Coastguard Worker 
221*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
222*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses().back());
223*61c4878aSAndroid Build Coastguard Worker 
224*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
225*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 16u);
226*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 16u);
227*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
228*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c1.payload().data(), kData.data() + 16, c1.payload().size()),
229*61c4878aSAndroid Build Coastguard Worker       0);
230*61c4878aSAndroid Build Coastguard Worker 
231*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
232*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersContinue)
233*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
234*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(48)
235*61c4878aSAndroid Build Coastguard Worker           .set_offset(32)));
236*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
237*61c4878aSAndroid Build Coastguard Worker 
238*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
239*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
240*61c4878aSAndroid Build Coastguard Worker 
241*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), 3u);
242*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c2.has_payload());
243*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c2.remaining_bytes().has_value());
244*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.remaining_bytes().value(), 0u);
245*61c4878aSAndroid Build Coastguard Worker 
246*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
247*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
248*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
249*61c4878aSAndroid Build Coastguard Worker 
250*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
251*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
252*61c4878aSAndroid Build Coastguard Worker }
253*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,MultiChunk_RepeatedContinuePackets)254*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, MultiChunk_RepeatedContinuePackets) {
255*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
256*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
257*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
258*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
259*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
260*61c4878aSAndroid Build Coastguard Worker 
261*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
262*61c4878aSAndroid Build Coastguard Worker 
263*61c4878aSAndroid Build Coastguard Worker   const auto continue_chunk = EncodeChunk(
264*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersContinue)
265*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
266*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(24)
267*61c4878aSAndroid Build Coastguard Worker           .set_offset(16));
268*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(continue_chunk);
269*61c4878aSAndroid Build Coastguard Worker 
270*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
271*61c4878aSAndroid Build Coastguard Worker 
272*61c4878aSAndroid Build Coastguard Worker   // Resend the CONTINUE packets that don't actually advance the window.
273*61c4878aSAndroid Build Coastguard Worker   for (int i = 0; i < 3; ++i) {
274*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(continue_chunk);
275*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
276*61c4878aSAndroid Build Coastguard Worker   }
277*61c4878aSAndroid Build Coastguard Worker 
278*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);  // Only sent one packet
279*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
280*61c4878aSAndroid Build Coastguard Worker 
281*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
282*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 16u);
283*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 8u);
284*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
285*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c1.payload().data(), kData.data() + 16, c1.payload().size()),
286*61c4878aSAndroid Build Coastguard Worker       0);
287*61c4878aSAndroid Build Coastguard Worker }
288*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,OutOfOrder_SeekingSupported)289*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, OutOfOrder_SeekingSupported) {
290*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 4, [this] {
291*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
292*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
293*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(3)
294*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(16)
295*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
296*61c4878aSAndroid Build Coastguard Worker 
297*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
298*61c4878aSAndroid Build Coastguard Worker 
299*61c4878aSAndroid Build Coastguard Worker     Chunk chunk = DecodeChunk(ctx_.responses().back());
300*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(pw::containers::Equal(span(kData).first(16), chunk.payload()));
301*61c4878aSAndroid Build Coastguard Worker 
302*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
303*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
304*61c4878aSAndroid Build Coastguard Worker             .set_session_id(3)
305*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(10)
306*61c4878aSAndroid Build Coastguard Worker             .set_offset(2)));
307*61c4878aSAndroid Build Coastguard Worker 
308*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
309*61c4878aSAndroid Build Coastguard Worker 
310*61c4878aSAndroid Build Coastguard Worker     chunk = DecodeChunk(ctx_.responses().back());
311*61c4878aSAndroid Build Coastguard Worker     EXPECT_TRUE(
312*61c4878aSAndroid Build Coastguard Worker         pw::containers::Equal(span(kData).subspan(2, 8), chunk.payload()));
313*61c4878aSAndroid Build Coastguard Worker 
314*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
315*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
316*61c4878aSAndroid Build Coastguard Worker             .set_session_id(3)
317*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(64)
318*61c4878aSAndroid Build Coastguard Worker             .set_offset(17)));
319*61c4878aSAndroid Build Coastguard Worker   });
320*61c4878aSAndroid Build Coastguard Worker 
321*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
322*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses()[2]);
323*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(pw::containers::Equal(
324*61c4878aSAndroid Build Coastguard Worker       span(&kData[17], kData.data() + kData.size()), chunk.payload()));
325*61c4878aSAndroid Build Coastguard Worker }
326*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,OutOfOrder_SeekingNotSupported_EndsWithUnimplemented)327*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, OutOfOrder_SeekingNotSupported_EndsWithUnimplemented) {
328*61c4878aSAndroid Build Coastguard Worker   handler_.set_seek_status(Status::Unimplemented());
329*61c4878aSAndroid Build Coastguard Worker 
330*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
331*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
332*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
333*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
334*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
335*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
336*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
337*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
338*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(10)
339*61c4878aSAndroid Build Coastguard Worker           .set_offset(2)));
340*61c4878aSAndroid Build Coastguard Worker 
341*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
342*61c4878aSAndroid Build Coastguard Worker 
343*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
344*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
345*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
346*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::Unimplemented());
347*61c4878aSAndroid Build Coastguard Worker }
348*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,MaxChunkSize_Client)349*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, MaxChunkSize_Client) {
350*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 5, [this] {
351*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
352*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
353*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(3)
354*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(64)
355*61c4878aSAndroid Build Coastguard Worker                         .set_max_chunk_size_bytes(8)
356*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
357*61c4878aSAndroid Build Coastguard Worker   });
358*61c4878aSAndroid Build Coastguard Worker 
359*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
360*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
361*61c4878aSAndroid Build Coastguard Worker 
362*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
363*61c4878aSAndroid Build Coastguard Worker   Chunk c0 = DecodeChunk(ctx_.responses()[0]);
364*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
365*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
366*61c4878aSAndroid Build Coastguard Worker   Chunk c3 = DecodeChunk(ctx_.responses()[3]);
367*61c4878aSAndroid Build Coastguard Worker   Chunk c4 = DecodeChunk(ctx_.responses()[4]);
368*61c4878aSAndroid Build Coastguard Worker 
369*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.session_id(), 3u);
370*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.offset(), 0u);
371*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c0.payload().size(), 8u);
372*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c0.payload().data(), kData.data(), c0.payload().size()),
373*61c4878aSAndroid Build Coastguard Worker             0);
374*61c4878aSAndroid Build Coastguard Worker 
375*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
376*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 8u);
377*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 8u);
378*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
379*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c1.payload().data(), kData.data() + 8, c1.payload().size()),
380*61c4878aSAndroid Build Coastguard Worker       0);
381*61c4878aSAndroid Build Coastguard Worker 
382*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), 3u);
383*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.offset(), 16u);
384*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c2.payload().size(), 8u);
385*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
386*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c2.payload().data(), kData.data() + 16, c2.payload().size()),
387*61c4878aSAndroid Build Coastguard Worker       0);
388*61c4878aSAndroid Build Coastguard Worker 
389*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.session_id(), 3u);
390*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.offset(), 24u);
391*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c3.payload().size(), 8u);
392*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
393*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c3.payload().data(), kData.data() + 24, c3.payload().size()),
394*61c4878aSAndroid Build Coastguard Worker       0);
395*61c4878aSAndroid Build Coastguard Worker 
396*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.session_id(), 3u);
397*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.payload().size(), 0u);
398*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c4.remaining_bytes().has_value());
399*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.remaining_bytes().value(), 0u);
400*61c4878aSAndroid Build Coastguard Worker 
401*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
402*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
403*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
404*61c4878aSAndroid Build Coastguard Worker 
405*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
406*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
407*61c4878aSAndroid Build Coastguard Worker }
408*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,HandlerIsClearedAfterTransfer)409*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, HandlerIsClearedAfterTransfer) {
410*61c4878aSAndroid Build Coastguard Worker   // Request an end offset smaller than the data size to prevent the server
411*61c4878aSAndroid Build Coastguard Worker   // from sending a final chunk.
412*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
413*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
414*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
415*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
416*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
417*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
418*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
419*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
420*61c4878aSAndroid Build Coastguard Worker 
421*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
422*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.prepare_read_called);
423*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.finalize_read_called);
424*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(OkStatus(), handler_.finalize_read_status);
425*61c4878aSAndroid Build Coastguard Worker 
426*61c4878aSAndroid Build Coastguard Worker   // Now, clear state and start a second transfer
427*61c4878aSAndroid Build Coastguard Worker   handler_.prepare_read_return_status = Status::FailedPrecondition();
428*61c4878aSAndroid Build Coastguard Worker   handler_.prepare_read_called = false;
429*61c4878aSAndroid Build Coastguard Worker   handler_.finalize_read_called = false;
430*61c4878aSAndroid Build Coastguard Worker 
431*61c4878aSAndroid Build Coastguard Worker   // Request an end offset smaller than the data size to prevent the server
432*61c4878aSAndroid Build Coastguard Worker   // from sending a final chunk.
433*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
434*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
435*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
436*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
437*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
438*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
439*61c4878aSAndroid Build Coastguard Worker 
440*61c4878aSAndroid Build Coastguard Worker   // Prepare failed, so the handler should not have been stored in the context,
441*61c4878aSAndroid Build Coastguard Worker   // and finalize should not have been called.
442*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.prepare_read_called);
443*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(handler_.finalize_read_called);
444*61c4878aSAndroid Build Coastguard Worker }
445*61c4878aSAndroid Build Coastguard Worker 
446*61c4878aSAndroid Build Coastguard Worker class ReadTransferMaxChunkSize8 : public ReadTransfer {
447*61c4878aSAndroid Build Coastguard Worker  protected:
ReadTransferMaxChunkSize8()448*61c4878aSAndroid Build Coastguard Worker   ReadTransferMaxChunkSize8() : ReadTransfer(/*max_chunk_size_bytes=*/8) {}
449*61c4878aSAndroid Build Coastguard Worker };
450*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransferMaxChunkSize8,MaxChunkSize_Server)451*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransferMaxChunkSize8, MaxChunkSize_Server) {
452*61c4878aSAndroid Build Coastguard Worker   // Client asks for max 16-byte chunks, but service places a limit of 8 bytes.
453*61c4878aSAndroid Build Coastguard Worker   // TODO(frolv): Fix
454*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 5, [this] {
455*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
456*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
457*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(3)
458*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(64)
459*61c4878aSAndroid Build Coastguard Worker                         // .set_max_chunk_size_bytes(16)
460*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
461*61c4878aSAndroid Build Coastguard Worker   });
462*61c4878aSAndroid Build Coastguard Worker 
463*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
464*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
465*61c4878aSAndroid Build Coastguard Worker 
466*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
467*61c4878aSAndroid Build Coastguard Worker   Chunk c0 = DecodeChunk(ctx_.responses()[0]);
468*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
469*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
470*61c4878aSAndroid Build Coastguard Worker   Chunk c3 = DecodeChunk(ctx_.responses()[3]);
471*61c4878aSAndroid Build Coastguard Worker   Chunk c4 = DecodeChunk(ctx_.responses()[4]);
472*61c4878aSAndroid Build Coastguard Worker 
473*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.session_id(), 3u);
474*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.offset(), 0u);
475*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c0.payload().size(), 8u);
476*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c0.payload().data(), kData.data(), c0.payload().size()),
477*61c4878aSAndroid Build Coastguard Worker             0);
478*61c4878aSAndroid Build Coastguard Worker 
479*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
480*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 8u);
481*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 8u);
482*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
483*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c1.payload().data(), kData.data() + 8, c1.payload().size()),
484*61c4878aSAndroid Build Coastguard Worker       0);
485*61c4878aSAndroid Build Coastguard Worker 
486*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), 3u);
487*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.offset(), 16u);
488*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c2.payload().size(), 8u);
489*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
490*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c2.payload().data(), kData.data() + 16, c2.payload().size()),
491*61c4878aSAndroid Build Coastguard Worker       0);
492*61c4878aSAndroid Build Coastguard Worker 
493*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.session_id(), 3u);
494*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.offset(), 24u);
495*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c3.payload().size(), 8u);
496*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
497*61c4878aSAndroid Build Coastguard Worker       std::memcmp(c3.payload().data(), kData.data() + 24, c3.payload().size()),
498*61c4878aSAndroid Build Coastguard Worker       0);
499*61c4878aSAndroid Build Coastguard Worker 
500*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.session_id(), 3u);
501*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.payload().size(), 0u);
502*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c4.remaining_bytes().has_value());
503*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.remaining_bytes().value(), 0u);
504*61c4878aSAndroid Build Coastguard Worker 
505*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
506*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
507*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
508*61c4878aSAndroid Build Coastguard Worker 
509*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
510*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
511*61c4878aSAndroid Build Coastguard Worker }
512*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,ClientError)513*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, ClientError) {
514*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
515*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
516*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
517*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
518*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
519*61c4878aSAndroid Build Coastguard Worker 
520*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
521*61c4878aSAndroid Build Coastguard Worker 
522*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
523*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
524*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
525*61c4878aSAndroid Build Coastguard Worker 
526*61c4878aSAndroid Build Coastguard Worker   // Send client error.
527*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
528*61c4878aSAndroid Build Coastguard Worker       Chunk::Final(ProtocolVersion::kLegacy, 3, Status::OutOfRange())));
529*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
530*61c4878aSAndroid Build Coastguard Worker 
531*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
532*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
533*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, Status::OutOfRange());
534*61c4878aSAndroid Build Coastguard Worker }
535*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,UnregisteredHandler)536*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, UnregisteredHandler) {
537*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
538*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
539*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(11)
540*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(32)
541*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
542*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
543*61c4878aSAndroid Build Coastguard Worker 
544*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
545*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
546*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 11u);
547*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
548*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::NotFound());
549*61c4878aSAndroid Build Coastguard Worker }
550*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,IgnoresNonPendingTransfers)551*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, IgnoresNonPendingTransfers) {
552*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
553*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
554*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
555*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(32)
556*61c4878aSAndroid Build Coastguard Worker           .set_offset(3)));
557*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
558*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
559*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
560*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(10))
561*61c4878aSAndroid Build Coastguard Worker                       .set_offset(3)));
562*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
563*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
564*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
565*61c4878aSAndroid Build Coastguard Worker 
566*61c4878aSAndroid Build Coastguard Worker   // Only start transfer for an initial packet.
567*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.prepare_read_called);
568*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
569*61c4878aSAndroid Build Coastguard Worker }
570*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,AbortAndRestartIfInitialPacketIsReceived)571*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, AbortAndRestartIfInitialPacketIsReceived) {
572*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
573*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
574*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
575*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
576*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
577*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
578*61c4878aSAndroid Build Coastguard Worker 
579*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
580*61c4878aSAndroid Build Coastguard Worker 
581*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
582*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
583*61c4878aSAndroid Build Coastguard Worker   handler_.prepare_read_called = false;  // Reset so can check if called again.
584*61c4878aSAndroid Build Coastguard Worker 
585*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(  // Resend starting chunk
586*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
587*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
588*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
589*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
590*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
591*61c4878aSAndroid Build Coastguard Worker 
592*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
593*61c4878aSAndroid Build Coastguard Worker 
594*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
595*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
596*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, Status::Aborted());
597*61c4878aSAndroid Build Coastguard Worker   handler_.finalize_read_called = false;  // Reset so can check later
598*61c4878aSAndroid Build Coastguard Worker 
599*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
600*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
601*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
602*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(32)
603*61c4878aSAndroid Build Coastguard Worker           .set_offset(16)));
604*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
605*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
606*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
607*61c4878aSAndroid Build Coastguard Worker 
608*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
609*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
610*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
611*61c4878aSAndroid Build Coastguard Worker }
612*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,ZeroPendingBytesWithRemainingData_Aborts)613*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, ZeroPendingBytesWithRemainingData_Aborts) {
614*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
615*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
616*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
617*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(0)
618*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
619*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
620*61c4878aSAndroid Build Coastguard Worker 
621*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
622*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.finalize_read_called);
623*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, Status::ResourceExhausted());
624*61c4878aSAndroid Build Coastguard Worker 
625*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
626*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status(), Status::ResourceExhausted());
627*61c4878aSAndroid Build Coastguard Worker }
628*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,ZeroPendingBytesNoRemainingData_Completes)629*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, ZeroPendingBytesNoRemainingData_Completes) {
630*61c4878aSAndroid Build Coastguard Worker   // Make the next read appear to be the end of the stream.
631*61c4878aSAndroid Build Coastguard Worker   handler_.set_read_status(Status::OutOfRange());
632*61c4878aSAndroid Build Coastguard Worker 
633*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
634*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
635*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(3)
636*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(0)
637*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
638*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
639*61c4878aSAndroid Build Coastguard Worker 
640*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
641*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 3u);
642*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.remaining_bytes(), 0u);
643*61c4878aSAndroid Build Coastguard Worker 
644*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
645*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
646*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
647*61c4878aSAndroid Build Coastguard Worker 
648*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
649*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.finalize_read_called);
650*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
651*61c4878aSAndroid Build Coastguard Worker }
652*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,SendsErrorIfChunkIsReceivedInCompletedState)653*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, SendsErrorIfChunkIsReceivedInCompletedState) {
654*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 2, [this] {
655*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
656*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
657*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(3)
658*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(64)
659*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
660*61c4878aSAndroid Build Coastguard Worker   });
661*61c4878aSAndroid Build Coastguard Worker 
662*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
663*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
664*61c4878aSAndroid Build Coastguard Worker 
665*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
666*61c4878aSAndroid Build Coastguard Worker   Chunk c0 = DecodeChunk(ctx_.responses()[0]);
667*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
668*61c4878aSAndroid Build Coastguard Worker 
669*61c4878aSAndroid Build Coastguard Worker   // First chunk should have all the read data.
670*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.session_id(), 3u);
671*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c0.offset(), 0u);
672*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c0.payload().size(), kData.size());
673*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c0.payload().data(), kData.data(), c0.payload().size()),
674*61c4878aSAndroid Build Coastguard Worker             0);
675*61c4878aSAndroid Build Coastguard Worker 
676*61c4878aSAndroid Build Coastguard Worker   // Second chunk should be empty and set remaining_bytes = 0.
677*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), 3u);
678*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c1.has_payload());
679*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.remaining_bytes().has_value());
680*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.remaining_bytes().value(), 0u);
681*61c4878aSAndroid Build Coastguard Worker 
682*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
683*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kLegacy, 3, OkStatus())));
684*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
685*61c4878aSAndroid Build Coastguard Worker 
686*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
687*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
688*61c4878aSAndroid Build Coastguard Worker 
689*61c4878aSAndroid Build Coastguard Worker   // At this point the transfer should be in a completed state. Send a
690*61c4878aSAndroid Build Coastguard Worker   // non-initial chunk as a continuation of the transfer.
691*61c4878aSAndroid Build Coastguard Worker   handler_.finalize_read_called = false;
692*61c4878aSAndroid Build Coastguard Worker 
693*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
694*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersRetransmit)
695*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
696*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(64)
697*61c4878aSAndroid Build Coastguard Worker           .set_offset(16)));
698*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
699*61c4878aSAndroid Build Coastguard Worker 
700*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
701*61c4878aSAndroid Build Coastguard Worker 
702*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
703*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c2.status().has_value());
704*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.status().value(), Status::FailedPrecondition());
705*61c4878aSAndroid Build Coastguard Worker 
706*61c4878aSAndroid Build Coastguard Worker   // FinalizeRead should not be called again.
707*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
708*61c4878aSAndroid Build Coastguard Worker }
709*61c4878aSAndroid Build Coastguard Worker 
710*61c4878aSAndroid Build Coastguard Worker class SimpleWriteTransfer final : public WriteOnlyHandler {
711*61c4878aSAndroid Build Coastguard Worker  public:
SimpleWriteTransfer(uint32_t session_id,ByteSpan data)712*61c4878aSAndroid Build Coastguard Worker   SimpleWriteTransfer(uint32_t session_id, ByteSpan data)
713*61c4878aSAndroid Build Coastguard Worker       : WriteOnlyHandler(session_id),
714*61c4878aSAndroid Build Coastguard Worker         prepare_write_called(false),
715*61c4878aSAndroid Build Coastguard Worker         finalize_write_called(false),
716*61c4878aSAndroid Build Coastguard Worker         finalize_write_status(Status::Unknown()),
717*61c4878aSAndroid Build Coastguard Worker         writer_(data) {}
718*61c4878aSAndroid Build Coastguard Worker 
PrepareWrite()719*61c4878aSAndroid Build Coastguard Worker   Status PrepareWrite() final {
720*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(OkStatus(), writer_.Seek(0));
721*61c4878aSAndroid Build Coastguard Worker     set_writer(writer_);
722*61c4878aSAndroid Build Coastguard Worker     prepare_write_called = true;
723*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
724*61c4878aSAndroid Build Coastguard Worker   }
725*61c4878aSAndroid Build Coastguard Worker 
FinalizeWrite(Status status)726*61c4878aSAndroid Build Coastguard Worker   Status FinalizeWrite(Status status) final {
727*61c4878aSAndroid Build Coastguard Worker     finalize_write_called = true;
728*61c4878aSAndroid Build Coastguard Worker     finalize_write_status = status;
729*61c4878aSAndroid Build Coastguard Worker     return finalize_write_return_status_;
730*61c4878aSAndroid Build Coastguard Worker   }
731*61c4878aSAndroid Build Coastguard Worker 
set_finalize_write_return(Status status)732*61c4878aSAndroid Build Coastguard Worker   void set_finalize_write_return(Status status) {
733*61c4878aSAndroid Build Coastguard Worker     finalize_write_return_status_ = status;
734*61c4878aSAndroid Build Coastguard Worker   }
735*61c4878aSAndroid Build Coastguard Worker 
736*61c4878aSAndroid Build Coastguard Worker   bool prepare_write_called;
737*61c4878aSAndroid Build Coastguard Worker   bool finalize_write_called;
738*61c4878aSAndroid Build Coastguard Worker   Status finalize_write_status;
739*61c4878aSAndroid Build Coastguard Worker 
740*61c4878aSAndroid Build Coastguard Worker  private:
741*61c4878aSAndroid Build Coastguard Worker   Status finalize_write_return_status_;
742*61c4878aSAndroid Build Coastguard Worker   stream::MemoryWriter writer_;
743*61c4878aSAndroid Build Coastguard Worker };
744*61c4878aSAndroid Build Coastguard Worker 
745*61c4878aSAndroid Build Coastguard Worker class WriteTransfer : public ::testing::Test {
746*61c4878aSAndroid Build Coastguard Worker  protected:
WriteTransfer(size_t max_bytes_to_receive=64)747*61c4878aSAndroid Build Coastguard Worker   WriteTransfer(size_t max_bytes_to_receive = 64)
748*61c4878aSAndroid Build Coastguard Worker       : buffer{},
749*61c4878aSAndroid Build Coastguard Worker         handler_(7, buffer),
750*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(data_buffer_, encode_buffer_),
751*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_),
752*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
753*61c4878aSAndroid Build Coastguard Worker              max_bytes_to_receive,
754*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
755*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1),
756*61c4878aSAndroid Build Coastguard Worker              /*max_retries=*/3) {
757*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
758*61c4878aSAndroid Build Coastguard Worker 
759*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_write_called);
760*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_write_called);
761*61c4878aSAndroid Build Coastguard Worker 
762*61c4878aSAndroid Build Coastguard Worker     ctx_.call();  // Open the write stream
763*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
764*61c4878aSAndroid Build Coastguard Worker   }
765*61c4878aSAndroid Build Coastguard Worker 
~WriteTransfer()766*61c4878aSAndroid Build Coastguard Worker   ~WriteTransfer() override {
767*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
768*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
769*61c4878aSAndroid Build Coastguard Worker   }
770*61c4878aSAndroid Build Coastguard Worker 
771*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kData.size()> buffer;
772*61c4878aSAndroid Build Coastguard Worker   SimpleWriteTransfer handler_;
773*61c4878aSAndroid Build Coastguard Worker 
774*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
775*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
776*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> data_buffer_;
777*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> encode_buffer_;
778*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write) ctx_;
779*61c4878aSAndroid Build Coastguard Worker };
780*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,SingleChunk)781*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, SingleChunk) {
782*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
783*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
784*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
785*61c4878aSAndroid Build Coastguard Worker 
786*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
787*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
788*61c4878aSAndroid Build Coastguard Worker 
789*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
790*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
791*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
792*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
793*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
794*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
795*61c4878aSAndroid Build Coastguard Worker 
796*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
797*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
798*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
799*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
800*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
801*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
802*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
803*61c4878aSAndroid Build Coastguard Worker 
804*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
805*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
806*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
807*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
808*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
809*61c4878aSAndroid Build Coastguard Worker 
810*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
811*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
812*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
813*61c4878aSAndroid Build Coastguard Worker }
814*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,FinalizeFails)815*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, FinalizeFails) {
816*61c4878aSAndroid Build Coastguard Worker   // Return an error when FinalizeWrite is called.
817*61c4878aSAndroid Build Coastguard Worker   handler_.set_finalize_write_return(Status::FailedPrecondition());
818*61c4878aSAndroid Build Coastguard Worker 
819*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
820*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
821*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
822*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
823*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
824*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
825*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
826*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
827*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
828*61c4878aSAndroid Build Coastguard Worker 
829*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
830*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses()[1]);
831*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
832*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
833*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::DataLoss());
834*61c4878aSAndroid Build Coastguard Worker 
835*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
836*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
837*61c4878aSAndroid Build Coastguard Worker }
838*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,SendingFinalPacketFails)839*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, SendingFinalPacketFails) {
840*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
841*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
842*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
843*61c4878aSAndroid Build Coastguard Worker 
844*61c4878aSAndroid Build Coastguard Worker   ctx_.output().set_send_status(Status::Unknown());
845*61c4878aSAndroid Build Coastguard Worker 
846*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
847*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
848*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
849*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
850*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
851*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
852*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
853*61c4878aSAndroid Build Coastguard Worker 
854*61c4878aSAndroid Build Coastguard Worker   // Should only have sent the transfer parameters.
855*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
856*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses()[0]);
857*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
858*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
859*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
860*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
861*61c4878aSAndroid Build Coastguard Worker 
862*61c4878aSAndroid Build Coastguard Worker   // When FinalizeWrite() was called, the transfer was considered successful.
863*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
864*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
865*61c4878aSAndroid Build Coastguard Worker }
866*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,MultiChunk)867*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, MultiChunk) {
868*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
869*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
870*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
871*61c4878aSAndroid Build Coastguard Worker 
872*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
873*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
874*61c4878aSAndroid Build Coastguard Worker 
875*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
876*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses()[0]);
877*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
878*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
879*61c4878aSAndroid Build Coastguard Worker 
880*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
881*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
882*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
883*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
884*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
885*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
886*61c4878aSAndroid Build Coastguard Worker 
887*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
888*61c4878aSAndroid Build Coastguard Worker 
889*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
890*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
891*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
892*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
893*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8))
894*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
895*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
896*61c4878aSAndroid Build Coastguard Worker 
897*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
898*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
899*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
900*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
901*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
902*61c4878aSAndroid Build Coastguard Worker 
903*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
904*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
905*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
906*61c4878aSAndroid Build Coastguard Worker }
907*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,WriteFailsOnRetry)908*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, WriteFailsOnRetry) {
909*61c4878aSAndroid Build Coastguard Worker   // Skip one packet to fail on a retry.
910*61c4878aSAndroid Build Coastguard Worker   ctx_.output().set_send_status(Status::FailedPrecondition(), 1);
911*61c4878aSAndroid Build Coastguard Worker 
912*61c4878aSAndroid Build Coastguard Worker   // Wait for 3 packets: initial params, retry attempt, final error
913*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 3, [this] {
914*61c4878aSAndroid Build Coastguard Worker     // Send only one client packet so the service times out.
915*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
916*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
917*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(7)));
918*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.SimulateServerTimeout(7);  // Time out to trigger retry
919*61c4878aSAndroid Build Coastguard Worker   });
920*61c4878aSAndroid Build Coastguard Worker 
921*61c4878aSAndroid Build Coastguard Worker   // Attempted to send 3 packets, but the 2nd packet was dropped.
922*61c4878aSAndroid Build Coastguard Worker   // Check that the last packet is an INTERNAL error from the RPC write failure.
923*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
924*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses()[1]);
925*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
926*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
927*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::Internal());
928*61c4878aSAndroid Build Coastguard Worker }
929*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,TimeoutInRecoveryState)930*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, TimeoutInRecoveryState) {
931*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
932*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
933*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
934*61c4878aSAndroid Build Coastguard Worker 
935*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
936*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
937*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
938*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
939*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
940*61c4878aSAndroid Build Coastguard Worker 
941*61c4878aSAndroid Build Coastguard Worker   constexpr span data(kData);
942*61c4878aSAndroid Build Coastguard Worker 
943*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
944*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
945*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
946*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
947*61c4878aSAndroid Build Coastguard Worker                       .set_payload(data.first(8))));
948*61c4878aSAndroid Build Coastguard Worker 
949*61c4878aSAndroid Build Coastguard Worker   // Skip offset 8 to enter a recovery state.
950*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
951*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
952*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
953*61c4878aSAndroid Build Coastguard Worker                       .set_offset(12)
954*61c4878aSAndroid Build Coastguard Worker                       .set_payload(data.subspan(12, 4))));
955*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
956*61c4878aSAndroid Build Coastguard Worker 
957*61c4878aSAndroid Build Coastguard Worker   // Recovery parameters should be sent for offset 8.
958*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
959*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
960*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
961*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 8u);
962*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
963*61c4878aSAndroid Build Coastguard Worker 
964*61c4878aSAndroid Build Coastguard Worker   // Timeout while in the recovery state.
965*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(7);
966*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
967*61c4878aSAndroid Build Coastguard Worker 
968*61c4878aSAndroid Build Coastguard Worker   // Same recovery parameters should be re-sent.
969*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
970*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
971*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
972*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 8u);
973*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
974*61c4878aSAndroid Build Coastguard Worker }
975*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,ExtendWindow)976*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, ExtendWindow) {
977*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
978*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
979*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
980*61c4878aSAndroid Build Coastguard Worker 
981*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
982*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
983*61c4878aSAndroid Build Coastguard Worker 
984*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
985*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
986*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
987*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
988*61c4878aSAndroid Build Coastguard Worker 
989*61c4878aSAndroid Build Coastguard Worker   // Window starts at 32 bytes and should extend when half of that is sent.
990*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
991*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
992*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
993*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
994*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(4))));
995*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
996*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
997*61c4878aSAndroid Build Coastguard Worker 
998*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
999*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1000*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1001*61c4878aSAndroid Build Coastguard Worker                       .set_offset(4)
1002*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(4, 4))));
1003*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1004*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1005*61c4878aSAndroid Build Coastguard Worker 
1006*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1007*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1008*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1009*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
1010*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8, 4))));
1011*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1012*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1013*61c4878aSAndroid Build Coastguard Worker 
1014*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1015*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1016*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1017*61c4878aSAndroid Build Coastguard Worker                       .set_offset(12)
1018*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(12, 4))));
1019*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1020*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1021*61c4878aSAndroid Build Coastguard Worker 
1022*61c4878aSAndroid Build Coastguard Worker   // Extend parameters chunk.
1023*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1024*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1025*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1026*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
1027*61c4878aSAndroid Build Coastguard Worker 
1028*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1029*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1030*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1031*61c4878aSAndroid Build Coastguard Worker                       .set_offset(16)
1032*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(16))
1033*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1034*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1035*61c4878aSAndroid Build Coastguard Worker 
1036*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1037*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[2]);
1038*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1039*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1040*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
1041*61c4878aSAndroid Build Coastguard Worker 
1042*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1043*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1044*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
1045*61c4878aSAndroid Build Coastguard Worker }
1046*61c4878aSAndroid Build Coastguard Worker 
1047*61c4878aSAndroid Build Coastguard Worker class WriteTransferMaxBytes16 : public WriteTransfer {
1048*61c4878aSAndroid Build Coastguard Worker  protected:
WriteTransferMaxBytes16()1049*61c4878aSAndroid Build Coastguard Worker   WriteTransferMaxBytes16() : WriteTransfer(/*max_bytes_to_receive=*/16) {}
1050*61c4878aSAndroid Build Coastguard Worker };
1051*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,TransmitterReducesWindow)1052*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, TransmitterReducesWindow) {
1053*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1054*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1055*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1056*61c4878aSAndroid Build Coastguard Worker 
1057*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1058*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1059*61c4878aSAndroid Build Coastguard Worker 
1060*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1061*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1062*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1063*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1064*61c4878aSAndroid Build Coastguard Worker 
1065*61c4878aSAndroid Build Coastguard Worker   // Send only 12 bytes and set that as the new end offset.
1066*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1067*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1068*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1069*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1070*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(12)
1071*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(12))));
1072*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1073*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1074*61c4878aSAndroid Build Coastguard Worker 
1075*61c4878aSAndroid Build Coastguard Worker   // Receiver should respond immediately with a continue chunk as the end of
1076*61c4878aSAndroid Build Coastguard Worker   // the window has been reached.
1077*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1078*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1079*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 12u);
1080*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1081*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
1082*61c4878aSAndroid Build Coastguard Worker }
1083*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,TransmitterExtendsWindow_TerminatesWithInvalid)1084*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, TransmitterExtendsWindow_TerminatesWithInvalid) {
1085*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1086*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1087*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1088*61c4878aSAndroid Build Coastguard Worker 
1089*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1090*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1091*61c4878aSAndroid Build Coastguard Worker 
1092*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1093*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1094*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1095*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1096*61c4878aSAndroid Build Coastguard Worker 
1097*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1098*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1099*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1100*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1101*61c4878aSAndroid Build Coastguard Worker                       // Larger window end offset than the receiver's.
1102*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(48)
1103*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(16))));
1104*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1105*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1106*61c4878aSAndroid Build Coastguard Worker 
1107*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1108*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1109*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1110*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::Internal());
1111*61c4878aSAndroid Build Coastguard Worker }
1112*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferMaxBytes16,MultipleParameters)1113*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferMaxBytes16, MultipleParameters) {
1114*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1115*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1116*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1117*61c4878aSAndroid Build Coastguard Worker 
1118*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1119*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1120*61c4878aSAndroid Build Coastguard Worker 
1121*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1122*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1123*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1124*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 16u);
1125*61c4878aSAndroid Build Coastguard Worker 
1126*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1127*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1128*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1129*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1130*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
1131*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1132*61c4878aSAndroid Build Coastguard Worker 
1133*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1134*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1135*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1136*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 8u);
1137*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 24u);
1138*61c4878aSAndroid Build Coastguard Worker 
1139*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1140*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1141*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1142*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
1143*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8, 8))));
1144*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1145*61c4878aSAndroid Build Coastguard Worker 
1146*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1147*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1148*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1149*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
1150*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1151*61c4878aSAndroid Build Coastguard Worker 
1152*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1153*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1154*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1155*61c4878aSAndroid Build Coastguard Worker                       .set_offset(16)
1156*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(16, 8))));
1157*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1158*61c4878aSAndroid Build Coastguard Worker 
1159*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
1160*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1161*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1162*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 24u);
1163*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1164*61c4878aSAndroid Build Coastguard Worker 
1165*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1166*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1167*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1168*61c4878aSAndroid Build Coastguard Worker                       .set_offset(24)
1169*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(24))
1170*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1171*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1172*61c4878aSAndroid Build Coastguard Worker 
1173*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
1174*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1175*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1176*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1177*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
1178*61c4878aSAndroid Build Coastguard Worker 
1179*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1180*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1181*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
1182*61c4878aSAndroid Build Coastguard Worker }
1183*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferMaxBytes16,SetsDefaultWindowEndOffset)1184*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferMaxBytes16, SetsDefaultWindowEndOffset) {
1185*61c4878aSAndroid Build Coastguard Worker   // Default max bytes is smaller than buffer.
1186*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1187*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1188*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1189*61c4878aSAndroid Build Coastguard Worker 
1190*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1191*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1192*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1193*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 16u);
1194*61c4878aSAndroid Build Coastguard Worker }
1195*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,SetsWriterWindowEndOffset)1196*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, SetsWriterWindowEndOffset) {
1197*61c4878aSAndroid Build Coastguard Worker   // Buffer is smaller than constructor's default max bytes.
1198*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 8> small_buffer = {};
1199*61c4878aSAndroid Build Coastguard Worker 
1200*61c4878aSAndroid Build Coastguard Worker   SimpleWriteTransfer handler_(987, small_buffer);
1201*61c4878aSAndroid Build Coastguard Worker   ctx_.service().RegisterHandler(handler_);
1202*61c4878aSAndroid Build Coastguard Worker 
1203*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1204*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
1205*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(987)));
1206*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1207*61c4878aSAndroid Build Coastguard Worker 
1208*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1209*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1210*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 987u);
1211*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 8u);
1212*61c4878aSAndroid Build Coastguard Worker 
1213*61c4878aSAndroid Build Coastguard Worker   ctx_.service().UnregisterHandler(handler_);
1214*61c4878aSAndroid Build Coastguard Worker }
1215*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,UnexpectedOffset)1216*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, UnexpectedOffset) {
1217*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1218*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1219*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1220*61c4878aSAndroid Build Coastguard Worker 
1221*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1222*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1223*61c4878aSAndroid Build Coastguard Worker 
1224*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1225*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1226*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1227*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
1228*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1229*61c4878aSAndroid Build Coastguard Worker 
1230*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1231*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1232*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1233*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1234*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
1235*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1236*61c4878aSAndroid Build Coastguard Worker 
1237*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1238*61c4878aSAndroid Build Coastguard Worker 
1239*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1240*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1241*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1242*61c4878aSAndroid Build Coastguard Worker                       .set_offset(4)  // incorrect
1243*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8))
1244*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1245*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1246*61c4878aSAndroid Build Coastguard Worker 
1247*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1248*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1249*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1250*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 8u);
1251*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1252*61c4878aSAndroid Build Coastguard Worker 
1253*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1254*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1255*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1256*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)  // correct
1257*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8))
1258*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1259*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1260*61c4878aSAndroid Build Coastguard Worker 
1261*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1262*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1263*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1264*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1265*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
1266*61c4878aSAndroid Build Coastguard Worker 
1267*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1268*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1269*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
1270*61c4878aSAndroid Build Coastguard Worker }
1271*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferMaxBytes16,TooMuchData_EntersRecovery)1272*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferMaxBytes16, TooMuchData_EntersRecovery) {
1273*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1274*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1275*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1276*61c4878aSAndroid Build Coastguard Worker 
1277*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1278*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1279*61c4878aSAndroid Build Coastguard Worker 
1280*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1281*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1282*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1283*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 16u);
1284*61c4878aSAndroid Build Coastguard Worker 
1285*61c4878aSAndroid Build Coastguard Worker   // window_end_offset = 16, but send 24 bytes of data.
1286*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1287*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1288*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1289*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1290*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(24))));
1291*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1292*61c4878aSAndroid Build Coastguard Worker 
1293*61c4878aSAndroid Build Coastguard Worker   // Transfer should resend a parameters chunk.
1294*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1295*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1296*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1297*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
1298*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
1299*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 16u);
1300*61c4878aSAndroid Build Coastguard Worker }
1301*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,UnregisteredHandler)1302*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, UnregisteredHandler) {
1303*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1304*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
1305*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(999)));
1306*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1307*61c4878aSAndroid Build Coastguard Worker 
1308*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1309*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1310*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 999u);
1311*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1312*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::NotFound());
1313*61c4878aSAndroid Build Coastguard Worker }
1314*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,ClientError)1315*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, ClientError) {
1316*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1317*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1318*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1319*61c4878aSAndroid Build Coastguard Worker 
1320*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1321*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1322*61c4878aSAndroid Build Coastguard Worker 
1323*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1324*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1325*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1326*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1327*61c4878aSAndroid Build Coastguard Worker 
1328*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(EncodeChunk(
1329*61c4878aSAndroid Build Coastguard Worker       Chunk::Final(ProtocolVersion::kLegacy, 7, Status::DataLoss())));
1330*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1331*61c4878aSAndroid Build Coastguard Worker 
1332*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(ctx_.total_responses(), 1u);
1333*61c4878aSAndroid Build Coastguard Worker 
1334*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1335*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, Status::DataLoss());
1336*61c4878aSAndroid Build Coastguard Worker }
1337*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,OnlySendParametersUpdateOnceAfterDrop)1338*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, OnlySendParametersUpdateOnceAfterDrop) {
1339*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1340*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1341*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1342*61c4878aSAndroid Build Coastguard Worker 
1343*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1344*61c4878aSAndroid Build Coastguard Worker 
1345*61c4878aSAndroid Build Coastguard Worker   constexpr span data(kData);
1346*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1347*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1348*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1349*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1350*61c4878aSAndroid Build Coastguard Worker                       .set_payload(data.first(1))));
1351*61c4878aSAndroid Build Coastguard Worker 
1352*61c4878aSAndroid Build Coastguard Worker   // Drop offset 1, then send the rest of the data.
1353*61c4878aSAndroid Build Coastguard Worker   for (uint32_t i = 2; i < kData.size(); ++i) {
1354*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream<64>(
1355*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1356*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(7)
1357*61c4878aSAndroid Build Coastguard Worker                         .set_offset(i)
1358*61c4878aSAndroid Build Coastguard Worker                         .set_payload(data.subspan(i, 1))));
1359*61c4878aSAndroid Build Coastguard Worker   }
1360*61c4878aSAndroid Build Coastguard Worker 
1361*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1362*61c4878aSAndroid Build Coastguard Worker 
1363*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1364*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1365*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1366*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 1u);
1367*61c4878aSAndroid Build Coastguard Worker 
1368*61c4878aSAndroid Build Coastguard Worker   // Send the remaining data.
1369*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1370*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1371*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1372*61c4878aSAndroid Build Coastguard Worker                       .set_offset(1)
1373*61c4878aSAndroid Build Coastguard Worker                       .set_payload(data.subspan(1, 31))
1374*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1375*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1376*61c4878aSAndroid Build Coastguard Worker 
1377*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1378*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1379*61c4878aSAndroid Build Coastguard Worker }
1380*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,ResendParametersIfSentRepeatedChunkDuringRecovery)1381*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, ResendParametersIfSentRepeatedChunkDuringRecovery) {
1382*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1383*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1384*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1385*61c4878aSAndroid Build Coastguard Worker 
1386*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1387*61c4878aSAndroid Build Coastguard Worker 
1388*61c4878aSAndroid Build Coastguard Worker   constexpr span data(kData);
1389*61c4878aSAndroid Build Coastguard Worker 
1390*61c4878aSAndroid Build Coastguard Worker   // Skip offset 0, then send the rest of the data.
1391*61c4878aSAndroid Build Coastguard Worker   for (uint32_t i = 1; i < kData.size(); ++i) {
1392*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream<64>(
1393*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1394*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(7)
1395*61c4878aSAndroid Build Coastguard Worker                         .set_offset(i)
1396*61c4878aSAndroid Build Coastguard Worker                         .set_payload(data.subspan(i, 1))));
1397*61c4878aSAndroid Build Coastguard Worker   }
1398*61c4878aSAndroid Build Coastguard Worker 
1399*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1400*61c4878aSAndroid Build Coastguard Worker 
1401*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);  // Resent transfer parameters once.
1402*61c4878aSAndroid Build Coastguard Worker 
1403*61c4878aSAndroid Build Coastguard Worker   const auto last_chunk =
1404*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1405*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1406*61c4878aSAndroid Build Coastguard Worker                       .set_offset(kData.size() - 1)
1407*61c4878aSAndroid Build Coastguard Worker                       .set_payload(data.last(1)));
1408*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(last_chunk);
1409*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1410*61c4878aSAndroid Build Coastguard Worker 
1411*61c4878aSAndroid Build Coastguard Worker   // Resent transfer parameters since the packet is repeated
1412*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1413*61c4878aSAndroid Build Coastguard Worker 
1414*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(last_chunk);
1415*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1416*61c4878aSAndroid Build Coastguard Worker 
1417*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
1418*61c4878aSAndroid Build Coastguard Worker 
1419*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1420*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1421*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
1422*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
1423*61c4878aSAndroid Build Coastguard Worker 
1424*61c4878aSAndroid Build Coastguard Worker   // Resumes normal operation when correct offset is sent.
1425*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1426*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1427*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1428*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1429*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
1430*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1431*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1432*61c4878aSAndroid Build Coastguard Worker 
1433*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1434*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1435*61c4878aSAndroid Build Coastguard Worker }
1436*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,ResendsStatusIfClientRetriesAfterStatusChunk)1437*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, ResendsStatusIfClientRetriesAfterStatusChunk) {
1438*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1439*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1440*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1441*61c4878aSAndroid Build Coastguard Worker 
1442*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1443*61c4878aSAndroid Build Coastguard Worker 
1444*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1445*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1446*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1447*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1448*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
1449*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1450*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1451*61c4878aSAndroid Build Coastguard Worker 
1452*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1453*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1454*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1455*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
1456*61c4878aSAndroid Build Coastguard Worker 
1457*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1458*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1459*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1460*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1461*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
1462*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1463*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1464*61c4878aSAndroid Build Coastguard Worker 
1465*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1466*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1467*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1468*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
1469*61c4878aSAndroid Build Coastguard Worker }
1470*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,IgnoresNonPendingTransfers)1471*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, IgnoresNonPendingTransfers) {
1472*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1473*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1474*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1475*61c4878aSAndroid Build Coastguard Worker                       .set_offset(3)));
1476*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1477*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1478*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1479*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1480*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(10))
1481*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1482*61c4878aSAndroid Build Coastguard Worker 
1483*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1484*61c4878aSAndroid Build Coastguard Worker 
1485*61c4878aSAndroid Build Coastguard Worker   // Only start transfer for initial packet.
1486*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.prepare_write_called);
1487*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1488*61c4878aSAndroid Build Coastguard Worker }
1489*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,AbortAndRestartIfInitialPacketIsReceived)1490*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, AbortAndRestartIfInitialPacketIsReceived) {
1491*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1492*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1493*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1494*61c4878aSAndroid Build Coastguard Worker 
1495*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1496*61c4878aSAndroid Build Coastguard Worker 
1497*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1498*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1499*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1500*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1501*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
1502*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1503*61c4878aSAndroid Build Coastguard Worker 
1504*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1505*61c4878aSAndroid Build Coastguard Worker 
1506*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(handler_.prepare_write_called);
1507*61c4878aSAndroid Build Coastguard Worker   ASSERT_FALSE(handler_.finalize_write_called);
1508*61c4878aSAndroid Build Coastguard Worker   handler_.prepare_write_called = false;  // Reset to check it's called again.
1509*61c4878aSAndroid Build Coastguard Worker 
1510*61c4878aSAndroid Build Coastguard Worker   // Simulate client disappearing then restarting the transfer.
1511*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1512*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1513*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1514*61c4878aSAndroid Build Coastguard Worker 
1515*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1516*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1517*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, Status::Aborted());
1518*61c4878aSAndroid Build Coastguard Worker 
1519*61c4878aSAndroid Build Coastguard Worker   handler_.finalize_write_called = false;  // Reset to check it's called again.
1520*61c4878aSAndroid Build Coastguard Worker 
1521*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1522*61c4878aSAndroid Build Coastguard Worker 
1523*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1524*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1525*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1526*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1527*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
1528*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
1529*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1530*61c4878aSAndroid Build Coastguard Worker 
1531*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1532*61c4878aSAndroid Build Coastguard Worker 
1533*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
1534*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
1535*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
1536*61c4878aSAndroid Build Coastguard Worker }
1537*61c4878aSAndroid Build Coastguard Worker 
1538*61c4878aSAndroid Build Coastguard Worker class SometimesUnavailableReadHandler final : public ReadOnlyHandler {
1539*61c4878aSAndroid Build Coastguard Worker  public:
SometimesUnavailableReadHandler(uint32_t session_id,ConstByteSpan data)1540*61c4878aSAndroid Build Coastguard Worker   SometimesUnavailableReadHandler(uint32_t session_id, ConstByteSpan data)
1541*61c4878aSAndroid Build Coastguard Worker       : ReadOnlyHandler(session_id), reader_(data), call_count_(0) {}
1542*61c4878aSAndroid Build Coastguard Worker 
PrepareRead()1543*61c4878aSAndroid Build Coastguard Worker   Status PrepareRead() final {
1544*61c4878aSAndroid Build Coastguard Worker     if ((call_count_++ % 2) == 0) {
1545*61c4878aSAndroid Build Coastguard Worker       return Status::Unavailable();
1546*61c4878aSAndroid Build Coastguard Worker     }
1547*61c4878aSAndroid Build Coastguard Worker 
1548*61c4878aSAndroid Build Coastguard Worker     set_reader(reader_);
1549*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
1550*61c4878aSAndroid Build Coastguard Worker   }
1551*61c4878aSAndroid Build Coastguard Worker 
1552*61c4878aSAndroid Build Coastguard Worker  private:
1553*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader_;
1554*61c4878aSAndroid Build Coastguard Worker   int call_count_;
1555*61c4878aSAndroid Build Coastguard Worker };
1556*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,PrepareError)1557*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, PrepareError) {
1558*61c4878aSAndroid Build Coastguard Worker   SometimesUnavailableReadHandler unavailable_handler(88, kData);
1559*61c4878aSAndroid Build Coastguard Worker   ctx_.service().RegisterHandler(unavailable_handler);
1560*61c4878aSAndroid Build Coastguard Worker 
1561*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1562*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
1563*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(88)
1564*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(128)
1565*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
1566*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1567*61c4878aSAndroid Build Coastguard Worker 
1568*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1569*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1570*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 88u);
1571*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1572*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::DataLoss());
1573*61c4878aSAndroid Build Coastguard Worker 
1574*61c4878aSAndroid Build Coastguard Worker   // Try starting the transfer again. It should work this time.
1575*61c4878aSAndroid Build Coastguard Worker   // TODO(frolv): This won't work until completion ACKs are supported.
1576*61c4878aSAndroid Build Coastguard Worker   if (false) {
1577*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(
1578*61c4878aSAndroid Build Coastguard Worker         EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
1579*61c4878aSAndroid Build Coastguard Worker                         .set_session_id(88)
1580*61c4878aSAndroid Build Coastguard Worker                         .set_window_end_offset(128)
1581*61c4878aSAndroid Build Coastguard Worker                         .set_offset(0)));
1582*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
1583*61c4878aSAndroid Build Coastguard Worker 
1584*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(ctx_.total_responses(), 2u);
1585*61c4878aSAndroid Build Coastguard Worker     chunk = DecodeChunk(ctx_.responses().back());
1586*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(chunk.session_id(), 88u);
1587*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(chunk.payload().size(), kData.size());
1588*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(std::memcmp(
1589*61c4878aSAndroid Build Coastguard Worker                   chunk.payload().data(), kData.data(), chunk.payload().size()),
1590*61c4878aSAndroid Build Coastguard Worker               0);
1591*61c4878aSAndroid Build Coastguard Worker   }
1592*61c4878aSAndroid Build Coastguard Worker }
1593*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferMaxBytes16,Service_SetMaxPendingBytes)1594*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferMaxBytes16, Service_SetMaxPendingBytes) {
1595*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1596*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart).set_session_id(7)));
1597*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1598*61c4878aSAndroid Build Coastguard Worker 
1599*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
1600*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
1601*61c4878aSAndroid Build Coastguard Worker 
1602*61c4878aSAndroid Build Coastguard Worker   // First parameters chunk has the default window end offset of 16.
1603*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1604*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1605*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1606*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 16u);
1607*61c4878aSAndroid Build Coastguard Worker 
1608*61c4878aSAndroid Build Coastguard Worker   // Update the max window size.
1609*61c4878aSAndroid Build Coastguard Worker   ctx_.service().set_max_window_size_bytes(12);
1610*61c4878aSAndroid Build Coastguard Worker 
1611*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
1612*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
1613*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
1614*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
1615*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
1616*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1617*61c4878aSAndroid Build Coastguard Worker 
1618*61c4878aSAndroid Build Coastguard Worker   // Second parameters chunk should use the new max pending bytes.
1619*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1620*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1621*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 7u);
1622*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 8u);
1623*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 8u + 12u);
1624*61c4878aSAndroid Build Coastguard Worker }
1625*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_SimpleTransfer)1626*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_SimpleTransfer) {
1627*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1628*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1629*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1630*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1631*61c4878aSAndroid Build Coastguard Worker 
1632*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1633*61c4878aSAndroid Build Coastguard Worker 
1634*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1635*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1636*61c4878aSAndroid Build Coastguard Worker 
1637*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
1638*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
1639*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1640*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1641*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1642*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1643*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(chunk.desired_session_id().has_value());
1644*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1645*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1646*61c4878aSAndroid Build Coastguard Worker 
1647*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK and sending the first
1648*61c4878aSAndroid Build Coastguard Worker   // read transfer parameters.
1649*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 2, [this] {
1650*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
1651*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
1652*61c4878aSAndroid Build Coastguard Worker             .set_session_id(kArbitrarySessionId)
1653*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(64)
1654*61c4878aSAndroid Build Coastguard Worker             .set_offset(0)));
1655*61c4878aSAndroid Build Coastguard Worker 
1656*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
1657*61c4878aSAndroid Build Coastguard Worker   });
1658*61c4878aSAndroid Build Coastguard Worker 
1659*61c4878aSAndroid Build Coastguard Worker   // Server should respond by starting the data transfer, sending its sole data
1660*61c4878aSAndroid Build Coastguard Worker   // chunk and a remaining_bytes 0 chunk.
1661*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1662*61c4878aSAndroid Build Coastguard Worker 
1663*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
1664*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
1665*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kData);
1666*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
1667*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 0u);
1668*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.has_payload());
1669*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), kData.size());
1670*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c1.payload().data(), kData.data(), c1.payload().size()),
1671*61c4878aSAndroid Build Coastguard Worker             0);
1672*61c4878aSAndroid Build Coastguard Worker 
1673*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
1674*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.protocol_version(), ProtocolVersion::kVersionTwo);
1675*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.type(), Chunk::Type::kData);
1676*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), kArbitrarySessionId);
1677*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c2.has_payload());
1678*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.remaining_bytes(), 0u);
1679*61c4878aSAndroid Build Coastguard Worker 
1680*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(Chunk::Final(
1681*61c4878aSAndroid Build Coastguard Worker       ProtocolVersion::kVersionTwo, kArbitrarySessionId, OkStatus())));
1682*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1683*61c4878aSAndroid Build Coastguard Worker 
1684*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
1685*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
1686*61c4878aSAndroid Build Coastguard Worker }
1687*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_MultiChunk)1688*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_MultiChunk) {
1689*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1690*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1691*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1692*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1693*61c4878aSAndroid Build Coastguard Worker 
1694*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1695*61c4878aSAndroid Build Coastguard Worker 
1696*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1697*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1698*61c4878aSAndroid Build Coastguard Worker 
1699*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
1700*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
1701*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1702*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1703*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1704*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1705*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1706*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1707*61c4878aSAndroid Build Coastguard Worker 
1708*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK and sending the first
1709*61c4878aSAndroid Build Coastguard Worker   // read transfer parameters.
1710*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 3, [this] {
1711*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
1712*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
1713*61c4878aSAndroid Build Coastguard Worker             .set_session_id(kArbitrarySessionId)
1714*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(64)
1715*61c4878aSAndroid Build Coastguard Worker             .set_max_chunk_size_bytes(16)
1716*61c4878aSAndroid Build Coastguard Worker             .set_offset(0)));
1717*61c4878aSAndroid Build Coastguard Worker 
1718*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
1719*61c4878aSAndroid Build Coastguard Worker   });
1720*61c4878aSAndroid Build Coastguard Worker 
1721*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
1722*61c4878aSAndroid Build Coastguard Worker 
1723*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
1724*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
1725*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kData);
1726*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
1727*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 0u);
1728*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.has_payload());
1729*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 16u);
1730*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c1.payload().data(), kData.data(), c1.payload().size()),
1731*61c4878aSAndroid Build Coastguard Worker             0);
1732*61c4878aSAndroid Build Coastguard Worker 
1733*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
1734*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.protocol_version(), ProtocolVersion::kVersionTwo);
1735*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.type(), Chunk::Type::kData);
1736*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), kArbitrarySessionId);
1737*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.offset(), 16u);
1738*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c2.has_payload());
1739*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c2.payload().size(), 16u);
1740*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
1741*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
1742*61c4878aSAndroid Build Coastguard Worker           c2.payload().data(), kData.data() + c2.offset(), c2.payload().size()),
1743*61c4878aSAndroid Build Coastguard Worker       0);
1744*61c4878aSAndroid Build Coastguard Worker 
1745*61c4878aSAndroid Build Coastguard Worker   Chunk c3 = DecodeChunk(ctx_.responses()[3]);
1746*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.protocol_version(), ProtocolVersion::kVersionTwo);
1747*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.type(), Chunk::Type::kData);
1748*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.session_id(), kArbitrarySessionId);
1749*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c3.has_payload());
1750*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.remaining_bytes(), 0u);
1751*61c4878aSAndroid Build Coastguard Worker 
1752*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(Chunk::Final(
1753*61c4878aSAndroid Build Coastguard Worker       ProtocolVersion::kVersionTwo, kArbitrarySessionId, OkStatus())));
1754*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1755*61c4878aSAndroid Build Coastguard Worker 
1756*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
1757*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
1758*61c4878aSAndroid Build Coastguard Worker }
1759*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_MultiParameters)1760*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_MultiParameters) {
1761*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1762*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1763*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1764*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1765*61c4878aSAndroid Build Coastguard Worker 
1766*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1767*61c4878aSAndroid Build Coastguard Worker 
1768*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1769*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1770*61c4878aSAndroid Build Coastguard Worker 
1771*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
1772*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
1773*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1774*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1775*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1776*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1777*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1778*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1779*61c4878aSAndroid Build Coastguard Worker 
1780*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK and sending the first
1781*61c4878aSAndroid Build Coastguard Worker   // read transfer parameters.
1782*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1783*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
1784*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
1785*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(16)
1786*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)));
1787*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1788*61c4878aSAndroid Build Coastguard Worker 
1789*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1790*61c4878aSAndroid Build Coastguard Worker 
1791*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
1792*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
1793*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kData);
1794*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
1795*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 0u);
1796*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.has_payload());
1797*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 16u);
1798*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c1.payload().data(), kData.data(), c1.payload().size()),
1799*61c4878aSAndroid Build Coastguard Worker             0);
1800*61c4878aSAndroid Build Coastguard Worker 
1801*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 2, [this] {
1802*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
1803*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kParametersContinue)
1804*61c4878aSAndroid Build Coastguard Worker             .set_session_id(kArbitrarySessionId)
1805*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(64)
1806*61c4878aSAndroid Build Coastguard Worker             .set_offset(16)));
1807*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
1808*61c4878aSAndroid Build Coastguard Worker   });
1809*61c4878aSAndroid Build Coastguard Worker 
1810*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
1811*61c4878aSAndroid Build Coastguard Worker 
1812*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
1813*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.protocol_version(), ProtocolVersion::kVersionTwo);
1814*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.type(), Chunk::Type::kData);
1815*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), kArbitrarySessionId);
1816*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.offset(), 16u);
1817*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c2.has_payload());
1818*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c2.payload().size(), 16u);
1819*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
1820*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
1821*61c4878aSAndroid Build Coastguard Worker           c2.payload().data(), kData.data() + c2.offset(), c2.payload().size()),
1822*61c4878aSAndroid Build Coastguard Worker       0);
1823*61c4878aSAndroid Build Coastguard Worker 
1824*61c4878aSAndroid Build Coastguard Worker   Chunk c3 = DecodeChunk(ctx_.responses()[3]);
1825*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.protocol_version(), ProtocolVersion::kVersionTwo);
1826*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.type(), Chunk::Type::kData);
1827*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.session_id(), kArbitrarySessionId);
1828*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(c3.has_payload());
1829*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.remaining_bytes(), 0u);
1830*61c4878aSAndroid Build Coastguard Worker 
1831*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(Chunk::Final(
1832*61c4878aSAndroid Build Coastguard Worker       ProtocolVersion::kVersionTwo, kArbitrarySessionId, OkStatus())));
1833*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1834*61c4878aSAndroid Build Coastguard Worker 
1835*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
1836*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
1837*61c4878aSAndroid Build Coastguard Worker }
1838*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_ClientTerminatesDuringHandshake)1839*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_ClientTerminatesDuringHandshake) {
1840*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1841*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1842*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1843*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1844*61c4878aSAndroid Build Coastguard Worker 
1845*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1846*61c4878aSAndroid Build Coastguard Worker 
1847*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1848*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1849*61c4878aSAndroid Build Coastguard Worker 
1850*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
1851*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
1852*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1853*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1854*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1855*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1856*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1857*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1858*61c4878aSAndroid Build Coastguard Worker 
1859*61c4878aSAndroid Build Coastguard Worker   // Send a terminating chunk instead of the third part of the handshake.
1860*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(Chunk::Final(ProtocolVersion::kVersionTwo,
1861*61c4878aSAndroid Build Coastguard Worker                                                  kArbitrarySessionId,
1862*61c4878aSAndroid Build Coastguard Worker                                                  Status::ResourceExhausted())));
1863*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1864*61c4878aSAndroid Build Coastguard Worker 
1865*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
1866*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, Status::ResourceExhausted());
1867*61c4878aSAndroid Build Coastguard Worker }
1868*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_ClientSendsWrongProtocolVersion)1869*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_ClientSendsWrongProtocolVersion) {
1870*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1871*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1872*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1873*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1874*61c4878aSAndroid Build Coastguard Worker 
1875*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1876*61c4878aSAndroid Build Coastguard Worker 
1877*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1878*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1879*61c4878aSAndroid Build Coastguard Worker 
1880*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
1881*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
1882*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1883*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1884*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1885*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1886*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1887*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1888*61c4878aSAndroid Build Coastguard Worker 
1889*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK and sending the first
1890*61c4878aSAndroid Build Coastguard Worker   // read transfer parameters.
1891*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1892*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
1893*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
1894*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(16)
1895*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)));
1896*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1897*61c4878aSAndroid Build Coastguard Worker 
1898*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1899*61c4878aSAndroid Build Coastguard Worker 
1900*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
1901*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
1902*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kData);
1903*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
1904*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 0u);
1905*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.has_payload());
1906*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(c1.payload().size(), 16u);
1907*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(c1.payload().data(), kData.data(), c1.payload().size()),
1908*61c4878aSAndroid Build Coastguard Worker             0);
1909*61c4878aSAndroid Build Coastguard Worker 
1910*61c4878aSAndroid Build Coastguard Worker   // Send a parameters update, but with the incorrect protocol version. The
1911*61c4878aSAndroid Build Coastguard Worker   // server should terminate the transfer.
1912*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1913*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersContinue)
1914*61c4878aSAndroid Build Coastguard Worker           .set_session_id(3)
1915*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(64)
1916*61c4878aSAndroid Build Coastguard Worker           .set_offset(16)));
1917*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1918*61c4878aSAndroid Build Coastguard Worker 
1919*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
1920*61c4878aSAndroid Build Coastguard Worker 
1921*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
1922*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1923*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
1924*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1925*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
1926*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::Internal());
1927*61c4878aSAndroid Build Coastguard Worker 
1928*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
1929*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, Status::Internal());
1930*61c4878aSAndroid Build Coastguard Worker }
1931*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_BadParametersInHandshake)1932*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_BadParametersInHandshake) {
1933*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1934*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1935*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1936*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
1937*61c4878aSAndroid Build Coastguard Worker 
1938*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1939*61c4878aSAndroid Build Coastguard Worker 
1940*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
1941*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
1942*61c4878aSAndroid Build Coastguard Worker 
1943*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1944*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1945*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1946*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
1947*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1948*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
1949*61c4878aSAndroid Build Coastguard Worker 
1950*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake, but send an invalid parameters chunk. The server
1951*61c4878aSAndroid Build Coastguard Worker   // should terminate the transfer.
1952*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
1953*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
1954*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
1955*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(0)
1956*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)));
1957*61c4878aSAndroid Build Coastguard Worker 
1958*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1959*61c4878aSAndroid Build Coastguard Worker 
1960*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
1961*61c4878aSAndroid Build Coastguard Worker 
1962*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
1963*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
1964*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kCompletion);
1965*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
1966*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.status().has_value());
1967*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.status().value(), Status::ResourceExhausted());
1968*61c4878aSAndroid Build Coastguard Worker }
1969*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_InvalidResourceId)1970*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_InvalidResourceId) {
1971*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1972*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1973*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1974*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(99)));
1975*61c4878aSAndroid Build Coastguard Worker 
1976*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1977*61c4878aSAndroid Build Coastguard Worker 
1978*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1979*61c4878aSAndroid Build Coastguard Worker 
1980*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1981*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
1982*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
1983*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
1984*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::NotFound());
1985*61c4878aSAndroid Build Coastguard Worker }
1986*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_PrepareError)1987*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_PrepareError) {
1988*61c4878aSAndroid Build Coastguard Worker   SometimesUnavailableReadHandler unavailable_handler(99, kData);
1989*61c4878aSAndroid Build Coastguard Worker   ctx_.service().RegisterHandler(unavailable_handler);
1990*61c4878aSAndroid Build Coastguard Worker 
1991*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
1992*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
1993*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
1994*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(99)));
1995*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
1996*61c4878aSAndroid Build Coastguard Worker 
1997*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
1998*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
1999*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2000*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2001*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2002*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 99u);
2003*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::DataLoss());
2004*61c4878aSAndroid Build Coastguard Worker }
2005*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransfer,Version2_HandlerSetsTransferSize)2006*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransfer, Version2_HandlerSetsTransferSize) {
2007*61c4878aSAndroid Build Coastguard Worker   handler_.set_resource_size(kData.size());
2008*61c4878aSAndroid Build Coastguard Worker 
2009*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2010*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2011*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2012*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(3)));
2013*61c4878aSAndroid Build Coastguard Worker 
2014*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2015*61c4878aSAndroid Build Coastguard Worker 
2016*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
2017*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
2018*61c4878aSAndroid Build Coastguard Worker 
2019*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2020*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2021*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2022*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2023*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2024*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2025*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2026*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 3u);
2027*61c4878aSAndroid Build Coastguard Worker 
2028*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK and sending the first
2029*61c4878aSAndroid Build Coastguard Worker   // read transfer parameters.
2030*61c4878aSAndroid Build Coastguard Worker   rpc::test::WaitForPackets(ctx_.output(), 4, [this] {
2031*61c4878aSAndroid Build Coastguard Worker     ctx_.SendClientStream(EncodeChunk(
2032*61c4878aSAndroid Build Coastguard Worker         Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2033*61c4878aSAndroid Build Coastguard Worker             .set_session_id(kArbitrarySessionId)
2034*61c4878aSAndroid Build Coastguard Worker             .set_window_end_offset(64)
2035*61c4878aSAndroid Build Coastguard Worker             .set_max_chunk_size_bytes(8)
2036*61c4878aSAndroid Build Coastguard Worker             .set_offset(0)));
2037*61c4878aSAndroid Build Coastguard Worker 
2038*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
2039*61c4878aSAndroid Build Coastguard Worker   });
2040*61c4878aSAndroid Build Coastguard Worker 
2041*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2042*61c4878aSAndroid Build Coastguard Worker 
2043*61c4878aSAndroid Build Coastguard Worker   // Each of the sent chunks should have a remaining_bytes value set.
2044*61c4878aSAndroid Build Coastguard Worker   Chunk c1 = DecodeChunk(ctx_.responses()[1]);
2045*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.protocol_version(), ProtocolVersion::kVersionTwo);
2046*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.type(), Chunk::Type::kData);
2047*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.session_id(), kArbitrarySessionId);
2048*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.offset(), 0u);
2049*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c1.remaining_bytes().has_value());
2050*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c1.remaining_bytes().value(), 24u);
2051*61c4878aSAndroid Build Coastguard Worker 
2052*61c4878aSAndroid Build Coastguard Worker   Chunk c2 = DecodeChunk(ctx_.responses()[2]);
2053*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.protocol_version(), ProtocolVersion::kVersionTwo);
2054*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.type(), Chunk::Type::kData);
2055*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.session_id(), kArbitrarySessionId);
2056*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.offset(), 8u);
2057*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c2.remaining_bytes().has_value());
2058*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c2.remaining_bytes().value(), 16u);
2059*61c4878aSAndroid Build Coastguard Worker 
2060*61c4878aSAndroid Build Coastguard Worker   Chunk c3 = DecodeChunk(ctx_.responses()[3]);
2061*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.protocol_version(), ProtocolVersion::kVersionTwo);
2062*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.type(), Chunk::Type::kData);
2063*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.session_id(), kArbitrarySessionId);
2064*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.offset(), 16u);
2065*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c3.remaining_bytes().has_value());
2066*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c3.remaining_bytes().value(), 8u);
2067*61c4878aSAndroid Build Coastguard Worker 
2068*61c4878aSAndroid Build Coastguard Worker   Chunk c4 = DecodeChunk(ctx_.responses()[4]);
2069*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.protocol_version(), ProtocolVersion::kVersionTwo);
2070*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.type(), Chunk::Type::kData);
2071*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.session_id(), kArbitrarySessionId);
2072*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.offset(), 24u);
2073*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(c4.remaining_bytes().has_value());
2074*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(c4.remaining_bytes().value(), 0u);
2075*61c4878aSAndroid Build Coastguard Worker 
2076*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(Chunk::Final(
2077*61c4878aSAndroid Build Coastguard Worker       ProtocolVersion::kVersionTwo, kArbitrarySessionId, OkStatus())));
2078*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2079*61c4878aSAndroid Build Coastguard Worker 
2080*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_read_called);
2081*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_read_status, OkStatus());
2082*61c4878aSAndroid Build Coastguard Worker }
2083*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_SimpleTransfer)2084*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_SimpleTransfer) {
2085*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2086*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2087*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2088*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2089*61c4878aSAndroid Build Coastguard Worker 
2090*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2091*61c4878aSAndroid Build Coastguard Worker 
2092*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2093*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2094*61c4878aSAndroid Build Coastguard Worker 
2095*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2096*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2097*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2098*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2099*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2100*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2101*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2102*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2103*61c4878aSAndroid Build Coastguard Worker 
2104*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2105*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2106*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2107*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2108*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2109*61c4878aSAndroid Build Coastguard Worker 
2110*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2111*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2112*61c4878aSAndroid Build Coastguard Worker 
2113*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2114*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2115*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2116*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2117*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2118*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2119*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2120*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
2121*61c4878aSAndroid Build Coastguard Worker 
2122*61c4878aSAndroid Build Coastguard Worker   // Send all of our data.
2123*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2124*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2125*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2126*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
2127*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
2128*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2129*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2130*61c4878aSAndroid Build Coastguard Worker 
2131*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2132*61c4878aSAndroid Build Coastguard Worker 
2133*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2134*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2135*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2136*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2137*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
2138*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
2139*61c4878aSAndroid Build Coastguard Worker 
2140*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2141*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2142*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2143*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2144*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2145*61c4878aSAndroid Build Coastguard Worker 
2146*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2147*61c4878aSAndroid Build Coastguard Worker 
2148*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2149*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
2150*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
2151*61c4878aSAndroid Build Coastguard Worker }
2152*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_Multichunk)2153*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_Multichunk) {
2154*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2155*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2156*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2157*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2158*61c4878aSAndroid Build Coastguard Worker 
2159*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2160*61c4878aSAndroid Build Coastguard Worker 
2161*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2162*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2163*61c4878aSAndroid Build Coastguard Worker 
2164*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2165*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2166*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2167*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2168*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2169*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2170*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2171*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2172*61c4878aSAndroid Build Coastguard Worker 
2173*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2174*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2175*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2176*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2177*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2178*61c4878aSAndroid Build Coastguard Worker 
2179*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2180*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2181*61c4878aSAndroid Build Coastguard Worker 
2182*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2183*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2184*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2185*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2186*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2187*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2188*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2189*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
2190*61c4878aSAndroid Build Coastguard Worker 
2191*61c4878aSAndroid Build Coastguard Worker   // Send all of our data across two chunks.
2192*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2193*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2194*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2195*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
2196*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
2197*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2198*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2199*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2200*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
2201*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8))
2202*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2203*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2204*61c4878aSAndroid Build Coastguard Worker 
2205*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2206*61c4878aSAndroid Build Coastguard Worker 
2207*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2208*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2209*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2210*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2211*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
2212*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
2213*61c4878aSAndroid Build Coastguard Worker 
2214*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2215*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2216*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2217*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2218*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2219*61c4878aSAndroid Build Coastguard Worker 
2220*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2221*61c4878aSAndroid Build Coastguard Worker 
2222*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2223*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
2224*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
2225*61c4878aSAndroid Build Coastguard Worker }
2226*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_ContinueParameters)2227*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_ContinueParameters) {
2228*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2229*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2230*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2231*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2232*61c4878aSAndroid Build Coastguard Worker 
2233*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2234*61c4878aSAndroid Build Coastguard Worker 
2235*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2236*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2237*61c4878aSAndroid Build Coastguard Worker 
2238*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2239*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2240*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2241*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2242*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2243*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2244*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2245*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2246*61c4878aSAndroid Build Coastguard Worker 
2247*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2248*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2249*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2250*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2251*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2252*61c4878aSAndroid Build Coastguard Worker 
2253*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2254*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2255*61c4878aSAndroid Build Coastguard Worker 
2256*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2257*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2258*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2259*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2260*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2261*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2262*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2263*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
2264*61c4878aSAndroid Build Coastguard Worker 
2265*61c4878aSAndroid Build Coastguard Worker   // Send all of our data across several chunks.
2266*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2267*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2268*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2269*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
2270*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(8))));
2271*61c4878aSAndroid Build Coastguard Worker 
2272*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2273*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2274*61c4878aSAndroid Build Coastguard Worker 
2275*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2276*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2277*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2278*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
2279*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8, 8))));
2280*61c4878aSAndroid Build Coastguard Worker 
2281*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2282*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2283*61c4878aSAndroid Build Coastguard Worker 
2284*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2285*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2286*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2287*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2288*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
2289*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2290*61c4878aSAndroid Build Coastguard Worker 
2291*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2292*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2293*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2294*61c4878aSAndroid Build Coastguard Worker                       .set_offset(16)
2295*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(16, 8))));
2296*61c4878aSAndroid Build Coastguard Worker 
2297*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2298*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
2299*61c4878aSAndroid Build Coastguard Worker 
2300*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2301*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2302*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2303*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2304*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 24u);
2305*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2306*61c4878aSAndroid Build Coastguard Worker 
2307*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2308*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2309*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2310*61c4878aSAndroid Build Coastguard Worker                       .set_offset(24)
2311*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(24))
2312*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2313*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2314*61c4878aSAndroid Build Coastguard Worker 
2315*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2316*61c4878aSAndroid Build Coastguard Worker 
2317*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2318*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2319*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2320*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2321*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
2322*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
2323*61c4878aSAndroid Build Coastguard Worker 
2324*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2325*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2326*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2327*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2328*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2329*61c4878aSAndroid Build Coastguard Worker 
2330*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2331*61c4878aSAndroid Build Coastguard Worker 
2332*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2333*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
2334*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
2335*61c4878aSAndroid Build Coastguard Worker }
2336*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_ClientTerminatesDuringHandshake)2337*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_ClientTerminatesDuringHandshake) {
2338*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2339*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2340*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2341*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2342*61c4878aSAndroid Build Coastguard Worker 
2343*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2344*61c4878aSAndroid Build Coastguard Worker 
2345*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2346*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2347*61c4878aSAndroid Build Coastguard Worker 
2348*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2349*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2350*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2351*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2352*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2353*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2354*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2355*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2356*61c4878aSAndroid Build Coastguard Worker 
2357*61c4878aSAndroid Build Coastguard Worker   // Send an error chunk instead of completing the handshake.
2358*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2359*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk::Final(ProtocolVersion::kVersionTwo,
2360*61c4878aSAndroid Build Coastguard Worker                                kArbitrarySessionId,
2361*61c4878aSAndroid Build Coastguard Worker                                Status::FailedPrecondition())));
2362*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2363*61c4878aSAndroid Build Coastguard Worker 
2364*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2365*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, Status::FailedPrecondition());
2366*61c4878aSAndroid Build Coastguard Worker }
2367*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_ClientSendsWrongProtocolVersion)2368*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_ClientSendsWrongProtocolVersion) {
2369*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2370*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2371*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2372*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2373*61c4878aSAndroid Build Coastguard Worker 
2374*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2375*61c4878aSAndroid Build Coastguard Worker 
2376*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2377*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2378*61c4878aSAndroid Build Coastguard Worker 
2379*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2380*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2381*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2382*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2383*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2384*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2385*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2386*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2387*61c4878aSAndroid Build Coastguard Worker 
2388*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2389*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2390*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2391*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2392*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2393*61c4878aSAndroid Build Coastguard Worker 
2394*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2395*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2396*61c4878aSAndroid Build Coastguard Worker 
2397*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2398*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2399*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2400*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2401*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2402*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), 32u);
2403*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2404*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), 37u);
2405*61c4878aSAndroid Build Coastguard Worker 
2406*61c4878aSAndroid Build Coastguard Worker   // The transfer was configured to use protocol version 2. Send a legacy chunk
2407*61c4878aSAndroid Build Coastguard Worker   // instead.
2408*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2409*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kData)
2410*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(7)
2411*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
2412*61c4878aSAndroid Build Coastguard Worker                       .set_payload(kData)
2413*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2414*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2415*61c4878aSAndroid Build Coastguard Worker 
2416*61c4878aSAndroid Build Coastguard Worker   // Server should terminate the transfer.
2417*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2418*61c4878aSAndroid Build Coastguard Worker 
2419*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[2]);
2420*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2421*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2422*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::Internal());
2423*61c4878aSAndroid Build Coastguard Worker 
2424*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2425*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2426*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2427*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2428*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2429*61c4878aSAndroid Build Coastguard Worker 
2430*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2431*61c4878aSAndroid Build Coastguard Worker }
2432*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_InvalidResourceId)2433*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_InvalidResourceId) {
2434*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2435*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2436*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2437*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(99)));
2438*61c4878aSAndroid Build Coastguard Worker 
2439*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2440*61c4878aSAndroid Build Coastguard Worker 
2441*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2442*61c4878aSAndroid Build Coastguard Worker 
2443*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2444*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2445*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2446*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(chunk.resource_id().has_value());
2447*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2448*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::NotFound());
2449*61c4878aSAndroid Build Coastguard Worker }
2450*61c4878aSAndroid Build Coastguard Worker 
2451*61c4878aSAndroid Build Coastguard Worker class ReadTransferLowMaxRetries : public ::testing::Test {
2452*61c4878aSAndroid Build Coastguard Worker  protected:
2453*61c4878aSAndroid Build Coastguard Worker   static constexpr uint32_t kMaxRetries = 3;
2454*61c4878aSAndroid Build Coastguard Worker   static constexpr uint32_t kMaxLifetimeRetries = 4;
2455*61c4878aSAndroid Build Coastguard Worker 
ReadTransferLowMaxRetries()2456*61c4878aSAndroid Build Coastguard Worker   ReadTransferLowMaxRetries()
2457*61c4878aSAndroid Build Coastguard Worker       : handler_(9, kData),
2458*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(data_buffer_, encode_buffer_),
2459*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
2460*61c4878aSAndroid Build Coastguard Worker              64,
2461*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
2462*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1),
2463*61c4878aSAndroid Build Coastguard Worker              kMaxRetries,
2464*61c4878aSAndroid Build Coastguard Worker              cfg::kDefaultExtendWindowDivisor,
2465*61c4878aSAndroid Build Coastguard Worker              kMaxLifetimeRetries),
2466*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_) {
2467*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
2468*61c4878aSAndroid Build Coastguard Worker 
2469*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_read_called);
2470*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_read_called);
2471*61c4878aSAndroid Build Coastguard Worker 
2472*61c4878aSAndroid Build Coastguard Worker     ctx_.call();  // Open the read stream
2473*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
2474*61c4878aSAndroid Build Coastguard Worker   }
2475*61c4878aSAndroid Build Coastguard Worker 
~ReadTransferLowMaxRetries()2476*61c4878aSAndroid Build Coastguard Worker   ~ReadTransferLowMaxRetries() override {
2477*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
2478*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
2479*61c4878aSAndroid Build Coastguard Worker   }
2480*61c4878aSAndroid Build Coastguard Worker 
2481*61c4878aSAndroid Build Coastguard Worker   SimpleReadTransfer handler_;
2482*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
2483*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, Read, 10) ctx_;
2484*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
2485*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> data_buffer_;
2486*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> encode_buffer_;
2487*61c4878aSAndroid Build Coastguard Worker };
2488*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransferLowMaxRetries,FailsAfterLifetimeRetryCount)2489*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransferLowMaxRetries, FailsAfterLifetimeRetryCount) {
2490*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2491*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kLegacy, Chunk::Type::kStart)
2492*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(9)
2493*61c4878aSAndroid Build Coastguard Worker                       .set_window_end_offset(16)
2494*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)));
2495*61c4878aSAndroid Build Coastguard Worker 
2496*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2497*61c4878aSAndroid Build Coastguard Worker 
2498*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
2499*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
2500*61c4878aSAndroid Build Coastguard Worker 
2501*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2502*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2503*61c4878aSAndroid Build Coastguard Worker 
2504*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 9u);
2505*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2506*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(chunk.payload().size(), 16u);
2507*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2508*61c4878aSAndroid Build Coastguard Worker       std::memcmp(chunk.payload().data(), kData.data(), chunk.payload().size()),
2509*61c4878aSAndroid Build Coastguard Worker       0);
2510*61c4878aSAndroid Build Coastguard Worker 
2511*61c4878aSAndroid Build Coastguard Worker   // Time out twice. Server should retry both times.
2512*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(9);
2513*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(9);
2514*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2515*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2516*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 9u);
2517*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2518*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(chunk.payload().size(), 16u);
2519*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2520*61c4878aSAndroid Build Coastguard Worker       std::memcmp(chunk.payload().data(), kData.data(), chunk.payload().size()),
2521*61c4878aSAndroid Build Coastguard Worker       0);
2522*61c4878aSAndroid Build Coastguard Worker 
2523*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2524*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kLegacy, Chunk::Type::kParametersContinue)
2525*61c4878aSAndroid Build Coastguard Worker           .set_session_id(9)
2526*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(32)
2527*61c4878aSAndroid Build Coastguard Worker           .set_offset(16)));
2528*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2529*61c4878aSAndroid Build Coastguard Worker 
2530*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
2531*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2532*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 9u);
2533*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
2534*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(chunk.payload().size(), 16u);
2535*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2536*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
2537*61c4878aSAndroid Build Coastguard Worker           chunk.payload().data(), kData.data() + 16, chunk.payload().size()),
2538*61c4878aSAndroid Build Coastguard Worker       0);
2539*61c4878aSAndroid Build Coastguard Worker 
2540*61c4878aSAndroid Build Coastguard Worker   // Time out three more times. The transfer should terminate.
2541*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(9);
2542*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2543*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2544*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 9u);
2545*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
2546*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(chunk.payload().size(), 16u);
2547*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2548*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
2549*61c4878aSAndroid Build Coastguard Worker           chunk.payload().data(), kData.data() + 16, chunk.payload().size()),
2550*61c4878aSAndroid Build Coastguard Worker       0);
2551*61c4878aSAndroid Build Coastguard Worker 
2552*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(9);
2553*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 6u);
2554*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2555*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), 9u);
2556*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
2557*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(chunk.payload().size(), 16u);
2558*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(
2559*61c4878aSAndroid Build Coastguard Worker       std::memcmp(
2560*61c4878aSAndroid Build Coastguard Worker           chunk.payload().data(), kData.data() + 16, chunk.payload().size()),
2561*61c4878aSAndroid Build Coastguard Worker       0);
2562*61c4878aSAndroid Build Coastguard Worker 
2563*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(9);
2564*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 7u);
2565*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2566*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status(), Status::DeadlineExceeded());
2567*61c4878aSAndroid Build Coastguard Worker }
2568*61c4878aSAndroid Build Coastguard Worker 
TEST_F(ReadTransferLowMaxRetries,Version2_FailsAfterLifetimeRetryCount)2569*61c4878aSAndroid Build Coastguard Worker TEST_F(ReadTransferLowMaxRetries, Version2_FailsAfterLifetimeRetryCount) {
2570*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2571*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2572*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2573*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(9)));
2574*61c4878aSAndroid Build Coastguard Worker 
2575*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2576*61c4878aSAndroid Build Coastguard Worker 
2577*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_read_called);
2578*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_read_called);
2579*61c4878aSAndroid Build Coastguard Worker 
2580*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2581*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2582*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2583*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2584*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2585*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2586*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2587*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 9u);
2588*61c4878aSAndroid Build Coastguard Worker 
2589*61c4878aSAndroid Build Coastguard Worker   // Time out twice. Server should retry both times.
2590*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2591*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2592*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2593*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2594*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2595*61c4878aSAndroid Build Coastguard Worker 
2596*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake, allowing the transfer to continue.
2597*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2598*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2599*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
2600*61c4878aSAndroid Build Coastguard Worker           .set_window_end_offset(16)
2601*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)));
2602*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2603*61c4878aSAndroid Build Coastguard Worker 
2604*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
2605*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2606*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kData);
2607*61c4878aSAndroid Build Coastguard Worker 
2608*61c4878aSAndroid Build Coastguard Worker   // Time out three more times. The transfer should terminate.
2609*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2610*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2611*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2612*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kData);
2613*61c4878aSAndroid Build Coastguard Worker 
2614*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2615*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 6u);
2616*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2617*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kData);
2618*61c4878aSAndroid Build Coastguard Worker 
2619*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2620*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 7u);
2621*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2622*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2623*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status(), Status::DeadlineExceeded());
2624*61c4878aSAndroid Build Coastguard Worker }
2625*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_ClientRetriesOpeningChunk)2626*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_ClientRetriesOpeningChunk) {
2627*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2628*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2629*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2630*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2631*61c4878aSAndroid Build Coastguard Worker 
2632*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2633*61c4878aSAndroid Build Coastguard Worker 
2634*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2635*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2636*61c4878aSAndroid Build Coastguard Worker 
2637*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2638*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2639*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2640*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2641*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2642*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2643*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2644*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2645*61c4878aSAndroid Build Coastguard Worker 
2646*61c4878aSAndroid Build Coastguard Worker   // Reset prepare_write_called to ensure it isn't called again.
2647*61c4878aSAndroid Build Coastguard Worker   handler_.prepare_write_called = false;
2648*61c4878aSAndroid Build Coastguard Worker 
2649*61c4878aSAndroid Build Coastguard Worker   // Client re-sends the same chunk instead of finishing the handshake.
2650*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2651*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2652*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2653*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2654*61c4878aSAndroid Build Coastguard Worker 
2655*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2656*61c4878aSAndroid Build Coastguard Worker 
2657*61c4878aSAndroid Build Coastguard Worker   // The server should re-send the same START_ACK without reinitializing the
2658*61c4878aSAndroid Build Coastguard Worker   // handler.
2659*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2660*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2661*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2662*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2663*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2664*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2665*61c4878aSAndroid Build Coastguard Worker 
2666*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.prepare_write_called);
2667*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2668*61c4878aSAndroid Build Coastguard Worker }
2669*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransfer,Version2_RegularSessionIdInStartChunk)2670*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransfer, Version2_RegularSessionIdInStartChunk) {
2671*61c4878aSAndroid Build Coastguard Worker   // Client incorrectly sets session_id instead of desired_session_id in its
2672*61c4878aSAndroid Build Coastguard Worker   // START chunk. Server should immediately respond with a protocol error.
2673*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2674*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2675*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2676*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(99)));
2677*61c4878aSAndroid Build Coastguard Worker 
2678*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2679*61c4878aSAndroid Build Coastguard Worker 
2680*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.prepare_write_called);
2681*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2682*61c4878aSAndroid Build Coastguard Worker 
2683*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2684*61c4878aSAndroid Build Coastguard Worker 
2685*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2686*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2687*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2688*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(chunk.resource_id().has_value());
2689*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2690*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), Status::DataLoss());
2691*61c4878aSAndroid Build Coastguard Worker }
2692*61c4878aSAndroid Build Coastguard Worker 
__anonbff93a0d0d02(size_t i) 2693*61c4878aSAndroid Build Coastguard Worker constexpr auto kData128 = bytes::Initialized<128>([](size_t i) { return i; });
2694*61c4878aSAndroid Build Coastguard Worker 
2695*61c4878aSAndroid Build Coastguard Worker class WriteTransferLargeData : public ::testing::Test {
2696*61c4878aSAndroid Build Coastguard Worker  protected:
WriteTransferLargeData()2697*61c4878aSAndroid Build Coastguard Worker   WriteTransferLargeData()
2698*61c4878aSAndroid Build Coastguard Worker       : buffer{},
2699*61c4878aSAndroid Build Coastguard Worker         handler_(7, buffer),
2700*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(chunk_buffer_, encode_buffer_),
2701*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_),
2702*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
2703*61c4878aSAndroid Build Coastguard Worker              kData128.size(),
2704*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
2705*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1),
2706*61c4878aSAndroid Build Coastguard Worker              /*max_retries=*/3) {
2707*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
2708*61c4878aSAndroid Build Coastguard Worker 
2709*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_write_called);
2710*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_write_called);
2711*61c4878aSAndroid Build Coastguard Worker 
2712*61c4878aSAndroid Build Coastguard Worker     ctx_.call();  // Open the write stream
2713*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
2714*61c4878aSAndroid Build Coastguard Worker   }
2715*61c4878aSAndroid Build Coastguard Worker 
~WriteTransferLargeData()2716*61c4878aSAndroid Build Coastguard Worker   ~WriteTransferLargeData() override {
2717*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
2718*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
2719*61c4878aSAndroid Build Coastguard Worker   }
2720*61c4878aSAndroid Build Coastguard Worker 
2721*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kData128.size()> buffer;
2722*61c4878aSAndroid Build Coastguard Worker   SimpleWriteTransfer handler_;
2723*61c4878aSAndroid Build Coastguard Worker 
2724*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
2725*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
2726*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 48> chunk_buffer_;
2727*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> encode_buffer_;
2728*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write, 10) ctx_;
2729*61c4878aSAndroid Build Coastguard Worker };
2730*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferLargeData,Version2_AdaptiveWindow_SlowStart)2731*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferLargeData, Version2_AdaptiveWindow_SlowStart) {
2732*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2733*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2734*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2735*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2736*61c4878aSAndroid Build Coastguard Worker 
2737*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2738*61c4878aSAndroid Build Coastguard Worker 
2739*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2740*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2741*61c4878aSAndroid Build Coastguard Worker 
2742*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2743*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2744*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2745*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2746*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2747*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2748*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2749*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2750*61c4878aSAndroid Build Coastguard Worker 
2751*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2752*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2753*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2754*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2755*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2756*61c4878aSAndroid Build Coastguard Worker 
2757*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2758*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2759*61c4878aSAndroid Build Coastguard Worker 
2760*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kExpectedMaxChunkSize = 21;
2761*61c4878aSAndroid Build Coastguard Worker 
2762*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2763*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2764*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2765*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2766*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2767*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), kExpectedMaxChunkSize);
2768*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2769*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), kExpectedMaxChunkSize);
2770*61c4878aSAndroid Build Coastguard Worker 
2771*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(EncodeChunk(
2772*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2773*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
2774*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)
2775*61c4878aSAndroid Build Coastguard Worker           .set_payload(span(kData128).first(kExpectedMaxChunkSize))));
2776*61c4878aSAndroid Build Coastguard Worker 
2777*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2778*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2779*61c4878aSAndroid Build Coastguard Worker 
2780*61c4878aSAndroid Build Coastguard Worker   // Window doubles in response to successful receive.
2781*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2782*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2783*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2784*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2785*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), kExpectedMaxChunkSize);
2786*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2787*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 2 * kExpectedMaxChunkSize);
2788*61c4878aSAndroid Build Coastguard Worker 
2789*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2790*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2791*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2792*61c4878aSAndroid Build Coastguard Worker                       .set_offset(chunk.offset())
2793*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData128).subspan(
2794*61c4878aSAndroid Build Coastguard Worker                           chunk.offset(), kExpectedMaxChunkSize))));
2795*61c4878aSAndroid Build Coastguard Worker 
2796*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2797*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
2798*61c4878aSAndroid Build Coastguard Worker 
2799*61c4878aSAndroid Build Coastguard Worker   // Window doubles in response to successful receive.
2800*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2801*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2802*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2803*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2804*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 2 * kExpectedMaxChunkSize);
2805*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2806*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 4 * kExpectedMaxChunkSize);
2807*61c4878aSAndroid Build Coastguard Worker 
2808*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2809*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2810*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2811*61c4878aSAndroid Build Coastguard Worker                       .set_offset(2 * kExpectedMaxChunkSize)
2812*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData128).subspan(
2813*61c4878aSAndroid Build Coastguard Worker                           chunk.offset(), kExpectedMaxChunkSize))
2814*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2815*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2816*61c4878aSAndroid Build Coastguard Worker 
2817*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2818*61c4878aSAndroid Build Coastguard Worker 
2819*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2820*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2821*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2822*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2823*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
2824*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
2825*61c4878aSAndroid Build Coastguard Worker 
2826*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2827*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2828*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2829*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2830*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2831*61c4878aSAndroid Build Coastguard Worker 
2832*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2833*61c4878aSAndroid Build Coastguard Worker 
2834*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2835*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
2836*61c4878aSAndroid Build Coastguard Worker }
2837*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferLargeData,Version2_AdaptiveWindow_CongestionAvoidance)2838*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferLargeData, Version2_AdaptiveWindow_CongestionAvoidance) {
2839*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2840*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2841*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2842*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2843*61c4878aSAndroid Build Coastguard Worker 
2844*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2845*61c4878aSAndroid Build Coastguard Worker 
2846*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2847*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2848*61c4878aSAndroid Build Coastguard Worker 
2849*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2850*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2851*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2852*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2853*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2854*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2855*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2856*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2857*61c4878aSAndroid Build Coastguard Worker 
2858*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
2859*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2860*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
2861*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2862*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2863*61c4878aSAndroid Build Coastguard Worker 
2864*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
2865*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
2866*61c4878aSAndroid Build Coastguard Worker 
2867*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kExpectedMaxChunkSize = 21;
2868*61c4878aSAndroid Build Coastguard Worker 
2869*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
2870*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2871*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2872*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2873*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
2874*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), kExpectedMaxChunkSize);
2875*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
2876*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), kExpectedMaxChunkSize);
2877*61c4878aSAndroid Build Coastguard Worker 
2878*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(EncodeChunk(
2879*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2880*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)
2881*61c4878aSAndroid Build Coastguard Worker           .set_offset(0)
2882*61c4878aSAndroid Build Coastguard Worker           .set_payload(span(kData128).first(kExpectedMaxChunkSize))));
2883*61c4878aSAndroid Build Coastguard Worker 
2884*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2885*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
2886*61c4878aSAndroid Build Coastguard Worker 
2887*61c4878aSAndroid Build Coastguard Worker   // Window doubles in response to successful receive.
2888*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2889*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2890*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2891*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2892*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), kExpectedMaxChunkSize);
2893*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2894*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 2 * kExpectedMaxChunkSize);
2895*61c4878aSAndroid Build Coastguard Worker 
2896*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2897*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2898*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2899*61c4878aSAndroid Build Coastguard Worker                       .set_offset(chunk.offset())
2900*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData128).subspan(
2901*61c4878aSAndroid Build Coastguard Worker                           chunk.offset(), kExpectedMaxChunkSize))));
2902*61c4878aSAndroid Build Coastguard Worker 
2903*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2904*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
2905*61c4878aSAndroid Build Coastguard Worker 
2906*61c4878aSAndroid Build Coastguard Worker   // Window doubles in response to successful receive.
2907*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2908*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2909*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2910*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2911*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 2 * kExpectedMaxChunkSize);
2912*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2913*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 4 * kExpectedMaxChunkSize);
2914*61c4878aSAndroid Build Coastguard Worker 
2915*61c4878aSAndroid Build Coastguard Worker   // Don't send any data in response.
2916*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
2917*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
2918*61c4878aSAndroid Build Coastguard Worker 
2919*61c4878aSAndroid Build Coastguard Worker   // Window size should now half from the previous one.
2920*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2921*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2922*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
2923*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2924*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 2 * kExpectedMaxChunkSize);
2925*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2926*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 2 * kExpectedMaxChunkSize);
2927*61c4878aSAndroid Build Coastguard Worker 
2928*61c4878aSAndroid Build Coastguard Worker   // Send the appropriate chunk.
2929*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2930*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2931*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2932*61c4878aSAndroid Build Coastguard Worker                       .set_offset(2 * kExpectedMaxChunkSize)
2933*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData128).subspan(
2934*61c4878aSAndroid Build Coastguard Worker                           chunk.offset(), kExpectedMaxChunkSize))));
2935*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2936*61c4878aSAndroid Build Coastguard Worker 
2937*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 6u);
2938*61c4878aSAndroid Build Coastguard Worker 
2939*61c4878aSAndroid Build Coastguard Worker   // Window size should now only increase by one chunk instead of doubling.
2940*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2941*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2942*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
2943*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2944*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 3 * kExpectedMaxChunkSize);
2945*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
2946*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 3 * kExpectedMaxChunkSize);
2947*61c4878aSAndroid Build Coastguard Worker 
2948*61c4878aSAndroid Build Coastguard Worker   // Complete the transfer.
2949*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
2950*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
2951*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
2952*61c4878aSAndroid Build Coastguard Worker                       .set_offset(3 * kExpectedMaxChunkSize)
2953*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData128).subspan(
2954*61c4878aSAndroid Build Coastguard Worker                           chunk.offset(), kExpectedMaxChunkSize))
2955*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
2956*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2957*61c4878aSAndroid Build Coastguard Worker 
2958*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 7u);
2959*61c4878aSAndroid Build Coastguard Worker 
2960*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
2961*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2962*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kCompletion);
2963*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2964*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
2965*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
2966*61c4878aSAndroid Build Coastguard Worker 
2967*61c4878aSAndroid Build Coastguard Worker   // Send the completion acknowledgement.
2968*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
2969*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
2970*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
2971*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2972*61c4878aSAndroid Build Coastguard Worker 
2973*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 7u);
2974*61c4878aSAndroid Build Coastguard Worker 
2975*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
2976*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
2977*61c4878aSAndroid Build Coastguard Worker }
2978*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferLargeData,Version2_ResendPreviousData_ReceivesContinueParameters)2979*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferLargeData,
2980*61c4878aSAndroid Build Coastguard Worker        Version2_ResendPreviousData_ReceivesContinueParameters) {
2981*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
2982*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
2983*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
2984*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
2985*61c4878aSAndroid Build Coastguard Worker 
2986*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
2987*61c4878aSAndroid Build Coastguard Worker 
2988*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
2989*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
2990*61c4878aSAndroid Build Coastguard Worker 
2991*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
2992*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
2993*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
2994*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
2995*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
2996*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
2997*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
2998*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
2999*61c4878aSAndroid Build Coastguard Worker 
3000*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
3001*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
3002*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
3003*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
3004*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3005*61c4878aSAndroid Build Coastguard Worker 
3006*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
3007*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
3008*61c4878aSAndroid Build Coastguard Worker 
3009*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kExpectedMaxChunkSizeBytes = 21u;
3010*61c4878aSAndroid Build Coastguard Worker 
3011*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
3012*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
3013*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
3014*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3015*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
3016*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), kExpectedMaxChunkSizeBytes);
3017*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
3018*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), kExpectedMaxChunkSizeBytes);
3019*61c4878aSAndroid Build Coastguard Worker 
3020*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
3021*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
3022*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
3023*61c4878aSAndroid Build Coastguard Worker                       .set_offset(0)
3024*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).first(16))));
3025*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3026*61c4878aSAndroid Build Coastguard Worker 
3027*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
3028*61c4878aSAndroid Build Coastguard Worker 
3029*61c4878aSAndroid Build Coastguard Worker   // Window size grows to 2 chunks on successful receipt.
3030*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
3031*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
3032*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
3033*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3034*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
3035*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
3036*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + 2 * kExpectedMaxChunkSizeBytes);
3037*61c4878aSAndroid Build Coastguard Worker 
3038*61c4878aSAndroid Build Coastguard Worker   // Resend data that has already been received.
3039*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
3040*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
3041*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
3042*61c4878aSAndroid Build Coastguard Worker                       .set_offset(8)
3043*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(8, 8))
3044*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
3045*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3046*61c4878aSAndroid Build Coastguard Worker 
3047*61c4878aSAndroid Build Coastguard Worker   // The server should respond with CONTINUE parameters rather than requesting
3048*61c4878aSAndroid Build Coastguard Worker   // retransmission and starting a recovery cycle. However, the window size
3049*61c4878aSAndroid Build Coastguard Worker   // should shrink in response to the retried data.
3050*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 4u);
3051*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
3052*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersContinue);
3053*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3054*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 16u);
3055*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(),
3056*61c4878aSAndroid Build Coastguard Worker             chunk.offset() + kExpectedMaxChunkSizeBytes);
3057*61c4878aSAndroid Build Coastguard Worker 
3058*61c4878aSAndroid Build Coastguard Worker   // Send the expected chunk.
3059*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(
3060*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kData)
3061*61c4878aSAndroid Build Coastguard Worker                       .set_session_id(kArbitrarySessionId)
3062*61c4878aSAndroid Build Coastguard Worker                       .set_offset(16)
3063*61c4878aSAndroid Build Coastguard Worker                       .set_payload(span(kData).subspan(16))
3064*61c4878aSAndroid Build Coastguard Worker                       .set_remaining_bytes(0)));
3065*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3066*61c4878aSAndroid Build Coastguard Worker 
3067*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
3068*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
3069*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3070*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.status().has_value());
3071*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.status().value(), OkStatus());
3072*61c4878aSAndroid Build Coastguard Worker 
3073*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.finalize_write_called);
3074*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(handler_.finalize_write_status, OkStatus());
3075*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(std::memcmp(buffer.data(), kData.data(), kData.size()), 0);
3076*61c4878aSAndroid Build Coastguard Worker 
3077*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream<64>(EncodeChunk(
3078*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kCompletionAck)
3079*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
3080*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3081*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 5u);
3082*61c4878aSAndroid Build Coastguard Worker }
3083*61c4878aSAndroid Build Coastguard Worker 
3084*61c4878aSAndroid Build Coastguard Worker class WriteTransferMultibyteVarintChunkSize : public ::testing::Test {
3085*61c4878aSAndroid Build Coastguard Worker  protected:
WriteTransferMultibyteVarintChunkSize()3086*61c4878aSAndroid Build Coastguard Worker   WriteTransferMultibyteVarintChunkSize()
3087*61c4878aSAndroid Build Coastguard Worker       : buffer{},
3088*61c4878aSAndroid Build Coastguard Worker         handler_(7, buffer),
3089*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(chunk_buffer_, encode_buffer_),
3090*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_),
3091*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
3092*61c4878aSAndroid Build Coastguard Worker              kData256.size(),
3093*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
3094*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1),
3095*61c4878aSAndroid Build Coastguard Worker              /*max_retries=*/3) {
3096*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
3097*61c4878aSAndroid Build Coastguard Worker 
3098*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_write_called);
3099*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_write_called);
3100*61c4878aSAndroid Build Coastguard Worker 
3101*61c4878aSAndroid Build Coastguard Worker     ctx_.call();  // Open the write stream
3102*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.WaitUntilEventIsProcessed();
3103*61c4878aSAndroid Build Coastguard Worker   }
3104*61c4878aSAndroid Build Coastguard Worker 
~WriteTransferMultibyteVarintChunkSize()3105*61c4878aSAndroid Build Coastguard Worker   ~WriteTransferMultibyteVarintChunkSize() override {
3106*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
3107*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
3108*61c4878aSAndroid Build Coastguard Worker   }
3109*61c4878aSAndroid Build Coastguard Worker 
3110*61c4878aSAndroid Build Coastguard Worker   static constexpr auto kData256 =
__anonbff93a0d0e02(size_t i) 3111*61c4878aSAndroid Build Coastguard Worker       bytes::Initialized<256>([](size_t i) { return i; });
3112*61c4878aSAndroid Build Coastguard Worker 
3113*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kData256.size()> buffer;
3114*61c4878aSAndroid Build Coastguard Worker   SimpleWriteTransfer handler_;
3115*61c4878aSAndroid Build Coastguard Worker 
3116*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
3117*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
3118*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kData256.size()> chunk_buffer_;
3119*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, kData256.size()> encode_buffer_;
3120*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, Write, 10) ctx_;
3121*61c4878aSAndroid Build Coastguard Worker };
3122*61c4878aSAndroid Build Coastguard Worker 
TEST_F(WriteTransferMultibyteVarintChunkSize,AssumesMinimumWindowSizeInFirstParameters)3123*61c4878aSAndroid Build Coastguard Worker TEST_F(WriteTransferMultibyteVarintChunkSize,
3124*61c4878aSAndroid Build Coastguard Worker        AssumesMinimumWindowSizeInFirstParameters) {
3125*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(
3126*61c4878aSAndroid Build Coastguard Worker       EncodeChunk(Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStart)
3127*61c4878aSAndroid Build Coastguard Worker                       .set_desired_session_id(kArbitrarySessionId)
3128*61c4878aSAndroid Build Coastguard Worker                       .set_resource_id(7)));
3129*61c4878aSAndroid Build Coastguard Worker 
3130*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3131*61c4878aSAndroid Build Coastguard Worker 
3132*61c4878aSAndroid Build Coastguard Worker   EXPECT_TRUE(handler_.prepare_write_called);
3133*61c4878aSAndroid Build Coastguard Worker   EXPECT_FALSE(handler_.finalize_write_called);
3134*61c4878aSAndroid Build Coastguard Worker 
3135*61c4878aSAndroid Build Coastguard Worker   // First, the server responds with a START_ACK, accepting the session ID and
3136*61c4878aSAndroid Build Coastguard Worker   // confirming the protocol version.
3137*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 1u);
3138*61c4878aSAndroid Build Coastguard Worker   Chunk chunk = DecodeChunk(ctx_.responses().back());
3139*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
3140*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kStartAck);
3141*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3142*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.resource_id(), 7u);
3143*61c4878aSAndroid Build Coastguard Worker 
3144*61c4878aSAndroid Build Coastguard Worker   // Complete the handshake by confirming the server's ACK.
3145*61c4878aSAndroid Build Coastguard Worker   ctx_.SendClientStream(EncodeChunk(
3146*61c4878aSAndroid Build Coastguard Worker       Chunk(ProtocolVersion::kVersionTwo, Chunk::Type::kStartAckConfirmation)
3147*61c4878aSAndroid Build Coastguard Worker           .set_session_id(kArbitrarySessionId)));
3148*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3149*61c4878aSAndroid Build Coastguard Worker 
3150*61c4878aSAndroid Build Coastguard Worker   // Server should respond by sending its initial transfer parameters.
3151*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 2u);
3152*61c4878aSAndroid Build Coastguard Worker 
3153*61c4878aSAndroid Build Coastguard Worker   constexpr uint32_t kExpectedMaxChunkSize = 226;
3154*61c4878aSAndroid Build Coastguard Worker 
3155*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses()[1]);
3156*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
3157*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
3158*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3159*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
3160*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), kExpectedMaxChunkSize);
3161*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
3162*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), kExpectedMaxChunkSize);
3163*61c4878aSAndroid Build Coastguard Worker 
3164*61c4878aSAndroid Build Coastguard Worker   // Simulate a timeout, prompting the server to recalculate its transfer
3165*61c4878aSAndroid Build Coastguard Worker   // parameters. The max chunk size and window size should not change.
3166*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.SimulateServerTimeout(kArbitrarySessionId);
3167*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.total_responses(), 3u);
3168*61c4878aSAndroid Build Coastguard Worker 
3169*61c4878aSAndroid Build Coastguard Worker   chunk = DecodeChunk(ctx_.responses().back());
3170*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.protocol_version(), ProtocolVersion::kVersionTwo);
3171*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.type(), Chunk::Type::kParametersRetransmit);
3172*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.session_id(), kArbitrarySessionId);
3173*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.offset(), 0u);
3174*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.window_end_offset(), kExpectedMaxChunkSize);
3175*61c4878aSAndroid Build Coastguard Worker   ASSERT_TRUE(chunk.max_chunk_size_bytes().has_value());
3176*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(chunk.max_chunk_size_bytes().value(), kExpectedMaxChunkSize);
3177*61c4878aSAndroid Build Coastguard Worker }
3178*61c4878aSAndroid Build Coastguard Worker 
3179*61c4878aSAndroid Build Coastguard Worker class ReadTransferWithStats : public SimpleReadTransfer {
3180*61c4878aSAndroid Build Coastguard Worker  public:
3181*61c4878aSAndroid Build Coastguard Worker   using SimpleReadTransfer::SimpleReadTransfer;
3182*61c4878aSAndroid Build Coastguard Worker 
GetStatus(uint64_t & readable_offset,uint64_t & writeable_offset,uint64_t & read_checksum,uint64_t & write_checksum)3183*61c4878aSAndroid Build Coastguard Worker   Status GetStatus(uint64_t& readable_offset,
3184*61c4878aSAndroid Build Coastguard Worker                    uint64_t& writeable_offset,
3185*61c4878aSAndroid Build Coastguard Worker                    uint64_t& read_checksum,
3186*61c4878aSAndroid Build Coastguard Worker                    uint64_t& write_checksum) override {
3187*61c4878aSAndroid Build Coastguard Worker     readable_offset = 64;
3188*61c4878aSAndroid Build Coastguard Worker     read_checksum = 0xffee;
3189*61c4878aSAndroid Build Coastguard Worker     writeable_offset = 128;
3190*61c4878aSAndroid Build Coastguard Worker     write_checksum = 0xeeff;
3191*61c4878aSAndroid Build Coastguard Worker     return OkStatus();
3192*61c4878aSAndroid Build Coastguard Worker   }
3193*61c4878aSAndroid Build Coastguard Worker };
3194*61c4878aSAndroid Build Coastguard Worker 
3195*61c4878aSAndroid Build Coastguard Worker class GetResourceStatus : public ::testing::Test {
3196*61c4878aSAndroid Build Coastguard Worker  protected:
GetResourceStatus(size_t max_chunk_size_bytes=64)3197*61c4878aSAndroid Build Coastguard Worker   GetResourceStatus(size_t max_chunk_size_bytes = 64)
3198*61c4878aSAndroid Build Coastguard Worker       : handler_(3, kData),
3199*61c4878aSAndroid Build Coastguard Worker         transfer_thread_(span(data_buffer_).first(max_chunk_size_bytes),
3200*61c4878aSAndroid Build Coastguard Worker                          encode_buffer_),
3201*61c4878aSAndroid Build Coastguard Worker         ctx_(transfer_thread_,
3202*61c4878aSAndroid Build Coastguard Worker              64,
3203*61c4878aSAndroid Build Coastguard Worker              // Use a long timeout to avoid accidentally triggering timeouts.
3204*61c4878aSAndroid Build Coastguard Worker              std::chrono::minutes(1)),
3205*61c4878aSAndroid Build Coastguard Worker         system_thread_(TransferThreadOptions(), transfer_thread_) {
3206*61c4878aSAndroid Build Coastguard Worker     ctx_.service().RegisterHandler(handler_);
3207*61c4878aSAndroid Build Coastguard Worker 
3208*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.prepare_read_called);
3209*61c4878aSAndroid Build Coastguard Worker     PW_CHECK(!handler_.finalize_read_called);
3210*61c4878aSAndroid Build Coastguard Worker   }
3211*61c4878aSAndroid Build Coastguard Worker 
~GetResourceStatus()3212*61c4878aSAndroid Build Coastguard Worker   ~GetResourceStatus() override {
3213*61c4878aSAndroid Build Coastguard Worker     transfer_thread_.Terminate();
3214*61c4878aSAndroid Build Coastguard Worker     system_thread_.join();
3215*61c4878aSAndroid Build Coastguard Worker   }
3216*61c4878aSAndroid Build Coastguard Worker 
3217*61c4878aSAndroid Build Coastguard Worker   ReadTransferWithStats handler_;
3218*61c4878aSAndroid Build Coastguard Worker   Thread<1, 1> transfer_thread_;
3219*61c4878aSAndroid Build Coastguard Worker   PW_RAW_TEST_METHOD_CONTEXT(TransferService, GetResourceStatus) ctx_;
3220*61c4878aSAndroid Build Coastguard Worker   pw::Thread system_thread_;
3221*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> data_buffer_;
3222*61c4878aSAndroid Build Coastguard Worker   std::array<std::byte, 64> encode_buffer_;
3223*61c4878aSAndroid Build Coastguard Worker };
3224*61c4878aSAndroid Build Coastguard Worker 
TEST_F(GetResourceStatus,ValidResourceId_ReturnsStatus)3225*61c4878aSAndroid Build Coastguard Worker TEST_F(GetResourceStatus, ValidResourceId_ReturnsStatus) {
3226*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatusRequest::MemoryEncoder encoder(encode_buffer_);
3227*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(encoder.Write({.resource_id = 3}), OkStatus());
3228*61c4878aSAndroid Build Coastguard Worker   ctx_.call(encoder);
3229*61c4878aSAndroid Build Coastguard Worker 
3230*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3231*61c4878aSAndroid Build Coastguard Worker 
3232*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.status(), OkStatus());
3233*61c4878aSAndroid Build Coastguard Worker 
3234*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(ctx_.response());
3235*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::StreamDecoder decoder(reader);
3236*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::Message response;
3237*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(decoder.Read(response), OkStatus());
3238*61c4878aSAndroid Build Coastguard Worker 
3239*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.resource_id, 3u);
3240*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.readable_offset, 64u);
3241*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.read_checksum, 0xffee);
3242*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.writeable_offset, 128u);
3243*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.write_checksum, 0xeeff);
3244*61c4878aSAndroid Build Coastguard Worker }
3245*61c4878aSAndroid Build Coastguard Worker 
TEST_F(GetResourceStatus,InvalidResourceId_ReturnsNotFound)3246*61c4878aSAndroid Build Coastguard Worker TEST_F(GetResourceStatus, InvalidResourceId_ReturnsNotFound) {
3247*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatusRequest::MemoryEncoder encoder(encode_buffer_);
3248*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(encoder.Write({.resource_id = 27}), OkStatus());
3249*61c4878aSAndroid Build Coastguard Worker   ctx_.call(encoder);
3250*61c4878aSAndroid Build Coastguard Worker 
3251*61c4878aSAndroid Build Coastguard Worker   transfer_thread_.WaitUntilEventIsProcessed();
3252*61c4878aSAndroid Build Coastguard Worker 
3253*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(ctx_.status(), Status::NotFound());
3254*61c4878aSAndroid Build Coastguard Worker 
3255*61c4878aSAndroid Build Coastguard Worker   stream::MemoryReader reader(ctx_.response());
3256*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::StreamDecoder decoder(reader);
3257*61c4878aSAndroid Build Coastguard Worker   pwpb::ResourceStatus::Message response;
3258*61c4878aSAndroid Build Coastguard Worker   ASSERT_EQ(decoder.Read(response), OkStatus());
3259*61c4878aSAndroid Build Coastguard Worker 
3260*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(response.resource_id, 27u);
3261*61c4878aSAndroid Build Coastguard Worker }
3262*61c4878aSAndroid Build Coastguard Worker 
3263*61c4878aSAndroid Build Coastguard Worker }  // namespace
3264*61c4878aSAndroid Build Coastguard Worker }  // namespace pw::transfer::test
3265