Added test coverage for GET /v1/healthy

Signed-off-by: Miguel Casqueira <miguel@balena.io>
This commit is contained in:
Miguel Casqueira 2020-05-19 21:27:36 -04:00
parent 15f2ac8d69
commit f494178b2b
3 changed files with 77 additions and 5 deletions

View File

@ -1,7 +1,9 @@
import { expect } from 'chai';
import { spy } from 'sinon';
import { spy, stub, SinonStub } from 'sinon';
import * as supertest from 'supertest';
import APIBinder from '../src/api-binder';
import DeviceState from '../src/device-state';
import Log from '../src/lib/supervisor-console';
import SupervisorAPI from '../src/supervisor-api';
import sampleResponses = require('./data/device-api-responses.json');
@ -17,9 +19,15 @@ const ALLOWED_INTERFACES = ['lo']; // Only need loopback since this is for testi
describe('SupervisorAPI', () => {
let api: SupervisorAPI;
let healthCheckStubs: SinonStub[];
const request = supertest(`http://127.0.0.1:${mockedOptions.listenPort}`);
before(async () => {
// Stub health checks so we can modify them whenever needed
healthCheckStubs = [
stub(APIBinder.prototype, 'healthcheck'),
stub(DeviceState.prototype, 'healthcheck'),
];
// The mockedAPI contains stubs that might create unexpected results
// See the module to know what has been stubbed
api = await mockedAPI.create();
@ -39,6 +47,8 @@ describe('SupervisorAPI', () => {
throw e;
}
}
// Restore healthcheck stubs
healthCheckStubs.forEach((hc) => hc.restore);
// Remove any test data generated
await mockedAPI.cleanUp();
});
@ -56,7 +66,43 @@ describe('SupervisorAPI', () => {
});
});
describe.skip('V1 endpoints', () => {
describe('V1 endpoints', () => {
describe('GET /v1/healthy', () => {
it('returns OK because all checks pass', async () => {
// Make all healthChecks pass
healthCheckStubs.forEach((hc) => hc.resolves(true));
await request
.get('/v1/healthy')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${VALID_SECRET}`)
.expect(sampleResponses.V1.GET['/healthy'].statusCode)
.then((response) => {
expect(response.body).to.deep.equal(
sampleResponses.V1.GET['/healthy'].body,
);
expect(response.text).to.deep.equal(
sampleResponses.V1.GET['/healthy'].text,
);
});
});
it('Fails because some checks did not pass', async () => {
// Make one of the healthChecks fail
healthCheckStubs[0].resolves(false);
await request
.get('/v1/healthy')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${VALID_SECRET}`)
.expect(sampleResponses.V1.GET['/healthy [2]'].statusCode)
.then((response) => {
expect(response.body).to.deep.equal(
sampleResponses.V1.GET['/healthy [2]'].body,
);
expect(response.text).to.deep.equal(
sampleResponses.V1.GET['/healthy [2]'].text,
);
});
});
});
// TODO: add tests for V1 endpoints
});

View File

@ -1,5 +1,18 @@
{
"V1": {},
"V1": {
"GET": {
"/healthy": {
"statusCode": 200,
"body": {},
"text": "OK"
},
"/healthy [2]": {
"statusCode": 500,
"body": {},
"text": "Unhealthy"
}
}
},
"V2": {
"GET": {
"/device/vpn": {

View File

@ -11,6 +11,7 @@ import Config from '../../src/config';
import * as db from '../../src/db';
import { createV1Api } from '../../src/device-api/v1';
import { createV2Api } from '../../src/device-api/v2';
import APIBinder from '../../src/api-binder';
import DeviceState from '../../src/device-state';
import EventTracker from '../../src/event-tracker';
import SupervisorAPI from '../../src/supervisor-api';
@ -67,7 +68,12 @@ const STUBBED_VALUES = {
async function create(): Promise<SupervisorAPI> {
// Get SupervisorAPI construct options
const { config, eventTracker, deviceState } = await createAPIOpts();
const {
config,
eventTracker,
deviceState,
apiBinder,
} = await createAPIOpts();
// Stub functions
setupStubs();
// Create ApplicationManager
@ -83,7 +89,7 @@ async function create(): Promise<SupervisorAPI> {
config,
eventTracker,
routers: [buildRoutes(appManager)],
healthchecks: [],
healthchecks: [deviceState.healthcheck, apiBinder.healthcheck],
});
// Return SupervisorAPI that is not listening yet
return api;
@ -115,10 +121,16 @@ async function createAPIOpts(): Promise<SupervisorAPIOpts> {
logger: null as any,
apiBinder: null as any,
});
const apiBinder = new APIBinder({
config: mockedConfig,
eventTracker: tracker,
logger: null as any,
});
return {
config: mockedConfig,
eventTracker: tracker,
deviceState,
apiBinder,
};
}
@ -168,6 +180,7 @@ interface SupervisorAPIOpts {
config: Config;
eventTracker: EventTracker;
deviceState: DeviceState;
apiBinder: APIBinder;
}
export = { create, cleanUp, STUBBED_VALUES };