Use identify action for POST /v1/blink

Signed-off-by: Christina Ying Wang <christina@balena.io>
This commit is contained in:
Christina Ying Wang 2022-10-26 15:12:35 -07:00
parent e351ed9803
commit c7db3189ad
5 changed files with 50 additions and 53 deletions

View File

@ -1,4 +1,6 @@
import * as eventTracker from '../event-tracker';
import log from '../lib/supervisor-console';
import blink = require('../lib/blink');
/**
* Run an array of healthchecks, outputting whether all passed or not
@ -22,3 +24,15 @@ export const runHealthchecks = async (
return true;
};
/**
* Identify a device by blinking or some other method, if supported
* Used by:
* - POST /v1/blink
*/
const DEFAULT_IDENTIFY_DURATION = 15000;
export const identify = (ms: number = DEFAULT_IDENTIFY_DURATION) => {
eventTracker.track('Device blink');
blink.pattern.start();
setTimeout(blink.pattern.stop, ms);
};

View File

@ -4,10 +4,8 @@ import * as _ from 'lodash';
import * as middleware from './middleware';
import * as apiKeys from './api-keys';
import * as actions from './actions';
import * as eventTracker from '../event-tracker';
import { reportCurrentState } from '../device-state';
import proxyvisor from '../proxyvisor';
import blink = require('../lib/blink');
import log from '../lib/supervisor-console';
import type { Server } from 'http';
@ -57,9 +55,7 @@ export class SupervisorAPI {
this.api.use(middleware.auth);
this.api.post('/v1/blink', (_req, res) => {
eventTracker.track('Device blink');
blink.pattern.start();
setTimeout(blink.pattern.stop, 15000);
actions.identify();
return res.sendStatus(200);
});

View File

@ -50,4 +50,17 @@ describe('device-api/v1', () => {
await request(api).get('/v1/healthy').expect(500);
});
});
describe('POST /v1/blink', () => {
// Actions are tested elsewhere so we can stub the dependency here
before(() => stub(actions, 'identify'));
after(() => (actions.identify as SinonStub).restore());
it('responds with 200', async () => {
await request(api)
.post('/v1/blink')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.expect(200);
});
});
});

View File

@ -1,13 +1,6 @@
import * as _ from 'lodash';
import { expect } from 'chai';
import {
stub,
spy,
useFakeTimers,
SinonStub,
SinonSpy,
SinonFakeTimers,
} from 'sinon';
import { stub, spy, SinonStub, SinonSpy } from 'sinon';
import * as supertest from 'supertest';
import * as path from 'path';
import { promises as fs } from 'fs';
@ -28,7 +21,6 @@ import * as dbus from '~/lib/dbus';
import * as updateLock from '~/lib/update-lock';
import * as TargetState from '~/src/device-state/target-state';
import * as targetStateCache from '~/src/device-state/target-state-cache';
import blink = require('~/lib/blink');
import constants = require('~/lib/constants');
import * as deviceAPIActions from '~/src/device-api/common';
import { UpdatesLockedError } from '~/lib/errors';
@ -680,45 +672,6 @@ describe('SupervisorAPI [V1 Endpoints]', () => {
});
});
describe('POST /v1/blink', () => {
// Further blink function-specific testing located in 07-blink.spec.ts
it('responds with code 200 and empty body', async () => {
await request
.post('/v1/blink')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.expect(sampleResponses.V1.POST['/blink'].statusCode)
.then((response) => {
expect(response.body).to.deep.equal(
sampleResponses.V1.POST['/blink'].body,
);
expect(response.text).to.deep.equal(
sampleResponses.V1.POST['/blink'].text,
);
});
});
it('directs device to blink for 15000ms (hardcoded length)', async () => {
const blinkStartSpy: SinonSpy = spy(blink.pattern, 'start');
const blinkStopSpy: SinonSpy = spy(blink.pattern, 'stop');
const clock: SinonFakeTimers = useFakeTimers();
await request
.post('/v1/blink')
.set('Accept', 'application/json')
.set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`)
.then(() => {
expect(blinkStartSpy.callCount).to.equal(1);
clock.tick(15000);
expect(blinkStopSpy.callCount).to.equal(1);
});
blinkStartSpy.restore();
blinkStopSpy.restore();
clock.restore();
});
});
describe('POST /v1/regenerate-api-key', () => {
it('returns a valid new API key', async () => {
const refreshKeySpy: SinonSpy = spy(apiKeys, 'refreshKey');

View File

@ -1,6 +1,8 @@
import { expect } from 'chai';
import { spy, useFakeTimers } from 'sinon';
import * as actions from '~/src/device-api/actions';
import blink = require('~/lib/blink');
describe('device-api/actions', () => {
describe('runs healthchecks', () => {
@ -22,4 +24,23 @@ describe('device-api/actions', () => {
expect(await actions.runHealthchecks([taskError, taskError])).to.be.false;
});
});
describe('identifies device', () => {
// This suite doesn't test that the blink submodule writes to the correct
// led file location on host. That test should be part of the blink module.
it('directs device to blink for set duration', async () => {
const blinkStartSpy = spy(blink.pattern, 'start');
const blinkStopSpy = spy(blink.pattern, 'stop');
const clock = useFakeTimers();
actions.identify();
expect(blinkStartSpy.callCount).to.equal(1);
clock.tick(15000);
expect(blinkStopSpy.callCount).to.equal(1);
blinkStartSpy.restore();
blinkStopSpy.restore();
clock.restore();
});
});
});