1// Copyright 2022 The Pigweed Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); you may not 4// use this file except in compliance with the License. You may obtain a copy of 5// the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12// License for the specific language governing permissions and limitations under 13// the License. 14 15/* eslint-env browser */ 16 17import { SomeMessage } from 'pigweedjs/protos/pw_rpc/ts/test2_pb'; 18 19import { Call } from './call'; 20import { Channel, Method, Service } from './descriptors'; 21import { PendingCalls, Rpc } from './rpc_classes'; 22 23class FakeRpc { 24 readonly channel: any = undefined; 25 readonly service: any = undefined; 26 readonly method: any = undefined; 27 28 getIdSet(callId: number): [number, number, number, number] { 29 return [1, 2, 3, callId]; 30 } 31 32 getIdString(callId: number): string { 33 return '1.2.3.' + callId; 34 } 35} 36 37describe('Call', () => { 38 let call: Call; 39 40 beforeEach(() => { 41 const noop = () => { 42 // Do nothing. 43 }; 44 const pendingCalls = new PendingCalls(); 45 const rpc = new FakeRpc(); 46 call = new Call(pendingCalls, rpc, noop, noop, noop); 47 }); 48 49 function newMessage(magicNumber = 1): SomeMessage { 50 const message = new SomeMessage(); 51 message.setMagicNumber(magicNumber); 52 return message; 53 } 54 55 it('getResponse returns all responses.', async () => { 56 const message1 = newMessage(1); 57 const message2 = newMessage(2); 58 const message3 = newMessage(3); 59 60 // Queue three responses 61 call.handleResponse(message1); 62 call.handleResponse(message2); 63 call.handleResponse(message3); 64 65 let responses = call.getResponses(2); 66 expect((await responses.next()).value).toEqual(message1); 67 expect((await responses.next()).value).toEqual(message2); 68 expect((await responses.next()).done).toEqual(true); 69 70 responses = call.getResponses(1); 71 expect((await responses.next()).value).toEqual(message3); 72 expect((await responses.next()).done).toEqual(true); 73 }); 74 75 it('getResponse early returns on stream end.', async () => { 76 const message = newMessage(); 77 const responses = call.getResponses(2); 78 79 // Queue one response and an early completion. 80 call.handleResponse(message); 81 call.handleCompletion(0); 82 83 expect((await responses.next()).value).toEqual(message); 84 expect((await responses.next()).done).toEqual(true); 85 }); 86 87 it('getResponse promise is rejected on stream error.', async () => { 88 expect.assertions(2); 89 const message = newMessage(); 90 const responses = call.getResponses(3); 91 92 call.handleResponse(message); 93 expect((await responses.next()).value).toEqual(message); 94 95 call.handleResponse(message); 96 call.handleError(1); 97 98 // Promise is rejected as soon as an error is received, even if there is a 99 // response in the queue. 100 responses.next().catch((e: Error) => { 101 expect(e.name).toEqual('TypeError'); 102 }); 103 }); 104 105 it('getResponse waits if queue is empty', async () => { 106 const message1 = newMessage(1); 107 const message2 = newMessage(2); 108 const responses = call.getResponses(2); 109 110 // Queue two responses after a small delay 111 setTimeout(() => { 112 call.handleResponse(message1); 113 call.handleResponse(message2); 114 call.handleCompletion(0); 115 expect(call.completed).toEqual(true); 116 }, 200); 117 118 expect(call.completed).toEqual(false); 119 expect((await responses.next()).value).toEqual(message1); 120 expect((await responses.next()).value).toEqual(message2); 121 expect((await responses.next()).done).toEqual(true); 122 }); 123 124 it('getResponse without count fetches all results', async () => { 125 const message1 = newMessage(1); 126 const message2 = newMessage(2); 127 const responses = call.getResponses(); 128 129 call.handleResponse(message1); 130 expect((await responses.next()).value).toEqual(message1); 131 132 setTimeout(() => { 133 call.handleResponse(message2); 134 call.handleCompletion(0); 135 expect(call.completed).toEqual(true); 136 }, 200); 137 138 expect(call.completed).toEqual(false); 139 expect((await responses.next()).value).toEqual(message2); 140 expect((await responses.next()).done).toEqual(true); 141 }); 142}); 143