gRPC

Common tests for gRPC APIs

Features of this Example

  • Simple RPC

  • Server-side streaming and client-side streaming RPC

  • Bidirectional streaming RPC

Walkthrough

This example was referenced in a walkthrough about gRPC Health Checks and Uptime.

Try it out

Repo is available here.

# Clone example
git clone https://github.com/assertedio/graphql-uptime

# Enter directory and install
cd node-uptime/
npm install

# Run asserted tests
npm run test:asrtd

Tests

Can also be viewed on github here.

const { expect } = require('chai');
const Bluebird = require('bluebird');
const path = require('path');
const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');

const PROTO_PATH = path.join(__dirname, '../protos/route_guide.proto');
const DATA = require('../route_guide/route_guide_db.json');

const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});
const { routeguide } = grpc.loadPackageDefinition(packageDefinition);
const client = new routeguide.RouteGuide('localhost:50051', grpc.credentials.createInsecure());

const sortByName = ({ name: name1 }, { name: name2 }) => name1.localeCompare(name2);

describe('grpc api tests', () => {
  it('get feature - simple rpc', async () => {
    const point1 = {
      latitude: 409146138,
      longitude: -746188906,
    };
    const point2 = {
      latitude: 0,
      longitude: 0,
    };

    const expectedFeature1 = {
      name: 'Berkshire Valley Management Area Trail, Jefferson, NJ, USA',
      location: {
        latitude: 409146138,
        longitude: -746188906,
      },
    };
    const feature1 = await Bluebird.fromCallback((cb) => client.getFeature(point1, cb));
    expect(feature1).to.eql(expectedFeature1);

    const expectedFeature2 = {
      name: '',
      location: {
        latitude: 0,
        longitude: 0,
      },
    };
    const feature2 = await Bluebird.fromCallback((cb) => client.getFeature(point2, cb));
    expect(feature2).to.eql(expectedFeature2);
  });

  it('list features - server-side streaming rpc', async () => {
    const rectangle = {
      lo: {
        latitude: 400000000,
        longitude: -750000000,
      },
      hi: {
        latitude: 420000000,
        longitude: -730000000,
      },
    };

    const call = client.listFeatures(rectangle);

    const features = [];

    call.on('data', (feature) => features.push(feature));
    await Bluebird.fromCallback((cb) => call.on('end', cb));

    expect(features.length).to.eql(64);
    expect(features.sort(sortByName)).to.eql(DATA.sort(sortByName).filter(({ name }) => name.length > 0));
  });

  it('record route - client-side streaming rpc', async () => {
    const num_points = 10;

    let call;
    const recorded = Bluebird.fromCallback((callback) => (call = client.recordRoute(callback)));

    for (let i = 0; i < num_points; i++) {
      const {
        location: { latitude, longitude },
      } = DATA[30 + i];

      call.write({ latitude, longitude });
      // eslint-disable-next-line no-await-in-loop
      await Bluebird.delay(100);
    }

    await call.end();
    const stats = await recorded;

    expect(stats).to.eql({
      point_count: 10,
      feature_count: 4,
      distance: 455927,
      elapsed_time: 1,
    });
  });

  it('route chat - bidirectional streaming RPC', async () => {
    const call = client.routeChat();

    const gotNotes = [];
    call.on('data', (note) => gotNotes.push(note));

    const result = Bluebird.fromCallback((callback) => call.on('end', callback));

    const notes = [
      {
        location: {
          latitude: 0,
          longitude: 0,
        },
        message: 'First message',
      },
      {
        location: {
          latitude: 0,
          longitude: 1,
        },
        message: 'Second message',
      },
      {
        location: {
          latitude: 1,
          longitude: 0,
        },
        message: 'Third message',
      },
      {
        location: {
          latitude: 0,
          longitude: 0,
        },
        message: 'Fourth message',
      },
    ];

    notes.forEach((note) => call.write(note));
    call.end();

    await result;

    const expectedNotes = [
      {
        location: {
          latitude: 0,
          longitude: 0,
        },
        message: 'First message',
      },
    ];

    expect(gotNotes).to.eql(expectedNotes);
  });
});

Last updated