From 469d1cb69d8724e5a1abdd2368c59e5ef8c0643c Mon Sep 17 00:00:00 2001 From: Manuel <30572287+manuel-rw@users.noreply.github.com> Date: Sat, 14 Jan 2023 22:47:53 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=85=20Add=20tests=20for=20health=20indica?= =?UTF-8?q?tors=20#12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/health/health.controller.spec.ts | 70 +++++++++++++++++-- src/health/health.controller.ts | 2 +- .../indicators/jeyllfin.indicator.spec.ts | 48 +++++++++++++ src/utils/tests.ts | 16 +++++ 4 files changed, 131 insertions(+), 5 deletions(-) create mode 100644 src/health/indicators/jeyllfin.indicator.spec.ts create mode 100644 src/utils/tests.ts diff --git a/src/health/health.controller.spec.ts b/src/health/health.controller.spec.ts index 0ab9987..f6f3951 100644 --- a/src/health/health.controller.spec.ts +++ b/src/health/health.controller.spec.ts @@ -1,18 +1,80 @@ -import { Test, TestingModule } from '@nestjs/testing'; +import { + HealthCheckResult, + HealthCheckService, + HealthIndicatorResult, +} from '@nestjs/terminus'; +import { HealthCheckExecutor } from '@nestjs/terminus/dist/health-check/health-check-executor.service'; +import { Test } from '@nestjs/testing'; +import { useDefaultMockerToken } from '../utils/tests'; import { HealthController } from './health.controller'; +import { DiscordHealthIndicator } from './indicators/discord.indicator'; +import { JellyfinHealthIndicator } from './indicators/jellyfin.indicator'; describe('HealthController', () => { let controller: HealthController; beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ + const moduleRef = await Test.createTestingModule({ controllers: [HealthController], - }).compile(); + }) + .useMocker((token) => { + if (token === JellyfinHealthIndicator) { + return { + isHealthy: jest.fn().mockResolvedValue({ + jellyfin: { + status: 'up', + }, + } as HealthIndicatorResult), + }; + } - controller = module.get(HealthController); + if (token === DiscordHealthIndicator) { + return { + isHealthy: jest.fn().mockResolvedValue({ + discord: { + status: 'up', + }, + } as HealthIndicatorResult), + }; + } + + if (token === HealthCheckService) { + return new HealthCheckService(new HealthCheckExecutor(), null); + } + + return useDefaultMockerToken(token); + }) + .compile(); + + controller = moduleRef.get(HealthController); }); it('should be defined', () => { expect(controller).toBeDefined(); }); + + it('should return health status', async () => { + const result = await controller.healthCheck(); + + expect(result).toStrictEqual({ + details: { + discord: { + status: 'up', + }, + jellyfin: { + status: 'up', + }, + }, + error: {}, + info: { + discord: { + status: 'up', + }, + jellyfin: { + status: 'up', + }, + }, + status: 'ok', + } as HealthCheckResult); + }); }); diff --git a/src/health/health.controller.ts b/src/health/health.controller.ts index 0852e87..4b3d7b8 100644 --- a/src/health/health.controller.ts +++ b/src/health/health.controller.ts @@ -14,7 +14,7 @@ export class HealthController { @Get() @HealthCheck() - healthCheck() { + async healthCheck() { return this.health.check([ () => this.discordIndicator.isHealthy('discord'), () => this.jellyfinHealthIndicator.isHealthy('jellyfin'), diff --git a/src/health/indicators/jeyllfin.indicator.spec.ts b/src/health/indicators/jeyllfin.indicator.spec.ts new file mode 100644 index 0000000..9c1e96d --- /dev/null +++ b/src/health/indicators/jeyllfin.indicator.spec.ts @@ -0,0 +1,48 @@ +import { HealthIndicatorResult } from '@nestjs/terminus'; +import { Test } from '@nestjs/testing'; +import { JellyfinService } from '../../clients/jellyfin/jellyfin.service'; +import { useDefaultMockerToken } from '../../utils/tests'; +import { JellyfinHealthIndicator } from './jellyfin.indicator'; + +describe('JellyfinHealthIndicator', () => { + let service: JellyfinHealthIndicator; + let jellyfinService: JellyfinService; + + beforeEach(async () => { + const moduleRef = await Test.createTestingModule({ + providers: [JellyfinHealthIndicator], + }) + .useMocker((token) => { + if (token === JellyfinService) { + return { isConnected: jest.fn() }; + } + return useDefaultMockerToken(token); + }) + .compile(); + + service = moduleRef.get(JellyfinHealthIndicator); + jellyfinService = moduleRef.get(JellyfinService); + }); + + it('isHealthyWhenJellyfinIsConnected', async () => { + jest.spyOn(jellyfinService, 'isConnected').mockImplementation(() => true); + const result = await service.isHealthy('jellyfin'); + + expect(result).toStrictEqual({ + jellyfin: { + status: 'up', + }, + } as HealthIndicatorResult); + }); + + it('isUnhealthyWhenJellyfinIsNotConnected', async () => { + jest.spyOn(jellyfinService, 'isConnected').mockImplementation(() => false); + const result = await service.isHealthy('jellyfin'); + + expect(result).toStrictEqual({ + jellyfin: { + status: 'down', + }, + } as HealthIndicatorResult); + }); +}); diff --git a/src/utils/tests.ts b/src/utils/tests.ts new file mode 100644 index 0000000..3749a37 --- /dev/null +++ b/src/utils/tests.ts @@ -0,0 +1,16 @@ +import { InjectionToken } from '@nestjs/common'; +import { MockFunctionMetadata, ModuleMocker } from 'jest-mock'; + +const moduleMocker = new ModuleMocker(global); + +export const useDefaultMockerToken = (token: InjectionToken) => { + if (typeof token === 'function') { + const mockMetadata = moduleMocker.getMetadata( + token, + ) as MockFunctionMetadata; + const Mock = moduleMocker.generateFromMetadata(mockMetadata); + return new Mock(); + } + + return null; +};