From acfcd6931f801492974fb64d6ccf53f40a2b1913 Mon Sep 17 00:00:00 2001 From: Robert DeLuca Date: Wed, 3 Apr 2019 15:14:43 -0500 Subject: [PATCH 1/4] Implement healthcheck command --- src/commands/health-check.ts | 37 +++++++++++++++++++++ src/utils/health-checker.ts | 3 +- test/commands/health-check.test.ts | 52 ++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/commands/health-check.ts create mode 100644 test/commands/health-check.test.ts diff --git a/src/commands/health-check.ts b/src/commands/health-check.ts new file mode 100644 index 00000000..70f2ffa4 --- /dev/null +++ b/src/commands/health-check.ts @@ -0,0 +1,37 @@ +import {flags} from '@oclif/command' +import * as colors from 'colors' +import Constants from '../services/constants' +import healthCheck from '../utils/health-checker' +import PercyCommand from './percy-command' + +export default class HealthCheck extends PercyCommand { + static description = 'Determins if the Percy Agent process is currently running' + static hidden = true + + static flags = { + port: flags.integer({ + char: 'p', + default: Constants.PORT, + description: 'port', + }), + } + + static examples = [ + '$ percy healthcheck', + '$ percy healthcheck --port 6884', + ] + + async run() { + await super.run() + + // If Percy is disabled or is missing a token, gracefully exit here + if (!this.percyWillRun()) { this.exit(0) } + + const {flags} = this.parse(HealthCheck) + const port = flags.port as number + + await healthCheck(port, { + shouldRetry: () => false, + }) + } +} diff --git a/src/utils/health-checker.ts b/src/utils/health-checker.ts index 4253e785..b41ef356 100644 --- a/src/utils/health-checker.ts +++ b/src/utils/health-checker.ts @@ -2,13 +2,14 @@ import Axios from 'axios' import * as retryAxios from 'retry-axios' import logger from './logger' -async function healthCheck(port: number) { +async function healthCheck(port: number, retryOptions?: object) { const healthcheckUrl = `http://localhost:${port}/percy/healthcheck` const retryConfig = { retry: 5, // with exponential back off retryDelay: 500, shouldRetry: () => true, + ...retryOptions, } const interceptorId = retryAxios.attach() diff --git a/test/commands/health-check.test.ts b/test/commands/health-check.test.ts new file mode 100644 index 00000000..b15bcbc0 --- /dev/null +++ b/test/commands/health-check.test.ts @@ -0,0 +1,52 @@ +import * as chai from 'chai' +import * as nock from 'nock' +import {describe} from 'mocha' +import HealthCheck from '../../src/commands/health-check' +import {captureStdOut, captureStdErr} from '../helpers/stdout' + +const expect = chai.expect + +describe('Health check', () => { + describe('when agent is running', () => { + beforeEach(() => { + nock(/localhost/).get('/percy/healthcheck').reply(200) + }) + + afterEach(() => { + nock.cleanAll() + }) + + it('messages that agent is ready', async () => { + const stdout = await captureStdOut(async () => await HealthCheck.run([])) + + expect(stdout).to.contain('[percy] percy is ready.') + }) + }) + + describe('when agent is not running', () => { + beforeEach(() => { + nock(/localhost/).get('/percy/healthcheck').reply(500) + }) + + afterEach(() => { + nock.cleanAll() + }) + + it('messages that agent is not ready', async () => { + const errorStdout = await captureStdErr(async () => await HealthCheck.run([])) + + expect(errorStdout).to + .contain('[percy] Failed to establish a connection with http://localhost:5338/percy/healthcheck') + }) + + it('properly passes the port', async () => { + const port = '5899' + const errorStdout = await captureStdErr(async () => + await HealthCheck.run(['--port', port]) + ) + + expect(errorStdout).to + .contain('[percy] Failed to establish a connection with http://localhost:5899/percy/healthcheck') + }) + }) +}) From c7ab13d377c1ae4494ea51c3f1e2996ab40be01e Mon Sep 17 00:00:00 2001 From: Robert DeLuca Date: Wed, 3 Apr 2019 15:17:55 -0500 Subject: [PATCH 2/4] Update ci cache key This should fix the following error in CI: ``` error computing cache key: template: cacheKey:1:47: executing "cacheKey" at : error calling checksum: open /home/circleci/cli/yarn.lock: no such file or directory ``` This is because we don't actually have a yarn lock file --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dc027a63..a0d8d7ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ jobs: - checkout - restore_cache: &restore_cache keys: - - v1-yarn-{{checksum ".circleci/config.yml"}}-{{ checksum "yarn.lock"}} + - v1-yarn-{{checksum ".circleci/config.yml"}}-{{ checksum "package-lock.json"}} - v1-yarn-{{checksum ".circleci/config.yml"}} - run: .circleci/greenkeeper - run: yarn add -D nyc@11 @oclif/nyc-config@1 mocha-junit-reporter@1 From 55c8d6c0d0c35d3741e25c13c415b49b0f62c830 Mon Sep 17 00:00:00 2001 From: Robert DeLuca Date: Wed, 3 Apr 2019 15:19:28 -0500 Subject: [PATCH 3/4] Make the linter happy --- test/commands/health-check.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/commands/health-check.test.ts b/test/commands/health-check.test.ts index b15bcbc0..63489185 100644 --- a/test/commands/health-check.test.ts +++ b/test/commands/health-check.test.ts @@ -1,8 +1,8 @@ import * as chai from 'chai' -import * as nock from 'nock' import {describe} from 'mocha' +import * as nock from 'nock' import HealthCheck from '../../src/commands/health-check' -import {captureStdOut, captureStdErr} from '../helpers/stdout' +import {captureStdErr, captureStdOut} from '../helpers/stdout' const expect = chai.expect @@ -17,7 +17,7 @@ describe('Health check', () => { }) it('messages that agent is ready', async () => { - const stdout = await captureStdOut(async () => await HealthCheck.run([])) + const stdout = await captureStdOut(async () => HealthCheck.run([])) expect(stdout).to.contain('[percy] percy is ready.') }) @@ -33,7 +33,7 @@ describe('Health check', () => { }) it('messages that agent is not ready', async () => { - const errorStdout = await captureStdErr(async () => await HealthCheck.run([])) + const errorStdout = await captureStdErr(async () => HealthCheck.run([])) expect(errorStdout).to .contain('[percy] Failed to establish a connection with http://localhost:5338/percy/healthcheck') @@ -42,7 +42,7 @@ describe('Health check', () => { it('properly passes the port', async () => { const port = '5899' const errorStdout = await captureStdErr(async () => - await HealthCheck.run(['--port', port]) + HealthCheck.run(['--port', port]), ) expect(errorStdout).to From a9f5474e37de8563a216c8b8f6db12c6f34e42b6 Mon Sep 17 00:00:00 2001 From: Robert DeLuca Date: Wed, 3 Apr 2019 17:18:15 -0500 Subject: [PATCH 4/4] Extend `Command`, remove `percyWillRun`. --- src/commands/health-check.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/commands/health-check.ts b/src/commands/health-check.ts index 70f2ffa4..b34a23d1 100644 --- a/src/commands/health-check.ts +++ b/src/commands/health-check.ts @@ -1,11 +1,10 @@ -import {flags} from '@oclif/command' +import {Command, flags} from '@oclif/command' import * as colors from 'colors' import Constants from '../services/constants' import healthCheck from '../utils/health-checker' -import PercyCommand from './percy-command' -export default class HealthCheck extends PercyCommand { - static description = 'Determins if the Percy Agent process is currently running' +export default class HealthCheck extends Command { + static description = 'Determines if the Percy Agent process is currently running' static hidden = true static flags = { @@ -22,11 +21,6 @@ export default class HealthCheck extends PercyCommand { ] async run() { - await super.run() - - // If Percy is disabled or is missing a token, gracefully exit here - if (!this.percyWillRun()) { this.exit(0) } - const {flags} = this.parse(HealthCheck) const port = flags.port as number