From 9e617edd5fa71305ac81dc2f0df2dfd98822e154 Mon Sep 17 00:00:00 2001 From: Warren <5959690+wrn14897@users.noreply.github.com> Date: Sun, 7 Jan 2024 16:46:37 -0800 Subject: [PATCH] ci: setup aggregator int tests (#197) --- .changeset/mean-balloons-shake.md | 6 + packages/api/src/fixtures.ts | 19 ++- .../routers/aggregator/__tests__/root.test.ts | 115 ++++++++++++++++++ packages/api/src/server.ts | 4 +- 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 .changeset/mean-balloons-shake.md create mode 100644 packages/api/src/routers/aggregator/__tests__/root.test.ts diff --git a/.changeset/mean-balloons-shake.md b/.changeset/mean-balloons-shake.md new file mode 100644 index 000000000..58b4d85dc --- /dev/null +++ b/.changeset/mean-balloons-shake.md @@ -0,0 +1,6 @@ +--- +'@hyperdx/api': patch +'@hyperdx/app': patch +--- + +ci: setup aggregator int tests diff --git a/packages/api/src/fixtures.ts b/packages/api/src/fixtures.ts index fd7440104..fb38b1136 100644 --- a/packages/api/src/fixtures.ts +++ b/packages/api/src/fixtures.ts @@ -86,7 +86,24 @@ class MockServer extends Server { } } -export const getServer = () => new MockServer(); +class MockAPIServer extends MockServer { + protected readonly appType = 'api'; +} + +class MockAggregatorServer extends MockServer { + protected readonly appType = 'aggregator'; +} + +export const getServer = (appType: 'api' | 'aggregator' = 'api') => { + switch (appType) { + case 'api': + return new MockAPIServer(); + case 'aggregator': + return new MockAggregatorServer(); + default: + throw new Error(`Invalid app type: ${appType}`); + } +}; export const getAgent = (server: MockServer) => request.agent(server.getHttpServer()); diff --git a/packages/api/src/routers/aggregator/__tests__/root.test.ts b/packages/api/src/routers/aggregator/__tests__/root.test.ts new file mode 100644 index 000000000..21a0a3f19 --- /dev/null +++ b/packages/api/src/routers/aggregator/__tests__/root.test.ts @@ -0,0 +1,115 @@ +import _ from 'lodash'; + +import * as clickhouse from '@/clickhouse'; +import { createTeam } from '@/controllers/team'; +import { + clearClickhouseTables, + clearDBCollections, + closeDB, + getAgent, + getServer, +} from '@/fixtures'; +import { sleep } from '@/utils/common'; + +describe('aggregator root router', () => { + const server = getServer('aggregator'); + + beforeAll(async () => { + await server.start(); + }); + + afterEach(async () => { + await clearDBCollections(); + await clearClickhouseTables(); + }); + + afterAll(async () => { + await server.closeHttpServer(); + await closeDB(); + }); + + it('GET /health', async () => { + const agent = await getAgent(server); + await agent.get('/health').expect(200); + }); + + it('POST / -> should return 400 if no logs', async () => { + const agent = await getAgent(server); + await agent.post('/').send({}).expect(400); + }); + + it('POST / -> should ingest logs', async () => { + const team = await createTeam({ name: 'test-team' }); + const agent = await getAgent(server); + await agent.post('/').send([ + { + b: { + _hdx_body: 'Initializing ClickHouse...', + level: 'info', + message: 'Initializing ClickHouse...', + }, + h: '509a8b2dea19', + hdx_platform: 'nodejs', + hdx_token: team.apiKey, + hdx_token_hash: '2f4da895de6a20c100c28daaa5c07c51', + path: '/', + r: { level: 'info', message: 'Initializing ClickHouse...' }, + s_id: null, + sn: 0, + st: 'info', + sv: 'hdx-oss-dev-api', + t_id: null, + ts: 1704517334214000000, + tso: 1704517336156579600, + }, + ]); + + // wait for data to be committed to clickhouse + await sleep(500); + + const resp = await clickhouse.client.query({ + query: `SELECT * FROM default.${clickhouse.TableName.LogStream}`, + format: 'JSON', + }); + const result: any = await resp.json(); + expect(result.data.length).toBe(1); + expect(result.data.map((row: any) => _.omit(row, ['id', '_created_at']))) + .toMatchInlineSnapshot(` +Array [ + Object { + "_host": "509a8b2dea19", + "_namespace": "", + "_platform": "nodejs", + "_service": "hdx-oss-dev-api", + "_source": "{\\"level\\":\\"info\\",\\"message\\":\\"Initializing ClickHouse...\\"}", + "bool.names": Array [], + "bool.values": Array [], + "end_timestamp": "1970-01-01T00:00:00.000000000Z", + "number.names": Array [], + "number.values": Array [], + "observed_timestamp": "2024-01-06T05:02:16.156579600Z", + "parent_span_id": "", + "severity_number": 0, + "severity_text": "info", + "span_id": "", + "span_name": "", + "string.names": Array [ + "_hdx_body", + "level", + "message", + ], + "string.values": Array [ + "Initializing ClickHouse...", + "info", + "Initializing ClickHouse...", + ], + "timestamp": "2024-01-06T05:02:14.214000000Z", + "trace_id": "", + "type": "log", + }, +] +`); + }); + + // TODO: test metrics +}); diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index 7b460400f..e694376d4 100644 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -8,10 +8,12 @@ import logger from './utils/logger'; import redisClient from './utils/redis'; export default class Server { + protected readonly appType = config.APP_TYPE; + protected httpServer!: http.Server; private async createServer() { - switch (config.APP_TYPE) { + switch (this.appType) { case 'api': return http.createServer( // eslint-disable-next-line n/no-unsupported-features/es-syntax