| // Copyright 2021 The Pigweed Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy of |
| // the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| |
| /* eslint-env browser, jasmine */ |
| import 'jasmine'; |
| |
| import {PacketType, RpcPacket} from 'packet_proto_tspb/packet_proto_tspb_pb/pw_rpc/internal/packet_pb' |
| import {Library} from 'pigweed/pw_protobuf_compiler/ts/proto_lib'; |
| import {Status} from 'pigweed/pw_status/ts/status'; |
| import {Request} from 'test_protos_tspb/test_protos_tspb_pb/pw_rpc/ts/test2_pb' |
| |
| import {Client} from './client'; |
| import {Channel} from './descriptors'; |
| import * as packets from './packets'; |
| |
| const TEST_PROTO_PATH = 'pw_rpc/ts/test_protos-descriptor-set.proto.bin'; |
| |
| describe('Client', () => { |
| let lib: Library; |
| let client: Client; |
| let lastPacketSent: RpcPacket; |
| |
| beforeEach(async () => { |
| lib = await Library.fromFileDescriptorSet( |
| TEST_PROTO_PATH, 'test_protos_tspb'); |
| const channels = [new Channel(1, savePacket), new Channel(5)]; |
| client = Client.fromProtoSet(channels, lib); |
| }); |
| |
| function savePacket(packetBytes: Uint8Array): void { |
| lastPacketSent = RpcPacket.deserializeBinary(packetBytes); |
| } |
| |
| it('channel returns undefined for empty list', () => { |
| const channels = Array<Channel>(); |
| const emptyChannelClient = Client.fromProtoSet(channels, lib); |
| expect(emptyChannelClient.channel()).toBeUndefined(); |
| }); |
| |
| it('fetches channel or returns undefined', () => { |
| expect(client.channel(1)!.channel.id).toEqual(1); |
| expect(client.channel(5)!.channel.id).toEqual(5); |
| expect(client.channel()!.channel.id).toEqual(1); |
| expect(client.channel(2)).toBeUndefined(); |
| }); |
| |
| it('ChannelClient fetches method by name', () => { |
| const channel = client.channel()!; |
| const stub = channel.methodStub('pw.rpc.test1.TheTestService.SomeUnary')!; |
| expect(stub.method.name).toEqual('SomeUnary'); |
| }) |
| |
| it('ChannelClient for unknown name returns undefined', () => { |
| const channel = client.channel()!; |
| expect(channel.methodStub('')).toBeUndefined(); |
| expect(channel.methodStub('pw.rpc.test1.Garbage.SomeUnary')) |
| .toBeUndefined(); |
| expect(channel.methodStub('pw.rpc.test1.TheTestService.Garbage')) |
| .toBeUndefined(); |
| }) |
| |
| it('processPacket with invalid proto data', () => { |
| const textEncoder = new TextEncoder(); |
| const data = textEncoder.encode('NOT a packet!'); |
| expect(client.processPacket(data)).toEqual(Status.DATA_LOSS) |
| }); |
| |
| it('processPacket not for client', () => { |
| const packet = new RpcPacket(); |
| packet.setType(PacketType.REQUEST); |
| const processStatus = client.processPacket(packet.serializeBinary()); |
| expect(processStatus).toEqual(Status.INVALID_ARGUMENT); |
| }); |
| |
| it('processPacket for unrecognized channel', () => { |
| const packet = packets.encodeResponse([123, 456, 789], new Request()); |
| expect(client.processPacket(packet)).toEqual(Status.NOT_FOUND); |
| }); |
| |
| it('processPacket for unrecognized service', () => { |
| const packet = packets.encodeResponse([1, 456, 789], new Request()); |
| const status = client.processPacket(packet); |
| expect(client.processPacket(packet)).toEqual(Status.OK); |
| |
| expect(lastPacketSent.getChannelId()).toEqual(1); |
| expect(lastPacketSent.getServiceId()).toEqual(456); |
| expect(lastPacketSent.getMethodId()).toEqual(789); |
| expect(lastPacketSent.getType()).toEqual(PacketType.CLIENT_ERROR); |
| expect(lastPacketSent.getStatus()).toEqual(Status.NOT_FOUND); |
| }); |
| |
| it('processPacket for unrecognized method', () => { |
| const service = client.services.values().next().value; |
| |
| const packet = packets.encodeResponse([1, service.id, 789], new Request()); |
| const status = client.processPacket(packet); |
| expect(client.processPacket(packet)).toEqual(Status.OK); |
| |
| expect(lastPacketSent.getChannelId()).toEqual(1); |
| expect(lastPacketSent.getServiceId()).toEqual(service.id); |
| expect(lastPacketSent.getMethodId()).toEqual(789); |
| expect(lastPacketSent.getType()).toEqual(PacketType.CLIENT_ERROR); |
| expect(lastPacketSent.getStatus()).toEqual(Status.NOT_FOUND); |
| }); |
| |
| it('processPacket for non-pending method', () => { |
| const service = client.services.values().next().value; |
| const method = service.methods.values().next().value; |
| |
| const packet = |
| packets.encodeResponse([1, service.id, method.id], new Request()); |
| const status = client.processPacket(packet); |
| expect(client.processPacket(packet)).toEqual(Status.OK); |
| |
| expect(lastPacketSent.getChannelId()).toEqual(1); |
| expect(lastPacketSent.getServiceId()).toEqual(service.id); |
| expect(lastPacketSent.getMethodId()).toEqual(method.id); |
| expect(lastPacketSent.getType()).toEqual(PacketType.CLIENT_ERROR); |
| expect(lastPacketSent.getStatus()).toEqual(Status.FAILED_PRECONDITION); |
| }); |
| }) |