• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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