xref: /aosp_15_r20/external/pigweed/pw_transfer/ts/transfer_test.ts (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker// Copyright 2022 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/* eslint-env browser */
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Workerimport {
18*61c4878aSAndroid Build Coastguard Worker  Channel,
19*61c4878aSAndroid Build Coastguard Worker  Client,
20*61c4878aSAndroid Build Coastguard Worker  decode,
21*61c4878aSAndroid Build Coastguard Worker  MethodStub,
22*61c4878aSAndroid Build Coastguard Worker  ServiceClient,
23*61c4878aSAndroid Build Coastguard Worker} from 'pigweedjs/pw_rpc';
24*61c4878aSAndroid Build Coastguard Workerimport { Status } from 'pigweedjs/pw_status';
25*61c4878aSAndroid Build Coastguard Workerimport {
26*61c4878aSAndroid Build Coastguard Worker  PacketType,
27*61c4878aSAndroid Build Coastguard Worker  RpcPacket,
28*61c4878aSAndroid Build Coastguard Worker} from 'pigweedjs/protos/pw_rpc/internal/packet_pb';
29*61c4878aSAndroid Build Coastguard Workerimport { ProtoCollection } from 'pigweedjs/protos/collection';
30*61c4878aSAndroid Build Coastguard Workerimport { Chunk } from 'pigweedjs/protos/pw_transfer/transfer_pb';
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard Workerimport { Manager } from './client';
33*61c4878aSAndroid Build Coastguard Workerimport { ProgressStats } from './transfer';
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Workerconst DEFAULT_TIMEOUT_S = 0.3;
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Workerdescribe('Transfer client', () => {
38*61c4878aSAndroid Build Coastguard Worker  const textEncoder = new TextEncoder();
39*61c4878aSAndroid Build Coastguard Worker  const textDecoder = new TextDecoder();
40*61c4878aSAndroid Build Coastguard Worker  let client: Client;
41*61c4878aSAndroid Build Coastguard Worker  let service: ServiceClient;
42*61c4878aSAndroid Build Coastguard Worker  let sentChunks: Chunk[];
43*61c4878aSAndroid Build Coastguard Worker  let packetsToSend: Uint8Array[][];
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard Worker  beforeEach(() => {
46*61c4878aSAndroid Build Coastguard Worker    const lib = new ProtoCollection();
47*61c4878aSAndroid Build Coastguard Worker    const channels: Channel[] = [new Channel(1, handleRequest)];
48*61c4878aSAndroid Build Coastguard Worker    client = Client.fromProtoSet(channels, lib);
49*61c4878aSAndroid Build Coastguard Worker    service = client.channel(1)!.service('pw.transfer.Transfer')!;
50*61c4878aSAndroid Build Coastguard Worker
51*61c4878aSAndroid Build Coastguard Worker    sentChunks = [];
52*61c4878aSAndroid Build Coastguard Worker    packetsToSend = [];
53*61c4878aSAndroid Build Coastguard Worker  });
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker  function handleRequest(data: Uint8Array): void {
56*61c4878aSAndroid Build Coastguard Worker    const packet = decode(data);
57*61c4878aSAndroid Build Coastguard Worker    if (packet.getType() !== PacketType.CLIENT_STREAM) {
58*61c4878aSAndroid Build Coastguard Worker      return;
59*61c4878aSAndroid Build Coastguard Worker    }
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker    const chunk = Chunk.deserializeBinary(packet.getPayload_asU8());
62*61c4878aSAndroid Build Coastguard Worker    sentChunks.push(chunk);
63*61c4878aSAndroid Build Coastguard Worker
64*61c4878aSAndroid Build Coastguard Worker    if (packetsToSend.length > 0) {
65*61c4878aSAndroid Build Coastguard Worker      const responses = packetsToSend.shift()!;
66*61c4878aSAndroid Build Coastguard Worker      for (const response of responses) {
67*61c4878aSAndroid Build Coastguard Worker        client.processPacket(response);
68*61c4878aSAndroid Build Coastguard Worker      }
69*61c4878aSAndroid Build Coastguard Worker    }
70*61c4878aSAndroid Build Coastguard Worker  }
71*61c4878aSAndroid Build Coastguard Worker
72*61c4878aSAndroid Build Coastguard Worker  function receivedData(): Uint8Array {
73*61c4878aSAndroid Build Coastguard Worker    let length = 0;
74*61c4878aSAndroid Build Coastguard Worker    sentChunks.forEach((chunk: Chunk) => {
75*61c4878aSAndroid Build Coastguard Worker      length += chunk.getData().length;
76*61c4878aSAndroid Build Coastguard Worker    });
77*61c4878aSAndroid Build Coastguard Worker    const data = new Uint8Array(length);
78*61c4878aSAndroid Build Coastguard Worker    let offset = 0;
79*61c4878aSAndroid Build Coastguard Worker    sentChunks.forEach((chunk: Chunk) => {
80*61c4878aSAndroid Build Coastguard Worker      data.set(chunk.getData() as Uint8Array, offset);
81*61c4878aSAndroid Build Coastguard Worker      offset += chunk.getData().length;
82*61c4878aSAndroid Build Coastguard Worker    });
83*61c4878aSAndroid Build Coastguard Worker    return data;
84*61c4878aSAndroid Build Coastguard Worker  }
85*61c4878aSAndroid Build Coastguard Worker
86*61c4878aSAndroid Build Coastguard Worker  function enqueueServerError(method: MethodStub, error: Status): void {
87*61c4878aSAndroid Build Coastguard Worker    const packet = new RpcPacket();
88*61c4878aSAndroid Build Coastguard Worker    packet.setType(PacketType.SERVER_ERROR);
89*61c4878aSAndroid Build Coastguard Worker    packet.setChannelId(1);
90*61c4878aSAndroid Build Coastguard Worker    packet.setServiceId(service.id);
91*61c4878aSAndroid Build Coastguard Worker    packet.setMethodId(method.id);
92*61c4878aSAndroid Build Coastguard Worker    packet.setCallId(method.rpcs.nextCallId);
93*61c4878aSAndroid Build Coastguard Worker    packet.setStatus(error);
94*61c4878aSAndroid Build Coastguard Worker    packetsToSend.push([packet.serializeBinary()]);
95*61c4878aSAndroid Build Coastguard Worker  }
96*61c4878aSAndroid Build Coastguard Worker
97*61c4878aSAndroid Build Coastguard Worker  function enqueueServerResponses(method: MethodStub, responses: Chunk[][]) {
98*61c4878aSAndroid Build Coastguard Worker    for (const responseGroup of responses) {
99*61c4878aSAndroid Build Coastguard Worker      const serializedGroup = [];
100*61c4878aSAndroid Build Coastguard Worker      for (const response of responseGroup) {
101*61c4878aSAndroid Build Coastguard Worker        const packet = new RpcPacket();
102*61c4878aSAndroid Build Coastguard Worker        packet.setType(PacketType.SERVER_STREAM);
103*61c4878aSAndroid Build Coastguard Worker        packet.setChannelId(1);
104*61c4878aSAndroid Build Coastguard Worker        packet.setServiceId(service.id);
105*61c4878aSAndroid Build Coastguard Worker        packet.setMethodId(method.id);
106*61c4878aSAndroid Build Coastguard Worker        packet.setCallId(method.rpcs.nextCallId);
107*61c4878aSAndroid Build Coastguard Worker        packet.setStatus(Status.OK);
108*61c4878aSAndroid Build Coastguard Worker        packet.setPayload(response.serializeBinary());
109*61c4878aSAndroid Build Coastguard Worker        serializedGroup.push(packet.serializeBinary());
110*61c4878aSAndroid Build Coastguard Worker      }
111*61c4878aSAndroid Build Coastguard Worker      packetsToSend.push(serializedGroup);
112*61c4878aSAndroid Build Coastguard Worker    }
113*61c4878aSAndroid Build Coastguard Worker  }
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker  function buildChunk(
116*61c4878aSAndroid Build Coastguard Worker    sessionId: number,
117*61c4878aSAndroid Build Coastguard Worker    offset: number,
118*61c4878aSAndroid Build Coastguard Worker    data: string,
119*61c4878aSAndroid Build Coastguard Worker    remainingBytes: number,
120*61c4878aSAndroid Build Coastguard Worker  ): Chunk {
121*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
122*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(sessionId);
123*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(offset);
124*61c4878aSAndroid Build Coastguard Worker    chunk.setData(textEncoder.encode(data));
125*61c4878aSAndroid Build Coastguard Worker    chunk.setRemainingBytes(remainingBytes);
126*61c4878aSAndroid Build Coastguard Worker    return chunk;
127*61c4878aSAndroid Build Coastguard Worker  }
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker  it('read transfer basic', async () => {
130*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard Worker    const chunk1 = buildChunk(3, 0, 'abc', 0);
133*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [[chunk1]]);
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3);
136*61c4878aSAndroid Build Coastguard Worker    expect(textDecoder.decode(data)).toEqual('abc');
137*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(2);
138*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
139*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
140*61c4878aSAndroid Build Coastguard Worker  });
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker  it('read transfer multichunk', async () => {
143*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
144*61c4878aSAndroid Build Coastguard Worker
145*61c4878aSAndroid Build Coastguard Worker    const chunk1 = buildChunk(3, 0, 'abc', 3);
146*61c4878aSAndroid Build Coastguard Worker    const chunk2 = buildChunk(3, 3, 'def', 0);
147*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [[chunk1, chunk2]]);
148*61c4878aSAndroid Build Coastguard Worker
149*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3);
150*61c4878aSAndroid Build Coastguard Worker    expect(data).toEqual(textEncoder.encode('abcdef'));
151*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(2);
152*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
153*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
154*61c4878aSAndroid Build Coastguard Worker  });
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker  it('read transfer progress callback', async () => {
157*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker    const chunk1 = buildChunk(3, 0, 'abc', 3);
160*61c4878aSAndroid Build Coastguard Worker    const chunk2 = buildChunk(3, 3, 'def', 0);
161*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [[chunk1, chunk2]]);
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker    const progress: Array<ProgressStats> = [];
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3, (stats: ProgressStats) => {
166*61c4878aSAndroid Build Coastguard Worker      progress.push(stats);
167*61c4878aSAndroid Build Coastguard Worker    });
168*61c4878aSAndroid Build Coastguard Worker    expect(textDecoder.decode(data)).toEqual('abcdef');
169*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(2);
170*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
171*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
172*61c4878aSAndroid Build Coastguard Worker
173*61c4878aSAndroid Build Coastguard Worker    expect(progress).toEqual([
174*61c4878aSAndroid Build Coastguard Worker      new ProgressStats(3, 3, 6),
175*61c4878aSAndroid Build Coastguard Worker      new ProgressStats(6, 6, 6),
176*61c4878aSAndroid Build Coastguard Worker    ]);
177*61c4878aSAndroid Build Coastguard Worker  });
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard Worker  it('read transfer retry bad offset', async () => {
180*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker    const chunk1 = buildChunk(3, 0, '123', 6);
183*61c4878aSAndroid Build Coastguard Worker    const chunk2 = buildChunk(3, 1, '456', 3); // Incorrect offset; expecting 3
184*61c4878aSAndroid Build Coastguard Worker    const chunk3 = buildChunk(3, 3, '456', 3);
185*61c4878aSAndroid Build Coastguard Worker    const chunk4 = buildChunk(3, 6, '789', 0);
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [
188*61c4878aSAndroid Build Coastguard Worker      [chunk1, chunk2],
189*61c4878aSAndroid Build Coastguard Worker      [chunk3, chunk4],
190*61c4878aSAndroid Build Coastguard Worker    ]);
191*61c4878aSAndroid Build Coastguard Worker
192*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3);
193*61c4878aSAndroid Build Coastguard Worker    expect(data).toEqual(textEncoder.encode('123456789'));
194*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
195*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
196*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
197*61c4878aSAndroid Build Coastguard Worker  });
198*61c4878aSAndroid Build Coastguard Worker
199*61c4878aSAndroid Build Coastguard Worker  it('read transfer retry re-sent offset', async () => {
200*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard Worker    const chunk1 = buildChunk(3, 0, '01234567', 8);
203*61c4878aSAndroid Build Coastguard Worker    const chunk2 = buildChunk(3, 4, '4567', 8);
204*61c4878aSAndroid Build Coastguard Worker    const chunk3 = buildChunk(3, 8, '89abcdef', 0);
205*61c4878aSAndroid Build Coastguard Worker
206*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [
207*61c4878aSAndroid Build Coastguard Worker      [chunk1, chunk2],
208*61c4878aSAndroid Build Coastguard Worker      [chunk3],
209*61c4878aSAndroid Build Coastguard Worker    ]);
210*61c4878aSAndroid Build Coastguard Worker
211*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3);
212*61c4878aSAndroid Build Coastguard Worker    expect(data).toEqual(textEncoder.encode('0123456789abcdef'));
213*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
214*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getType()).toEqual(Chunk.Type.PARAMETERS_CONTINUE);
215*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getOffset()).toEqual(8);
216*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
217*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
218*61c4878aSAndroid Build Coastguard Worker  });
219*61c4878aSAndroid Build Coastguard Worker
220*61c4878aSAndroid Build Coastguard Worker  it('read transfer retry timeout', async () => {
221*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
222*61c4878aSAndroid Build Coastguard Worker
223*61c4878aSAndroid Build Coastguard Worker    const chunk = buildChunk(3, 0, 'xyz', 0);
224*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [[], [chunk]]);
225*61c4878aSAndroid Build Coastguard Worker
226*61c4878aSAndroid Build Coastguard Worker    const data = await manager.read(3);
227*61c4878aSAndroid Build Coastguard Worker    expect(textDecoder.decode(data)).toEqual('xyz');
228*61c4878aSAndroid Build Coastguard Worker
229*61c4878aSAndroid Build Coastguard Worker    // Two transfer parameter requests should have been sent.
230*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
231*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].hasStatus()).toBe(true);
232*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[sentChunks.length - 1].getStatus()).toEqual(Status.OK);
233*61c4878aSAndroid Build Coastguard Worker  });
234*61c4878aSAndroid Build Coastguard Worker
235*61c4878aSAndroid Build Coastguard Worker  it('read transfer timeout', async () => {
236*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
237*61c4878aSAndroid Build Coastguard Worker
238*61c4878aSAndroid Build Coastguard Worker    await manager
239*61c4878aSAndroid Build Coastguard Worker      .read(27)
240*61c4878aSAndroid Build Coastguard Worker      .then(() => {
241*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected completed promise');
242*61c4878aSAndroid Build Coastguard Worker      })
243*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
244*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(27);
245*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.DEADLINE_EXCEEDED]);
246*61c4878aSAndroid Build Coastguard Worker        expect(sentChunks).toHaveLength(4);
247*61c4878aSAndroid Build Coastguard Worker      });
248*61c4878aSAndroid Build Coastguard Worker  });
249*61c4878aSAndroid Build Coastguard Worker
250*61c4878aSAndroid Build Coastguard Worker  it('read transfer error', async () => {
251*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
252*61c4878aSAndroid Build Coastguard Worker
253*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
254*61c4878aSAndroid Build Coastguard Worker    chunk.setStatus(Status.NOT_FOUND);
255*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(31);
256*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Read')!, [[chunk]]);
257*61c4878aSAndroid Build Coastguard Worker
258*61c4878aSAndroid Build Coastguard Worker    await manager
259*61c4878aSAndroid Build Coastguard Worker      .read(31)
260*61c4878aSAndroid Build Coastguard Worker      .then(() => {
261*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected completed promise');
262*61c4878aSAndroid Build Coastguard Worker      })
263*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
264*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(31);
265*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.NOT_FOUND]);
266*61c4878aSAndroid Build Coastguard Worker      });
267*61c4878aSAndroid Build Coastguard Worker  });
268*61c4878aSAndroid Build Coastguard Worker
269*61c4878aSAndroid Build Coastguard Worker  it('read transfer server error', async () => {
270*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
271*61c4878aSAndroid Build Coastguard Worker
272*61c4878aSAndroid Build Coastguard Worker    enqueueServerError(service.method('Read')!, Status.NOT_FOUND);
273*61c4878aSAndroid Build Coastguard Worker    await manager
274*61c4878aSAndroid Build Coastguard Worker      .read(31)
275*61c4878aSAndroid Build Coastguard Worker      .then((data) => {
276*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected completed promise');
277*61c4878aSAndroid Build Coastguard Worker      })
278*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
279*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(31);
280*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.INTERNAL]);
281*61c4878aSAndroid Build Coastguard Worker      });
282*61c4878aSAndroid Build Coastguard Worker  });
283*61c4878aSAndroid Build Coastguard Worker
284*61c4878aSAndroid Build Coastguard Worker  it('write transfer basic', async () => {
285*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
286*61c4878aSAndroid Build Coastguard Worker
287*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
288*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(4);
289*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(0);
290*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(32);
291*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(8);
292*61c4878aSAndroid Build Coastguard Worker
293*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
294*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
295*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
296*61c4878aSAndroid Build Coastguard Worker
297*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
298*61c4878aSAndroid Build Coastguard Worker      [chunk],
299*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
300*61c4878aSAndroid Build Coastguard Worker    ]);
301*61c4878aSAndroid Build Coastguard Worker
302*61c4878aSAndroid Build Coastguard Worker    await manager.write(4, textEncoder.encode('hello'));
303*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(2);
304*61c4878aSAndroid Build Coastguard Worker    expect(receivedData()).toEqual(textEncoder.encode('hello'));
305*61c4878aSAndroid Build Coastguard Worker  });
306*61c4878aSAndroid Build Coastguard Worker
307*61c4878aSAndroid Build Coastguard Worker  it('write transfer max chunk size', async () => {
308*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
309*61c4878aSAndroid Build Coastguard Worker
310*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
311*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(4);
312*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(0);
313*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(32);
314*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(8);
315*61c4878aSAndroid Build Coastguard Worker
316*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
317*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
318*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
319*61c4878aSAndroid Build Coastguard Worker
320*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
321*61c4878aSAndroid Build Coastguard Worker      [chunk],
322*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
323*61c4878aSAndroid Build Coastguard Worker    ]);
324*61c4878aSAndroid Build Coastguard Worker
325*61c4878aSAndroid Build Coastguard Worker    await manager.write(4, textEncoder.encode('hello world'));
326*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
327*61c4878aSAndroid Build Coastguard Worker    expect(receivedData()).toEqual(textEncoder.encode('hello world'));
328*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getData()).toEqual(textEncoder.encode('hello wo'));
329*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[2].getData()).toEqual(textEncoder.encode('rld'));
330*61c4878aSAndroid Build Coastguard Worker  });
331*61c4878aSAndroid Build Coastguard Worker
332*61c4878aSAndroid Build Coastguard Worker  it('write transfer multiple parameters', async () => {
333*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
334*61c4878aSAndroid Build Coastguard Worker
335*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
336*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(4);
337*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(0);
338*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(8);
339*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(8);
340*61c4878aSAndroid Build Coastguard Worker
341*61c4878aSAndroid Build Coastguard Worker    const chunk2 = new Chunk();
342*61c4878aSAndroid Build Coastguard Worker    chunk2.setTransferId(4);
343*61c4878aSAndroid Build Coastguard Worker    chunk2.setOffset(8);
344*61c4878aSAndroid Build Coastguard Worker    chunk2.setPendingBytes(8);
345*61c4878aSAndroid Build Coastguard Worker    chunk2.setMaxChunkSizeBytes(8);
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
348*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
349*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
350*61c4878aSAndroid Build Coastguard Worker
351*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
352*61c4878aSAndroid Build Coastguard Worker      [chunk],
353*61c4878aSAndroid Build Coastguard Worker      [chunk2],
354*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
355*61c4878aSAndroid Build Coastguard Worker    ]);
356*61c4878aSAndroid Build Coastguard Worker
357*61c4878aSAndroid Build Coastguard Worker    await manager.write(4, textEncoder.encode('data to write'));
358*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
359*61c4878aSAndroid Build Coastguard Worker    expect(receivedData()).toEqual(textEncoder.encode('data to write'));
360*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getData()).toEqual(textEncoder.encode('data to '));
361*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[2].getData()).toEqual(textEncoder.encode('write'));
362*61c4878aSAndroid Build Coastguard Worker  });
363*61c4878aSAndroid Build Coastguard Worker
364*61c4878aSAndroid Build Coastguard Worker  it('write transfer parameters update', async () => {
365*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
366*61c4878aSAndroid Build Coastguard Worker
367*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
368*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(4);
369*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(0);
370*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(8);
371*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(4);
372*61c4878aSAndroid Build Coastguard Worker    chunk.setType(Chunk.Type.PARAMETERS_RETRANSMIT);
373*61c4878aSAndroid Build Coastguard Worker    chunk.setWindowEndOffset(8);
374*61c4878aSAndroid Build Coastguard Worker
375*61c4878aSAndroid Build Coastguard Worker    const chunk2 = new Chunk();
376*61c4878aSAndroid Build Coastguard Worker    chunk2.setTransferId(4);
377*61c4878aSAndroid Build Coastguard Worker    chunk2.setOffset(4);
378*61c4878aSAndroid Build Coastguard Worker    chunk2.setPendingBytes(8);
379*61c4878aSAndroid Build Coastguard Worker    chunk2.setType(Chunk.Type.PARAMETERS_CONTINUE);
380*61c4878aSAndroid Build Coastguard Worker    chunk2.setWindowEndOffset(12);
381*61c4878aSAndroid Build Coastguard Worker
382*61c4878aSAndroid Build Coastguard Worker    const chunk3 = new Chunk();
383*61c4878aSAndroid Build Coastguard Worker    chunk3.setTransferId(4);
384*61c4878aSAndroid Build Coastguard Worker    chunk3.setOffset(8);
385*61c4878aSAndroid Build Coastguard Worker    chunk3.setPendingBytes(8);
386*61c4878aSAndroid Build Coastguard Worker    chunk3.setType(Chunk.Type.PARAMETERS_CONTINUE);
387*61c4878aSAndroid Build Coastguard Worker    chunk3.setWindowEndOffset(16);
388*61c4878aSAndroid Build Coastguard Worker
389*61c4878aSAndroid Build Coastguard Worker    const chunk4 = new Chunk();
390*61c4878aSAndroid Build Coastguard Worker    chunk4.setTransferId(4);
391*61c4878aSAndroid Build Coastguard Worker    chunk4.setOffset(12);
392*61c4878aSAndroid Build Coastguard Worker    chunk4.setPendingBytes(8);
393*61c4878aSAndroid Build Coastguard Worker    chunk4.setType(Chunk.Type.PARAMETERS_CONTINUE);
394*61c4878aSAndroid Build Coastguard Worker    chunk4.setWindowEndOffset(20);
395*61c4878aSAndroid Build Coastguard Worker
396*61c4878aSAndroid Build Coastguard Worker    const chunk5 = new Chunk();
397*61c4878aSAndroid Build Coastguard Worker    chunk5.setTransferId(4);
398*61c4878aSAndroid Build Coastguard Worker    chunk5.setOffset(16);
399*61c4878aSAndroid Build Coastguard Worker    chunk5.setPendingBytes(8);
400*61c4878aSAndroid Build Coastguard Worker    chunk5.setType(Chunk.Type.PARAMETERS_CONTINUE);
401*61c4878aSAndroid Build Coastguard Worker    chunk5.setWindowEndOffset(24);
402*61c4878aSAndroid Build Coastguard Worker
403*61c4878aSAndroid Build Coastguard Worker    const chunk6 = new Chunk();
404*61c4878aSAndroid Build Coastguard Worker    chunk6.setTransferId(4);
405*61c4878aSAndroid Build Coastguard Worker    chunk6.setOffset(20);
406*61c4878aSAndroid Build Coastguard Worker    chunk6.setPendingBytes(8);
407*61c4878aSAndroid Build Coastguard Worker    chunk6.setType(Chunk.Type.PARAMETERS_CONTINUE);
408*61c4878aSAndroid Build Coastguard Worker    chunk6.setWindowEndOffset(28);
409*61c4878aSAndroid Build Coastguard Worker
410*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
411*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
412*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
413*61c4878aSAndroid Build Coastguard Worker
414*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
415*61c4878aSAndroid Build Coastguard Worker      [chunk],
416*61c4878aSAndroid Build Coastguard Worker      [chunk2],
417*61c4878aSAndroid Build Coastguard Worker      [chunk3],
418*61c4878aSAndroid Build Coastguard Worker      [chunk4],
419*61c4878aSAndroid Build Coastguard Worker      [chunk5],
420*61c4878aSAndroid Build Coastguard Worker      [chunk6],
421*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
422*61c4878aSAndroid Build Coastguard Worker    ]);
423*61c4878aSAndroid Build Coastguard Worker
424*61c4878aSAndroid Build Coastguard Worker    await manager.write(4, textEncoder.encode('hello this is a message'));
425*61c4878aSAndroid Build Coastguard Worker    expect(receivedData()).toEqual(
426*61c4878aSAndroid Build Coastguard Worker      textEncoder.encode('hello this is a message'),
427*61c4878aSAndroid Build Coastguard Worker    );
428*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getData()).toEqual(textEncoder.encode('hell'));
429*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[2].getData()).toEqual(textEncoder.encode('o th'));
430*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[3].getData()).toEqual(textEncoder.encode('is i'));
431*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[4].getData()).toEqual(textEncoder.encode('s a '));
432*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[5].getData()).toEqual(textEncoder.encode('mess'));
433*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[6].getData()).toEqual(textEncoder.encode('age'));
434*61c4878aSAndroid Build Coastguard Worker  });
435*61c4878aSAndroid Build Coastguard Worker
436*61c4878aSAndroid Build Coastguard Worker  it('write transfer progress callback', async () => {
437*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
438*61c4878aSAndroid Build Coastguard Worker
439*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
440*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(4);
441*61c4878aSAndroid Build Coastguard Worker    chunk.setOffset(0);
442*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(8);
443*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(8);
444*61c4878aSAndroid Build Coastguard Worker
445*61c4878aSAndroid Build Coastguard Worker    const chunk2 = new Chunk();
446*61c4878aSAndroid Build Coastguard Worker    chunk2.setTransferId(4);
447*61c4878aSAndroid Build Coastguard Worker    chunk2.setOffset(8);
448*61c4878aSAndroid Build Coastguard Worker    chunk2.setPendingBytes(8);
449*61c4878aSAndroid Build Coastguard Worker    chunk2.setMaxChunkSizeBytes(8);
450*61c4878aSAndroid Build Coastguard Worker
451*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
452*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
453*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
454*61c4878aSAndroid Build Coastguard Worker
455*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
456*61c4878aSAndroid Build Coastguard Worker      [chunk],
457*61c4878aSAndroid Build Coastguard Worker      [chunk2],
458*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
459*61c4878aSAndroid Build Coastguard Worker    ]);
460*61c4878aSAndroid Build Coastguard Worker
461*61c4878aSAndroid Build Coastguard Worker    const progress: Array<ProgressStats> = [];
462*61c4878aSAndroid Build Coastguard Worker    await manager.write(
463*61c4878aSAndroid Build Coastguard Worker      4,
464*61c4878aSAndroid Build Coastguard Worker      textEncoder.encode('data to write'),
465*61c4878aSAndroid Build Coastguard Worker      (stats: ProgressStats) => {
466*61c4878aSAndroid Build Coastguard Worker        progress.push(stats);
467*61c4878aSAndroid Build Coastguard Worker      },
468*61c4878aSAndroid Build Coastguard Worker    );
469*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(3);
470*61c4878aSAndroid Build Coastguard Worker    expect(receivedData()).toEqual(textEncoder.encode('data to write'));
471*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getData()).toEqual(textEncoder.encode('data to '));
472*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[2].getData()).toEqual(textEncoder.encode('write'));
473*61c4878aSAndroid Build Coastguard Worker
474*61c4878aSAndroid Build Coastguard Worker    console.log(progress);
475*61c4878aSAndroid Build Coastguard Worker    expect(progress).toEqual([
476*61c4878aSAndroid Build Coastguard Worker      new ProgressStats(8, 0, 13),
477*61c4878aSAndroid Build Coastguard Worker      new ProgressStats(13, 8, 13),
478*61c4878aSAndroid Build Coastguard Worker      new ProgressStats(13, 13, 13),
479*61c4878aSAndroid Build Coastguard Worker    ]);
480*61c4878aSAndroid Build Coastguard Worker  });
481*61c4878aSAndroid Build Coastguard Worker
482*61c4878aSAndroid Build Coastguard Worker  it('write transfer rewind', async () => {
483*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
484*61c4878aSAndroid Build Coastguard Worker
485*61c4878aSAndroid Build Coastguard Worker    const chunk1 = new Chunk();
486*61c4878aSAndroid Build Coastguard Worker    chunk1.setTransferId(4);
487*61c4878aSAndroid Build Coastguard Worker    chunk1.setOffset(0);
488*61c4878aSAndroid Build Coastguard Worker    chunk1.setPendingBytes(8);
489*61c4878aSAndroid Build Coastguard Worker    chunk1.setMaxChunkSizeBytes(8);
490*61c4878aSAndroid Build Coastguard Worker
491*61c4878aSAndroid Build Coastguard Worker    const chunk2 = new Chunk();
492*61c4878aSAndroid Build Coastguard Worker    chunk2.setTransferId(4);
493*61c4878aSAndroid Build Coastguard Worker    chunk2.setOffset(8);
494*61c4878aSAndroid Build Coastguard Worker    chunk2.setPendingBytes(8);
495*61c4878aSAndroid Build Coastguard Worker    chunk2.setMaxChunkSizeBytes(8);
496*61c4878aSAndroid Build Coastguard Worker
497*61c4878aSAndroid Build Coastguard Worker    const chunk3 = new Chunk();
498*61c4878aSAndroid Build Coastguard Worker    chunk3.setTransferId(4);
499*61c4878aSAndroid Build Coastguard Worker    chunk3.setOffset(4); // Rewind
500*61c4878aSAndroid Build Coastguard Worker    chunk3.setPendingBytes(8);
501*61c4878aSAndroid Build Coastguard Worker    chunk3.setMaxChunkSizeBytes(8);
502*61c4878aSAndroid Build Coastguard Worker
503*61c4878aSAndroid Build Coastguard Worker    const chunk4 = new Chunk();
504*61c4878aSAndroid Build Coastguard Worker    chunk4.setTransferId(4);
505*61c4878aSAndroid Build Coastguard Worker    chunk4.setOffset(12); // Rewind
506*61c4878aSAndroid Build Coastguard Worker    chunk4.setPendingBytes(16);
507*61c4878aSAndroid Build Coastguard Worker    chunk4.setMaxChunkSizeBytes(16);
508*61c4878aSAndroid Build Coastguard Worker
509*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
510*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
511*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
512*61c4878aSAndroid Build Coastguard Worker
513*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
514*61c4878aSAndroid Build Coastguard Worker      [chunk1],
515*61c4878aSAndroid Build Coastguard Worker      [chunk2],
516*61c4878aSAndroid Build Coastguard Worker      [chunk3],
517*61c4878aSAndroid Build Coastguard Worker      [chunk4],
518*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
519*61c4878aSAndroid Build Coastguard Worker    ]);
520*61c4878aSAndroid Build Coastguard Worker
521*61c4878aSAndroid Build Coastguard Worker    await manager.write(4, textEncoder.encode('pigweed data transfer'));
522*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks).toHaveLength(5);
523*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[1].getData()).toEqual(textEncoder.encode('pigweed '));
524*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[2].getData()).toEqual(textEncoder.encode('data tra'));
525*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[3].getData()).toEqual(textEncoder.encode('eed data'));
526*61c4878aSAndroid Build Coastguard Worker    expect(sentChunks[4].getData()).toEqual(textEncoder.encode(' transfer'));
527*61c4878aSAndroid Build Coastguard Worker  });
528*61c4878aSAndroid Build Coastguard Worker
529*61c4878aSAndroid Build Coastguard Worker  it('write transfer bad offset', async () => {
530*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
531*61c4878aSAndroid Build Coastguard Worker
532*61c4878aSAndroid Build Coastguard Worker    const chunk1 = new Chunk();
533*61c4878aSAndroid Build Coastguard Worker    chunk1.setTransferId(4);
534*61c4878aSAndroid Build Coastguard Worker    chunk1.setOffset(0);
535*61c4878aSAndroid Build Coastguard Worker    chunk1.setPendingBytes(8);
536*61c4878aSAndroid Build Coastguard Worker    chunk1.setMaxChunkSizeBytes(8);
537*61c4878aSAndroid Build Coastguard Worker
538*61c4878aSAndroid Build Coastguard Worker    const chunk2 = new Chunk();
539*61c4878aSAndroid Build Coastguard Worker    chunk2.setTransferId(4);
540*61c4878aSAndroid Build Coastguard Worker    chunk2.setOffset(100); // larger offset than data
541*61c4878aSAndroid Build Coastguard Worker    chunk2.setPendingBytes(8);
542*61c4878aSAndroid Build Coastguard Worker    chunk2.setMaxChunkSizeBytes(8);
543*61c4878aSAndroid Build Coastguard Worker
544*61c4878aSAndroid Build Coastguard Worker    const completeChunk = new Chunk();
545*61c4878aSAndroid Build Coastguard Worker    completeChunk.setTransferId(4);
546*61c4878aSAndroid Build Coastguard Worker    completeChunk.setStatus(Status.OK);
547*61c4878aSAndroid Build Coastguard Worker
548*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [
549*61c4878aSAndroid Build Coastguard Worker      [chunk1],
550*61c4878aSAndroid Build Coastguard Worker      [chunk2],
551*61c4878aSAndroid Build Coastguard Worker      [completeChunk],
552*61c4878aSAndroid Build Coastguard Worker    ]);
553*61c4878aSAndroid Build Coastguard Worker
554*61c4878aSAndroid Build Coastguard Worker    await manager
555*61c4878aSAndroid Build Coastguard Worker      .write(4, textEncoder.encode('small data'))
556*61c4878aSAndroid Build Coastguard Worker      .then(() => {
557*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected succesful promise');
558*61c4878aSAndroid Build Coastguard Worker      })
559*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
560*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(4);
561*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.OUT_OF_RANGE]);
562*61c4878aSAndroid Build Coastguard Worker      });
563*61c4878aSAndroid Build Coastguard Worker  });
564*61c4878aSAndroid Build Coastguard Worker
565*61c4878aSAndroid Build Coastguard Worker  it('write transfer error', async () => {
566*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
567*61c4878aSAndroid Build Coastguard Worker
568*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
569*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(21);
570*61c4878aSAndroid Build Coastguard Worker    chunk.setStatus(Status.UNAVAILABLE);
571*61c4878aSAndroid Build Coastguard Worker
572*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [[chunk]]);
573*61c4878aSAndroid Build Coastguard Worker
574*61c4878aSAndroid Build Coastguard Worker    await manager
575*61c4878aSAndroid Build Coastguard Worker      .write(21, textEncoder.encode('no write'))
576*61c4878aSAndroid Build Coastguard Worker      .then(() => {
577*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected succesful promise');
578*61c4878aSAndroid Build Coastguard Worker      })
579*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
580*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(21);
581*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.UNAVAILABLE]);
582*61c4878aSAndroid Build Coastguard Worker      });
583*61c4878aSAndroid Build Coastguard Worker  });
584*61c4878aSAndroid Build Coastguard Worker
585*61c4878aSAndroid Build Coastguard Worker  it('write transfer server error', async () => {
586*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
587*61c4878aSAndroid Build Coastguard Worker
588*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
589*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(21);
590*61c4878aSAndroid Build Coastguard Worker    chunk.setStatus(Status.NOT_FOUND);
591*61c4878aSAndroid Build Coastguard Worker
592*61c4878aSAndroid Build Coastguard Worker    enqueueServerError(service.method('Write')!, Status.NOT_FOUND);
593*61c4878aSAndroid Build Coastguard Worker
594*61c4878aSAndroid Build Coastguard Worker    await manager
595*61c4878aSAndroid Build Coastguard Worker      .write(21, textEncoder.encode('server error'))
596*61c4878aSAndroid Build Coastguard Worker      .then(() => {
597*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected succesful promise');
598*61c4878aSAndroid Build Coastguard Worker      })
599*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
600*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(21);
601*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.INTERNAL]);
602*61c4878aSAndroid Build Coastguard Worker      });
603*61c4878aSAndroid Build Coastguard Worker  });
604*61c4878aSAndroid Build Coastguard Worker
605*61c4878aSAndroid Build Coastguard Worker  it('write transfer timeout after initial chunk', async () => {
606*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, 0.001, 4, 2);
607*61c4878aSAndroid Build Coastguard Worker
608*61c4878aSAndroid Build Coastguard Worker    await manager
609*61c4878aSAndroid Build Coastguard Worker      .write(22, textEncoder.encode('no server response!'))
610*61c4878aSAndroid Build Coastguard Worker      .then(() => {
611*61c4878aSAndroid Build Coastguard Worker        fail('unexpected succesful write');
612*61c4878aSAndroid Build Coastguard Worker      })
613*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
614*61c4878aSAndroid Build Coastguard Worker        expect(sentChunks).toHaveLength(3); // Initial chunk + two retries.
615*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(22);
616*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.DEADLINE_EXCEEDED]);
617*61c4878aSAndroid Build Coastguard Worker      });
618*61c4878aSAndroid Build Coastguard Worker  });
619*61c4878aSAndroid Build Coastguard Worker
620*61c4878aSAndroid Build Coastguard Worker  it('write transfer timeout after intermediate chunk', async () => {
621*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S, 4, 2);
622*61c4878aSAndroid Build Coastguard Worker
623*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
624*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(22);
625*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(10);
626*61c4878aSAndroid Build Coastguard Worker    chunk.setMaxChunkSizeBytes(5);
627*61c4878aSAndroid Build Coastguard Worker
628*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [[chunk]]);
629*61c4878aSAndroid Build Coastguard Worker
630*61c4878aSAndroid Build Coastguard Worker    await manager
631*61c4878aSAndroid Build Coastguard Worker      .write(22, textEncoder.encode('0123456789'))
632*61c4878aSAndroid Build Coastguard Worker      .then(() => {
633*61c4878aSAndroid Build Coastguard Worker        fail('unexpected succesful write');
634*61c4878aSAndroid Build Coastguard Worker      })
635*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
636*61c4878aSAndroid Build Coastguard Worker        const expectedChunk1 = new Chunk();
637*61c4878aSAndroid Build Coastguard Worker        expectedChunk1.setTransferId(22);
638*61c4878aSAndroid Build Coastguard Worker        expectedChunk1.setResourceId(22);
639*61c4878aSAndroid Build Coastguard Worker        expectedChunk1.setType(Chunk.Type.START);
640*61c4878aSAndroid Build Coastguard Worker        const expectedChunk2 = new Chunk();
641*61c4878aSAndroid Build Coastguard Worker        expectedChunk2.setTransferId(22);
642*61c4878aSAndroid Build Coastguard Worker        expectedChunk2.setData(textEncoder.encode('01234'));
643*61c4878aSAndroid Build Coastguard Worker        expectedChunk2.setType(Chunk.Type.DATA);
644*61c4878aSAndroid Build Coastguard Worker        const lastChunk = new Chunk();
645*61c4878aSAndroid Build Coastguard Worker        lastChunk.setTransferId(22);
646*61c4878aSAndroid Build Coastguard Worker        lastChunk.setData(textEncoder.encode('56789'));
647*61c4878aSAndroid Build Coastguard Worker        lastChunk.setOffset(5);
648*61c4878aSAndroid Build Coastguard Worker        lastChunk.setRemainingBytes(0);
649*61c4878aSAndroid Build Coastguard Worker        lastChunk.setType(Chunk.Type.DATA);
650*61c4878aSAndroid Build Coastguard Worker
651*61c4878aSAndroid Build Coastguard Worker        const expectedChunks = [
652*61c4878aSAndroid Build Coastguard Worker          expectedChunk1,
653*61c4878aSAndroid Build Coastguard Worker          expectedChunk2,
654*61c4878aSAndroid Build Coastguard Worker          lastChunk,
655*61c4878aSAndroid Build Coastguard Worker          lastChunk, // retry 1
656*61c4878aSAndroid Build Coastguard Worker          lastChunk, // retry 2
657*61c4878aSAndroid Build Coastguard Worker        ];
658*61c4878aSAndroid Build Coastguard Worker
659*61c4878aSAndroid Build Coastguard Worker        expect(sentChunks).toEqual(expectedChunks);
660*61c4878aSAndroid Build Coastguard Worker
661*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(22);
662*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.DEADLINE_EXCEEDED]);
663*61c4878aSAndroid Build Coastguard Worker      });
664*61c4878aSAndroid Build Coastguard Worker  });
665*61c4878aSAndroid Build Coastguard Worker
666*61c4878aSAndroid Build Coastguard Worker  it('write zero pending bytes is internal error', async () => {
667*61c4878aSAndroid Build Coastguard Worker    const manager = new Manager(service, DEFAULT_TIMEOUT_S);
668*61c4878aSAndroid Build Coastguard Worker
669*61c4878aSAndroid Build Coastguard Worker    const chunk = new Chunk();
670*61c4878aSAndroid Build Coastguard Worker    chunk.setTransferId(23);
671*61c4878aSAndroid Build Coastguard Worker    chunk.setPendingBytes(0);
672*61c4878aSAndroid Build Coastguard Worker
673*61c4878aSAndroid Build Coastguard Worker    enqueueServerResponses(service.method('Write')!, [[chunk]]);
674*61c4878aSAndroid Build Coastguard Worker
675*61c4878aSAndroid Build Coastguard Worker    await manager
676*61c4878aSAndroid Build Coastguard Worker      .write(23, textEncoder.encode('no write'))
677*61c4878aSAndroid Build Coastguard Worker      .then(() => {
678*61c4878aSAndroid Build Coastguard Worker        fail('Unexpected succesful promise');
679*61c4878aSAndroid Build Coastguard Worker      })
680*61c4878aSAndroid Build Coastguard Worker      .catch((error) => {
681*61c4878aSAndroid Build Coastguard Worker        expect(error.id).toEqual(23);
682*61c4878aSAndroid Build Coastguard Worker        expect(Status[error.status]).toEqual(Status[Status.INTERNAL]);
683*61c4878aSAndroid Build Coastguard Worker      });
684*61c4878aSAndroid Build Coastguard Worker  });
685*61c4878aSAndroid Build Coastguard Worker});
686