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