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