Skip to content

Commit

Permalink
feat(docker): integration tests in github pipeline
Browse files Browse the repository at this point in the history
Signed-off-by: GALLLASMILAN <gallas.milan@gmail.com>
  • Loading branch information
GALLLASMILAN committed Jan 2, 2025
1 parent f7226f6 commit fba2acf
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
################# Fastify #################
###########################################
# 1. Fastify port
PORT=3000
PORT=4318
# 2. Secure auth API key
AUTH_KEY=very-strong-and-long-api-key-with-special-chars
# 3. Request body limit
Expand Down
5 changes: 4 additions & 1 deletion .env.testing.docker
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
NODE_ENV=production
PORT=4318
AUTH_KEY=valid-api-key
FASTIFY_BODY_LIMIT=10485760
Expand All @@ -11,8 +12,10 @@ MLFLOW_AUTHORIZATION=BASE_AUTH
MLFLOW_USERNAME=admin
MLFLOW_PASSWORD=password
MLFLOW_DEFAULT_EXPERIMENT_ID=0
MLFLOW_TRACE_DELETE_IN_BATCHES_CRON_PATTERN="0 */1 * * * *"
MLFLOW_TRACE_DELETE_IN_BATCHES_CRON_PATTERN="* * * * */20"
MLFLOW_TRACE_DELETE_IN_BATCHES_BATCH_SIZE=100

BEE_FRAMEWORK_INSTRUMENTATION_METRICS_ENABLED=false
BEE_FRAMEWORK_INSTRUMENTATION_ENABLED=true

USE_FAKE_BACKEND_FOR_TESTING=true
51 changes: 51 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Integration Test

on:
push:
branches: ['main']
pull_request:
branches: ['main']

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
main:
timeout-minutes: 20
name: Integration Test
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Enable Corepack
run: corepack enable
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'yarn'
- name: Install dependencies
run: yarn install
- name: Copy .env file
run: cp .env.testing.docker .env
- name: Build infra
run: docker compose build
- name: Build Observe API
run: docker compose build
- name: Temp 1
run: docker ps
- name: Run Observe API
run: docker compose up -d
- name: Temp 2
run: docker ps
- name: Run Vitest
run: yarn run vitest --run
- name: Collect Logs on Failure (Observe)
if: failure()
run: docker compose logs
- name: Cleanup
if: always()
run: docker compose down
38 changes: 0 additions & 38 deletions compose-before.yml

This file was deleted.

42 changes: 42 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
name: 'bee-observe'
services:
mongo:
image: mongo:7
ports:
- '${DATABASE_EXPOSED_PORT:-27019}:27017'
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME:-mongo}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD:-mongo}
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongosh localhost:27017/test --quiet
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7
ports:
- '${REDIS_EXPOSED_PORT:-6380}:6379'
command: redis-server --save 20 1 --loglevel warning
healthcheck:
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
interval: 10s
timeout: 5s
retries: 5
mlflow:
image: bitnami/mlflow:2.17.2
ports:
- '${MLFLOW_EXPOSED_PORT:-8080}:8080'
entrypoint:
[
'/bin/bash',
'-c',
'/entrypoint.sh && mlflow server --app-name basic-auth --host 0.0.0.0 --port 8080'
]
security_opt:
- 'label=disable'
volumes:
- ./entrypoint.sh:/entrypoint.sh:ro
observe_api:
build:
context: .
Expand All @@ -10,6 +46,12 @@ services:
- '${OBSERVE_API_EXPOSED_PORT:-4318}:4318'
env_file:
- .env.testing.docker
command: >
/bin/sh -c "
touch tsconfig.json &&
NODE_ENV=production npx mikro-orm --config dist/mikro-orm.config.js migration:up &&
node ./dist/index.js
"
healthcheck:
test: wget --no-verbose --tries=1 --spider http://0.0.0.0:4318/health || exit 1
interval: 10s
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
"scripts": {
"build": "rm -rf dist && tsc && cp -R src/protos dist/protos",
"proto:generate": "./scripts/open_telemetry_generate_protos/generate_protos.sh",
"start:infra": "docker compose -f compose-before.yml up -d mongo redis mlflow",
"start:infra": "docker compose up -d mongo redis mlflow",
"start:dev": "tsx watch ./src/index.ts | pino-pretty --singleLine",
"stop:infra": "docker compose -f compose-before.yml down",
"stop:infra": "docker compose down",
"dev": "yarn start:dev",
"start": "node ./dist/index.js",
"test": "./scripts/test_local.sh",
Expand Down
18 changes: 2 additions & 16 deletions scripts/test_local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ set -e

## turn off testing containers if are running
docker compose down
docker compose -f compose-before.yml down

## run containers
### pull latest versions
Expand All @@ -28,18 +27,6 @@ docker compose pull
### build the observe image
docker compose build

### run compose up and wait 120 seconds - in case of failure - cancel the operation and print logs
if timeout 120 yarn start:infra 2>/dev/null ; then
echo '🆗 docker containers are working and ready to test'
else
echo '❌ There is some error with the docker compose up command. Check your environments in .env.testing.docker and see docker logs ...'
docker compose logs
exit 1;
fi

### run migrations
yarn mikro-orm-esm migration:up

### run compose up and wait 120 seconds - in case of failure - cancel the operation and print logs
if timeout 120 docker compose up -d 2>/dev/null ; then
echo '🆗 docker containers are working and ready to test'
Expand All @@ -52,9 +39,8 @@ fi
## run integration tests
yarn run vitest --run

## 7) clean
## clean
docker compose down
docker compose -f compose-before.yml down

## 8) info
## info
echo "✅ tests done"
9 changes: 2 additions & 7 deletions src/span/span.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { Version } from 'bee-agent-framework';

import { sdk, spanTraceExporterProcessor } from '../testing/telemetry.js';
import { agent, makeRequest } from '../testing/utils.js';
import { generateTrace, makeRequest } from '../testing/utils.js';

let traceId: string | undefined = undefined;
const prompt = 'hello';

describe('span module', () => {
beforeAll(async () => {
await sdk.start();
await agent.run({ prompt }).middleware((ctx) => (traceId = ctx.emitter.trace?.id));
traceId = await generateTrace({ prompt });
await spanTraceExporterProcessor.forceFlush();
});

Expand Down Expand Up @@ -63,10 +63,5 @@ describe('span module', () => {
expect(mainSpan.attributes.prompt).toBe(prompt);
expect(mainSpan.attributes.response.text.length).toBeGreaterThan(0);
expect(mainSpan.ctx).toBeUndefined();

const startSpan = results.find((result: any) => result.name === 'ollama.chat_llm.start-1');
expect(
startSpan.attributes.data.input.find((input: any) => input.role === 'system').text.length
).toBeGreaterThan(0);
});
});
55 changes: 55 additions & 0 deletions src/testing/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { setTimeout as setTimeoutPromise } from 'node:timers/promises';

Check failure on line 17 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

There should be at least one empty line between import groups
import { api } from '@opentelemetry/sdk-node';

Check failure on line 18 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

There should be no empty line within import group

import { BeeAgent } from 'bee-agent-framework/agents/bee/agent';
import { TokenMemory } from 'bee-agent-framework/memory/tokenMemory';
Expand All @@ -26,6 +27,7 @@ import protobuf from 'protobufjs';

import { TraceDto } from '../trace/trace.dto.js';
import { constants } from '../utils/constants.js';

Check failure on line 29 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

There should be at least one empty line between import groups
import { Version } from 'bee-agent-framework';

Check failure on line 30 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

`bee-agent-framework` import should occur before import of `../trace/trace.dto.js`

export const buildUrl = (route: string): string => {
const port = process.env.PORT || '4318';
Expand Down Expand Up @@ -131,3 +133,56 @@ export async function sendCustomProtobuf(payload: SendCustomProtobufProps) {
body: buffer
});
}

const fakeSpans = [
{
id: 'fake-1',
target: 'groupId',
name: 'iteration-1'
}
];

export async function generateTrace({ prompt }: { prompt: string; }) {

Check failure on line 145 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Delete `;`
let traceId: string | undefined = undefined;
// bee-agent-framework
if (!process.env.USE_FAKE_BACKEND_FOR_TESTING) {
await agent.run({ prompt }).middleware((ctx) => (traceId = ctx.emitter.trace?.id));
return traceId;
}

// mock
const tracer = api.trace.getTracer("bee-agent-framework", Version);

Check failure on line 154 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Replace `"bee-agent-framework"` with `'bee-agent-framework'`
traceId = 'ea215b9f';

// 1) main span
tracer.startActiveSpan(`bee-agent-framework-BeeAgent-${traceId}`, {

Check failure on line 158 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Replace ``bee-agent-framework-BeeAgent-${traceId}`,` with `⏎····`bee-agent-framework-BeeAgent-${traceId}`,⏎···`
attributes: {

Check failure on line 159 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Insert `··`
traceId,

Check failure on line 160 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Replace `······` with `········`
version: Version,

Check failure on line 161 in src/testing/utils.ts

View workflow job for this annotation

GitHub Actions / Lint & Format & CommitLint & Build

Insert `··`
prompt,
response: JSON.stringify({
role: "assistant",
text: "Hello! It's nice to chat with you."
})
}
}, (activeSpan) => {
activeSpan.setStatus({ code: 1 });

// 2) nested spans
fakeSpans.map((span) => {
tracer.startActiveSpan(span.id, {
attributes: {
target: span.target,
name: span.name
}
}, (nestedSpan) => {
nestedSpan.setStatus({ code: 1 });
nestedSpan.end();
})
});

activeSpan.end();
});

return traceId;
}
6 changes: 3 additions & 3 deletions src/trace/trace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
import { expect, it, describe, beforeAll, afterAll } from 'vitest';

import { sdk, spanTraceExporterProcessor } from '../testing/telemetry.js';
import { agent, makeRequest, sendCustomProtobuf, waitForMlflowTrace } from '../testing/utils.js';
import { generateTrace, makeRequest, sendCustomProtobuf, waitForMlflowTrace } from '../testing/utils.js';

let traceId: string | undefined = undefined;
const prompt = 'hello';

describe('trace module', () => {
beforeAll(async () => {
await sdk.start();
await agent.run({ prompt }).middleware((ctx) => (traceId = ctx.emitter.trace?.id));
traceId = await generateTrace({ prompt });
await spanTraceExporterProcessor.forceFlush();
if (traceId) await waitForMlflowTrace({ traceId });
});
Expand All @@ -41,7 +41,7 @@ describe('trace module', () => {

it('should use "Retry-After" header and wait until the trace is ready', async () => {
let retryAfterTraceId: string | undefined = undefined;
await agent.run({ prompt }).middleware((ctx) => (retryAfterTraceId = ctx.emitter.trace?.id));
retryAfterTraceId = await generateTrace({ prompt });
if (retryAfterTraceId) await waitForMlflowTrace({ traceId: retryAfterTraceId });

const traceResponse = await makeRequest({ route: `v1/traces/${retryAfterTraceId}` });
Expand Down

0 comments on commit fba2acf

Please sign in to comment.