Skip to content

Commit 622b3ac

Browse files
committed
ci: Add Docker-based tests with pgvector and Ollama services
- Add comprehensive documentation to integration-tests.yml - Add docker-tests group with pgvector and Ollama services - Create Dockerfile for Ollama with pre-loaded flow-judge model - Add build-ollama-image.yml workflow to build/push to ghcr.io - Enable rag-with-kotlin and evaluation-recursive-advisor-demo in CI
1 parent 51c4769 commit 622b3ac

3 files changed

Lines changed: 320 additions & 7 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# ============================================================================
2+
# Ollama with Flow Judge Model Pre-loaded
3+
# ============================================================================
4+
#
5+
# This image contains Ollama with the flow-judge model pre-downloaded
6+
# for use in CI/CD pipelines where downloading large models is impractical.
7+
#
8+
# Model: avcodes/flowaicom-flow-judge:q4 (~2.5GB)
9+
# Base: ollama/ollama:latest
10+
#
11+
# Build:
12+
# docker build -t ollama-flow-judge .
13+
#
14+
# Run:
15+
# docker run -d -p 11434:11434 ollama-flow-judge
16+
#
17+
# ============================================================================
18+
19+
FROM ollama/ollama:latest
20+
21+
# Set environment variables
22+
ENV OLLAMA_HOST=0.0.0.0
23+
ENV OLLAMA_MODELS=/root/.ollama/models
24+
25+
# Create models directory
26+
RUN mkdir -p /root/.ollama/models
27+
28+
# Download the flow-judge model during build
29+
# This runs ollama in the background, pulls the model, then stops
30+
RUN ollama serve & \
31+
sleep 5 && \
32+
ollama pull avcodes/flowaicom-flow-judge:q4 && \
33+
pkill ollama
34+
35+
# Expose the Ollama API port
36+
EXPOSE 11434
37+
38+
# Default command - start Ollama server
39+
ENTRYPOINT ["/bin/ollama"]
40+
CMD ["serve"]
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# ============================================================================
2+
# Build Ollama Flow Judge Image
3+
# ============================================================================
4+
#
5+
# Builds and pushes the Ollama image with pre-loaded flow-judge model to ghcr.io.
6+
# This image is used by the integration tests workflow.
7+
#
8+
# TRIGGERS:
9+
# - Push to main with changes to the Dockerfile
10+
# - Manual trigger (workflow_dispatch)
11+
#
12+
# The image is cached in ghcr.io and only rebuilt when:
13+
# - The Dockerfile changes
14+
# - Manually triggered (e.g., to update to newer Ollama version)
15+
#
16+
# ============================================================================
17+
18+
name: Build Ollama Image
19+
20+
on:
21+
push:
22+
branches: [main]
23+
paths:
24+
- '.github/docker/ollama-flow-judge/**'
25+
workflow_dispatch:
26+
inputs:
27+
force_rebuild:
28+
description: 'Force rebuild even if no changes'
29+
required: false
30+
default: false
31+
type: boolean
32+
33+
env:
34+
REGISTRY: ghcr.io
35+
IMAGE_NAME: ${{ github.repository }}/ollama-flow-judge
36+
37+
jobs:
38+
build-and-push:
39+
name: Build and Push Ollama Image
40+
runs-on: ubuntu-latest
41+
permissions:
42+
contents: read
43+
packages: write
44+
45+
steps:
46+
- name: Checkout repository
47+
uses: actions/checkout@v4
48+
49+
- name: Set up Docker Buildx
50+
uses: docker/setup-buildx-action@v3
51+
52+
- name: Log in to Container Registry
53+
uses: docker/login-action@v3
54+
with:
55+
registry: ${{ env.REGISTRY }}
56+
username: ${{ github.actor }}
57+
password: ${{ secrets.GITHUB_TOKEN }}
58+
59+
- name: Extract metadata
60+
id: meta
61+
uses: docker/metadata-action@v5
62+
with:
63+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
64+
tags: |
65+
type=raw,value=latest
66+
type=sha,prefix=
67+
type=raw,value={{date 'YYYYMMDD'}}
68+
69+
- name: Build and push
70+
uses: docker/build-push-action@v5
71+
with:
72+
context: .github/docker/ollama-flow-judge
73+
push: true
74+
tags: ${{ steps.meta.outputs.tags }}
75+
labels: ${{ steps.meta.outputs.labels }}
76+
cache-from: type=gha
77+
cache-to: type=gha,mode=max
78+
79+
- name: Summary
80+
run: |
81+
echo "## Ollama Image Built" >> $GITHUB_STEP_SUMMARY
82+
echo "" >> $GITHUB_STEP_SUMMARY
83+
echo "**Image:** \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest\`" >> $GITHUB_STEP_SUMMARY
84+
echo "" >> $GITHUB_STEP_SUMMARY
85+
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
86+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
87+
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
88+
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
89+
echo "" >> $GITHUB_STEP_SUMMARY
90+
echo "**Contains:**" >> $GITHUB_STEP_SUMMARY
91+
echo "- Ollama server" >> $GITHUB_STEP_SUMMARY
92+
echo "- \`avcodes/flowaicom-flow-judge:q4\` model pre-loaded" >> $GITHUB_STEP_SUMMARY

.github/workflows/integration-tests.yml

Lines changed: 188 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,71 @@
1+
# ============================================================================
2+
# Spring AI Examples - Integration Tests
3+
# ============================================================================
4+
#
5+
# This workflow runs integration tests for Spring AI examples in parallel groups.
6+
#
7+
# SCHEDULE: Weekly on Sundays at 6 AM UTC
8+
#
9+
# MANUAL TRIGGER OPTIONS:
10+
# - test_filter: Run a specific test by name pattern
11+
# Examples: "kotlin-hello-world", "chain-workflow", "weather"
12+
#
13+
# - test_group: Run only tests in a specific group
14+
# Options: all, mcp-servers, openai-1, openai-2, openai-3, anthropic-multi, docker-tests
15+
#
16+
# TEST GROUPS:
17+
# ┌─────────────────────┬────────────────────────────────────────────────────┐
18+
# │ Group │ Tests │
19+
# ├─────────────────────┼────────────────────────────────────────────────────┤
20+
# │ mcp-servers │ weather/starter-webmvc-server │
21+
# │ │ weather/starter-webflux-server │
22+
# │ │ weather/starter-stdio-server │
23+
# ├─────────────────────┼────────────────────────────────────────────────────┤
24+
# │ openai-1 │ agentic-patterns/chain-workflow │
25+
# │ (Agentic Patterns) │ agentic-patterns/evaluator-optimizer │
26+
# │ │ agentic-patterns/orchestrator-workers │
27+
# │ │ agentic-patterns/parallelization-workflow │
28+
# │ │ agentic-patterns/routing-workflow │
29+
# │ │ agents/reflection │
30+
# ├─────────────────────┼────────────────────────────────────────────────────┤
31+
# │ openai-2 │ kotlin/kotlin-hello-world │
32+
# │ (Kotlin & Misc) │ kotlin/kotlin-function-callback │
33+
# │ │ misc/openai-streaming-response │
34+
# │ │ misc/spring-ai-java-function-callback │
35+
# │ │ models/chat/helloworld │
36+
# ├─────────────────────┼────────────────────────────────────────────────────┤
37+
# │ openai-3 │ advisors/tool-argument-augmenter-demo │
38+
# │ (MCP Clients) │ model-context-protocol/client-starter/starter-default-client │
39+
# │ │ model-context-protocol/dynamic-tool-update │
40+
# │ │ model-context-protocol/filesystem │
41+
# │ │ model-context-protocol/sqlite/simple │
42+
# │ │ model-context-protocol/sqlite/chatbot │
43+
# ├─────────────────────┼────────────────────────────────────────────────────┤
44+
# │ anthropic-multi │ advisors/recursive-advisor-demo │
45+
# │ (Multi-API) │ misc/claude-skills-demo/document-forge │
46+
# │ │ prompt-engineering/prompt-engineering-patterns │
47+
# │ │ model-context-protocol/brave │
48+
# │ │ model-context-protocol/client-starter/starter-webflux-client │
49+
# │ │ model-context-protocol/sampling │
50+
# │ │ model-context-protocol/web-search/brave-chatbot │
51+
# │ │ model-context-protocol/web-search/brave-starter │
52+
# ├─────────────────────┼────────────────────────────────────────────────────┤
53+
# │ docker-tests │ kotlin/rag-with-kotlin (requires pgvector) │
54+
# │ │ advisors/evaluation-recursive-advisor-demo (Ollama)│
55+
# └─────────────────────┴────────────────────────────────────────────────────┘
56+
#
57+
# SKIPPED TESTS (not in any group):
58+
# - mcp-annotations-server: Orphaned directory
59+
# - sampling/mcp-weather-webmvc-server: Orphaned directory
60+
# - weather/starter-webmvc-oauth2-server: Known MCP 404 issue
61+
#
62+
# REQUIRED SECRETS:
63+
# - OPENAI_API_KEY
64+
# - ANTHROPIC_API_KEY
65+
# - BRAVE_API_KEY
66+
#
67+
# ============================================================================
68+
169
name: Integration Tests
270

371
on:
@@ -6,7 +74,7 @@ on:
674
workflow_dispatch:
775
inputs:
876
test_filter:
9-
description: 'Run specific test (e.g., kotlin-hello-world, agentic-patterns/chain-workflow)'
77+
description: 'Run specific test (e.g., kotlin-hello-world, chain-workflow)'
1078
required: false
1179
default: ''
1280
type: string
@@ -22,16 +90,19 @@ on:
2290
- openai-2
2391
- openai-3
2492
- anthropic-multi
93+
- docker-tests
2594

2695
jobs:
27-
# Define test groups for parallel execution
96+
# ============================================================================
97+
# Standard Integration Tests (no Docker services required)
98+
# ============================================================================
2899
integration-tests:
29100
name: ${{ matrix.group_name }}
30101
runs-on: ubuntu-latest
31102
timeout-minutes: 45
32103

33104
strategy:
34-
fail-fast: false # Continue other groups even if one fails
105+
fail-fast: false
35106
matrix:
36107
include:
37108
# Group 1: MCP Servers (no API keys, fast)
@@ -241,11 +312,122 @@ jobs:
241312
integration-testing/logs/**/*.log
242313
retention-days: 7
243314

244-
# Summary job that runs after all test groups
315+
# ============================================================================
316+
# Docker-based Tests (pgvector, Ollama)
317+
# ============================================================================
318+
docker-tests:
319+
name: "Docker Tests"
320+
runs-on: ubuntu-latest
321+
timeout-minutes: 60
322+
if: ${{ inputs.test_group == 'all' || inputs.test_group == 'docker-tests' || inputs.test_group == '' }}
323+
324+
services:
325+
pgvector:
326+
image: pgvector/pgvector:pg16
327+
ports:
328+
- 5432:5432
329+
env:
330+
POSTGRES_USER: postgres
331+
POSTGRES_PASSWORD: postgres
332+
POSTGRES_DB: postgres
333+
options: >-
334+
--health-cmd="pg_isready -U postgres"
335+
--health-interval=10s
336+
--health-timeout=5s
337+
--health-retries=5
338+
339+
ollama:
340+
image: ghcr.io/${{ github.repository }}/ollama-flow-judge:latest
341+
ports:
342+
- 11434:11434
343+
options: >-
344+
--health-cmd="curl -f http://localhost:11434/api/tags || exit 1"
345+
--health-interval=10s
346+
--health-timeout=5s
347+
--health-retries=10
348+
349+
steps:
350+
- name: Checkout repository
351+
uses: actions/checkout@v4
352+
353+
- name: Set up JDK 21
354+
uses: actions/setup-java@v4
355+
with:
356+
java-version: '21'
357+
distribution: 'temurin'
358+
cache: maven
359+
360+
- name: Set up Python 3
361+
uses: actions/setup-python@v5
362+
with:
363+
python-version: '3.11'
364+
365+
- name: Setup Node.js
366+
uses: actions/setup-node@v4
367+
with:
368+
node-version: '20'
369+
370+
- name: Install Claude Code CLI
371+
run: |
372+
npm install -g @anthropic-ai/claude-code --silent
373+
echo "Claude Code CLI installed"
374+
375+
- name: Install JBang
376+
run: |
377+
curl -Ls https://sh.jbang.dev | bash -s - app setup
378+
echo "$HOME/.jbang/bin" >> "$GITHUB_PATH"
379+
380+
- name: Verify services
381+
run: |
382+
echo "Checking pgvector..."
383+
pg_isready -h localhost -p 5432 -U postgres
384+
echo "pgvector is ready"
385+
386+
echo "Checking Ollama..."
387+
curl -s http://localhost:11434/api/tags | head -c 200
388+
echo ""
389+
echo "Ollama is ready"
390+
391+
- name: Run rag-with-kotlin test
392+
env:
393+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
394+
SPRING_AI_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
395+
# pgvector connection - override Docker Compose
396+
SPRING_DATASOURCE_URL: jdbc:postgresql://localhost:5432/postgres
397+
SPRING_DATASOURCE_USERNAME: postgres
398+
SPRING_DATASOURCE_PASSWORD: postgres
399+
SPRING_DOCKER_COMPOSE_ENABLED: false
400+
run: |
401+
export PATH="$HOME/.jbang/bin:$PATH"
402+
echo "Running: kotlin/rag-with-kotlin"
403+
./integration-testing/scripts/run-integration-tests.sh "rag-with-kotlin"
404+
405+
- name: Run evaluation-recursive-advisor-demo test
406+
env:
407+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
408+
SPRING_AI_ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
409+
SPRING_AI_OLLAMA_BASE_URL: http://localhost:11434
410+
run: |
411+
export PATH="$HOME/.jbang/bin:$PATH"
412+
echo "Running: advisors/evaluation-recursive-advisor-demo"
413+
./integration-testing/scripts/run-integration-tests.sh "evaluation-recursive"
414+
415+
- name: Upload test logs
416+
if: always()
417+
uses: actions/upload-artifact@v4
418+
with:
419+
name: logs-docker-tests-${{ github.run_number }}
420+
path: |
421+
integration-testing/logs/**/*.log
422+
retention-days: 7
423+
424+
# ============================================================================
425+
# Summary
426+
# ============================================================================
245427
summary:
246428
name: Test Summary
247429
runs-on: ubuntu-latest
248-
needs: integration-tests
430+
needs: [integration-tests, docker-tests]
249431
if: always()
250432
steps:
251433
- name: Generate Summary
@@ -259,10 +441,9 @@ jobs:
259441
echo "| OpenAI - Kotlin | ${{ needs.integration-tests.result }} |" >> $GITHUB_STEP_SUMMARY
260442
echo "| OpenAI - MCP | ${{ needs.integration-tests.result }} |" >> $GITHUB_STEP_SUMMARY
261443
echo "| Anthropic & Multi | ${{ needs.integration-tests.result }} |" >> $GITHUB_STEP_SUMMARY
444+
echo "| Docker Tests | ${{ needs.docker-tests.result }} |" >> $GITHUB_STEP_SUMMARY
262445
echo "" >> $GITHUB_STEP_SUMMARY
263446
echo "### Skipped Tests" >> $GITHUB_STEP_SUMMARY
264-
echo "- \`advisors/evaluation-recursive-advisor-demo\` - Requires Ollama (too slow for CI)" >> $GITHUB_STEP_SUMMARY
265-
echo "- \`kotlin/rag-with-kotlin\` - Requires Docker with pgvector" >> $GITHUB_STEP_SUMMARY
266447
echo "- \`mcp-annotations-server\` - Orphaned directory" >> $GITHUB_STEP_SUMMARY
267448
echo "- \`sampling/mcp-weather-webmvc-server\` - Orphaned directory" >> $GITHUB_STEP_SUMMARY
268449
echo "- \`weather/starter-webmvc-oauth2-server\` - Known MCP 404 issue" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)