From 9443281dec0ec8b6ca6a93b820f43eb07059ac35 Mon Sep 17 00:00:00 2001 From: Christina Ying Wang Date: Tue, 5 Dec 2023 14:04:34 -0800 Subject: [PATCH] Separate routes & actions, add tests for GET /v2/version Signed-off-by: Christina Ying Wang --- src/config/functions.ts | 3 +-- src/device-api/actions.ts | 10 +++++++++ src/device-api/v2.ts | 16 ++++++++------ src/lib/request.ts | 3 +-- src/lib/supervisor-version.ts | 13 ++++++------ src/supervisor.ts | 6 +++--- test/integration/device-api/v2.spec.ts | 27 ++++++++++++++++++++++++ test/legacy/10-api-binder.spec.ts | 2 +- test/unit/device-api/actions.spec.ts | 7 ++++++ test/unit/lib/contracts.spec.ts | 2 +- test/unit/lib/supervisor-version.spec.ts | 9 ++++++++ 11 files changed, 76 insertions(+), 22 deletions(-) create mode 100644 test/unit/lib/supervisor-version.spec.ts diff --git a/src/config/functions.ts b/src/config/functions.ts index af3330cfc..374500be9 100644 --- a/src/config/functions.ts +++ b/src/config/functions.ts @@ -1,14 +1,13 @@ import * as _ from 'lodash'; import * as memoizee from 'memoizee'; -import supervisorVersion = require('../lib/supervisor-version'); - import * as config from '.'; import * as constants from '../lib/constants'; import * as osRelease from '../lib/os-release'; import * as macAddress from '../lib/mac-address'; import * as hostUtils from '../lib/host-utils'; import log from '../lib/supervisor-console'; +import { supervisorVersion } from '../lib/supervisor-version'; export const fnSchema = { version: () => { diff --git a/src/device-api/actions.ts b/src/device-api/actions.ts index f1a1f4fde..c4300491b 100644 --- a/src/device-api/actions.ts +++ b/src/device-api/actions.ts @@ -28,6 +28,7 @@ import { BadRequestError, } from '../lib/errors'; import { JournalctlOpts, spawnJournalctl } from '../lib/journald'; +import { supervisorVersion } from '../lib/supervisor-version'; /** * Run an array of healthchecks, outputting whether all passed or not @@ -474,3 +475,12 @@ export const cleanupVolumes = async ( export const getLogStream = (opts: JournalctlOpts) => { return spawnJournalctl(opts); }; + +/** + * Get version of running Supervisor + * Used by: + * - GET /v2/version + */ +export const getSupervisorVersion = () => { + return supervisorVersion; +}; diff --git a/src/device-api/v2.ts b/src/device-api/v2.ts index 2fd62d088..4d85e1286 100644 --- a/src/device-api/v2.ts +++ b/src/device-api/v2.ts @@ -13,7 +13,6 @@ import * as logger from '../logger'; import * as images from '../compose/images'; import * as serviceManager from '../compose/service-manager'; import log from '../lib/supervisor-console'; -import supervisorVersion = require('../lib/supervisor-version'); import { checkInt, checkString, checkTruthy } from '../lib/validation'; import { isNotFoundError, @@ -378,11 +377,16 @@ router.get('/v2/local/logs', async (_req, res) => { listenStream.pipe(res); }); -router.get('/v2/version', (_req, res) => { - res.status(200).json({ - status: 'success', - version: supervisorVersion, - }); +router.get('/v2/version', (_req, res, next) => { + try { + const supervisorVersion = actions.getSupervisorVersion(); + return res.status(200).json({ + status: 'success', + version: supervisorVersion, + }); + } catch (e: unknown) { + next(e); + } }); router.get('/v2/containerId', async (req: AuthorizedRequest, res) => { diff --git a/src/lib/request.ts b/src/lib/request.ts index cbd7c4fb8..e5d883197 100644 --- a/src/lib/request.ts +++ b/src/lib/request.ts @@ -5,8 +5,7 @@ import * as resumableRequestLib from 'resumable-request'; import * as constants from './constants'; import * as osRelease from './os-release'; - -import supervisorVersion = require('./supervisor-version'); +import { supervisorVersion } from './supervisor-version'; export { requestLib }; diff --git a/src/lib/supervisor-version.ts b/src/lib/supervisor-version.ts index 6d95b7972..fd1e3f020 100644 --- a/src/lib/supervisor-version.ts +++ b/src/lib/supervisor-version.ts @@ -1,10 +1,9 @@ -import * as _ from 'lodash'; - -import * as packageJson from '../../package.json'; -let version = packageJson.version; +import { version as packageJsonVersion } from '../../package.json'; +let supervisorVersion = packageJsonVersion; const tagExtra = process.env.SUPERVISOR_TAG_EXTRA; -if (!_.isEmpty(tagExtra)) { - version += '+' + tagExtra; +if (tagExtra != null) { + supervisorVersion += '+' + tagExtra; } -export = version; + +export { supervisorVersion }; diff --git a/src/supervisor.ts b/src/supervisor.ts index 03d5becfc..9f8c1ba41 100644 --- a/src/supervisor.ts +++ b/src/supervisor.ts @@ -12,7 +12,7 @@ import { initializeContractRequirements } from './lib/contracts'; import { normaliseLegacyDatabase } from './lib/legacy'; import * as osRelease from './lib/os-release'; import log from './lib/supervisor-console'; -import version = require('./lib/supervisor-version'); +import { supervisorVersion } from './lib/supervisor-version'; import * as avahi from './lib/avahi'; import * as firewall from './lib/firewall'; @@ -32,7 +32,7 @@ export class Supervisor { private api: SupervisorAPI; public async init() { - log.info(`Supervisor v${version} starting up...`); + log.info(`Supervisor v${supervisorVersion} starting up...`); await db.initialized(); await config.initialized(); @@ -43,7 +43,7 @@ export class Supervisor { const conf = await config.getMany(startupConfigFields); initializeContractRequirements({ - supervisorVersion: version, + supervisorVersion, deviceType: await config.get('deviceType'), deviceArch: await config.get('deviceArch'), l4tVersion: await osRelease.getL4tVersion(), diff --git a/test/integration/device-api/v2.spec.ts b/test/integration/device-api/v2.spec.ts index 42000b997..0dff7a3ef 100644 --- a/test/integration/device-api/v2.spec.ts +++ b/test/integration/device-api/v2.spec.ts @@ -13,6 +13,7 @@ import { NotFoundError, BadRequestError, } from '~/lib/errors'; +import { supervisorVersion } from '~/src/lib/supervisor-version'; // All routes that require Authorization are integration tests due to // the api-key module relying on the database. @@ -802,4 +803,30 @@ describe('device-api/v2', () => { .expect(503); }); }); + + describe('GET /v2/version', () => { + let getSupervisorVersionStub: SinonStub; + before(() => { + getSupervisorVersionStub = stub(actions, 'getSupervisorVersion'); + }); + after(() => { + getSupervisorVersionStub.restore(); + }); + + it('responds with 200 and Supervisor version', async () => { + getSupervisorVersionStub.callThrough(); + await request(api) + .get('/v2/version') + .set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`) + .expect(200, { status: 'success', version: supervisorVersion }); + }); + + it('responds with 503 if an error occurred', async () => { + getSupervisorVersionStub.throws(new Error()); + await request(api) + .get('/v2/version') + .set('Authorization', `Bearer ${await deviceApi.getGlobalApiKey()}`) + .expect(503); + }); + }); }); diff --git a/test/legacy/10-api-binder.spec.ts b/test/legacy/10-api-binder.spec.ts index 758d0ef47..b33669a9e 100644 --- a/test/legacy/10-api-binder.spec.ts +++ b/test/legacy/10-api-binder.spec.ts @@ -13,7 +13,7 @@ import { schema } from '~/src/config/schema'; import ConfigJsonConfigBackend from '~/src/config/configJson'; import * as TargetState from '~/src/device-state/target-state'; import * as ApiHelper from '~/lib/api-helper'; -import supervisorVersion = require('~/lib/supervisor-version'); +import { supervisorVersion } from '~/lib/supervisor-version'; import * as eventTracker from '~/src/event-tracker'; import * as constants from '~/lib/constants'; diff --git a/test/unit/device-api/actions.spec.ts b/test/unit/device-api/actions.spec.ts index 8a846faee..45cf7c8b8 100644 --- a/test/unit/device-api/actions.spec.ts +++ b/test/unit/device-api/actions.spec.ts @@ -3,6 +3,7 @@ import { spy, useFakeTimers, stub, SinonStub } from 'sinon'; import * as hostConfig from '~/src/host-config'; import * as actions from '~/src/device-api/actions'; +import { supervisorVersion } from '~/lib/supervisor-version'; import blink = require('~/lib/blink'); describe('device-api/actions', () => { @@ -67,4 +68,10 @@ describe('device-api/actions', () => { expect(await actions.getHostConfig()).to.deep.equal(conf); }); }); + + describe('gets Supervisor version', () => { + it('gets Supervisor version from package.json', () => { + expect(actions.getSupervisorVersion()).to.equal(supervisorVersion); + }); + }); }); diff --git a/test/unit/lib/contracts.spec.ts b/test/unit/lib/contracts.spec.ts index ee50b649b..594ee5843 100644 --- a/test/unit/lib/contracts.spec.ts +++ b/test/unit/lib/contracts.spec.ts @@ -3,7 +3,7 @@ import * as semver from 'semver'; import { SinonStub, stub } from 'sinon'; import * as osRelease from '~/lib/os-release'; -import supervisorVersion = require('~/lib/supervisor-version'); +import { supervisorVersion } from '~/lib/supervisor-version'; import * as fsUtils from '~/lib/fs-utils'; describe('lib/contracts', () => { diff --git a/test/unit/lib/supervisor-version.spec.ts b/test/unit/lib/supervisor-version.spec.ts new file mode 100644 index 000000000..da7ea62ad --- /dev/null +++ b/test/unit/lib/supervisor-version.spec.ts @@ -0,0 +1,9 @@ +import { expect } from 'chai'; +import { version as packageJsonVersion } from '~/src/../package.json'; +import { supervisorVersion } from '~/lib/supervisor-version'; + +describe('lib/supervisor-version', () => { + it('should return the version from package.json', () => { + expect(supervisorVersion).to.equal(packageJsonVersion); + }); +});