Skip to content

Add PostgreSQL service integration test workflow with database lifecycle management#91

Closed
Copilot wants to merge 8 commits into
mainfrom
copilot/create-integration-test-workflow
Closed

Add PostgreSQL service integration test workflow with database lifecycle management#91
Copilot wants to merge 8 commits into
mainfrom
copilot/create-integration-test-workflow

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 24, 2026

Integration Test Workflow with PostgreSQL Service

Implementation Complete ✅

All acceptance criteria met and review feedback addressed.

Latest Refinements

Remove Unnecessary RESTART IDENTITY

  • Issue: RESTART IDENTITY clause is unnecessary since all tables use UUID PKs, not sequences
  • Fix: Changed to TRUNCATE TABLE agents CASCADE (removed RESTART IDENTITY)
  • Impact: Clearer, more accurate code that matches schema design

Document Grace Period Validation

  • Issue: Validation logic didn't document that 0 is intentionally rejected
  • Fix: Added comment explaining positive integer requirement and default behavior
  • Impact: Clearer intent for future maintainers

Review Feedback Addressed ✅

1. Database Connection Leak Fixed (jest.integration.setup.ts)

  • Issue: globalDb created but never closed, causing connection leaks and Jest exit issues
  • Fix: Added await globalDb.close() after migrations and in error path
  • Impact: Prevents open handles and connection pool exhaustion

2. Configurable Grace Period (jest.integration.teardown.ts)

  • Issue: TEARDOWN_GRACE_PERIOD_MS was hardcoded despite PR description saying it's configurable
  • Fix: Read from process.env.TEARDOWN_GRACE_PERIOD_MS with safe fallback to 2000ms
  • Enhancement: Added NaN validation and positive integer check (0 uses default)
  • Documentation: Clarified that positive integers are required
  • Usage: TEARDOWN_GRACE_PERIOD_MS=5000 npm run test:integration

3. Fail-Fast PostgreSQL Check (.github/workflows/integration-tests.yml)

  • Issue: Wait loop didn't fail if PostgreSQL never became ready
  • Fix: Track readiness state, exit with error code 1 and clear message if timeout
  • Impact: Faster CI feedback when database service fails

4. Remove Duplicate Schema Initialization (.github/workflows/integration-tests.yml)

  • Issue: Workflow ran schema SQL, then Jest setup also ran migrations (duplication)
  • Fix: Removed explicit schema initialization steps from workflow
  • Impact: Faster workflow, single source of truth (Jest setup), consistent CI/local behavior

5. Optimize cleanAll() (src/database/test-seeder.ts)

  • Issue: Multiple DELETE statements slow, don't leverage CASCADE
  • Fix: Use TRUNCATE TABLE agents CASCADE (no RESTART IDENTITY since UUIDs don't use sequences)
  • Impact: Significantly faster test cleanup as test suite grows, accurate to schema

6. Fix Comment Accuracy (src/database/test-seeder.ts)

  • Issue: Comment said "Generate unique DID with UUID" but used timestamp+random
  • Fix: Updated comment to "Generate unique DID with timestamp and random string"

Test Results

  • ✅ 31 integration tests passed locally
  • ✅ Database setup/teardown works correctly
  • ✅ Test isolation verified
  • ✅ Connection leaks eliminated
  • ✅ Faster cleanup with TRUNCATE CASCADE
  • ✅ Robust environment variable parsing

Files Modified (4 files)

  • jest.integration.setup.ts - Close connection after migrations
  • jest.integration.teardown.ts - Configurable grace period with validation and documentation
  • .github/workflows/integration-tests.yml - Fail-fast check, remove duplicate schema init
  • src/database/test-seeder.ts - TRUNCATE CASCADE optimization (no RESTART IDENTITY), fix comment

Ready for Merge ✅

All review feedback addressed, connection leaks fixed, workflow optimized, validation robust, code accurate to schema.

Original prompt

This section details on the original issue you should resolve

<issue_title>[P0] Create Integration Test Workflow with PostgreSQL Service</issue_title>
<issue_description>## Overview
Create dedicated integration test workflow with PostgreSQL service container for database integration testing in CI environment.

Priority

P0 - Critical - Database integration tests are core to system reliability

Problem Statement

Current integration tests may not run reliably in CI due to:

  • Lack of PostgreSQL service configuration
  • Environment setup complexity
  • Missing database initialization
  • Connection configuration issues
  • Test data management challenges

Tasks

  • Configure PostgreSQL service in GitHub Actions
  • Set up database initialization scripts
  • Configure test database connection strings
  • Create database migration runner for tests
  • Add test data seeding mechanism
  • Configure database cleanup between test runs
  • Test all database-dependent integration tests
  • Add database health check
  • Document integration test setup
  • Add troubleshooting guide

Acceptance Criteria

  • PostgreSQL service starts in CI
  • Database schema created automatically
  • Test data seeded before tests run
  • All integration tests pass in CI
  • Tests clean up after themselves
  • Connection errors handled gracefully
  • Workflow completes in < 15 minutes
  • Documentation complete

Dependencies

  • Issue #R0.4 (CI Workflow) - should be completed first or in parallel

Related Files

  • `.github/workflows/ci.yml` or `.github/workflows/integration-tests.yml`
  • `database/schema.sql`
  • `jest.integration.config.js`
  • `src/database/client.ts`</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 4 commits January 24, 2026 22:11
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Copilot AI changed the title [WIP] Create integration test workflow with PostgreSQL service Add PostgreSQL service integration test workflow with database lifecycle management Jan 24, 2026
@colleenpridemore
Copy link
Copy Markdown
Contributor

@copilot ok!

Copy link
Copy Markdown
Contributor

@colleenpridemore colleenpridemore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok!

@colleenpridemore colleenpridemore marked this pull request as ready for review January 30, 2026 18:39
Copilot AI review requested due to automatic review settings January 30, 2026 18:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a dedicated integration testing pipeline backed by a PostgreSQL service, including automated schema lifecycle management and test data utilities, to make CI and local integration test runs reproducible.

Changes:

  • Added a GitHub Actions workflow that provisions PostgreSQL and runs the integration test suite.
  • Added Jest integration globalSetup/globalTeardown to initialize and clean up database schema for integration runs.
  • Introduced a TestDataSeeder utility and updated integration tests + docs to standardize test DB usage.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
.github/workflows/integration-tests.yml New CI workflow to run integration tests with a PostgreSQL service container.
jest.integration.setup.ts Global Jest setup for DB validation, connection test, and schema initialization via migrations.
jest.integration.teardown.ts Global Jest teardown for DB cleanup and connection closure.
jest.integration.config.js Wires integration setup/teardown into Jest and enforces serial execution.
src/database/test-seeder.ts Adds utilities for cleaning and seeding test data for integration tests.
src/__tests__/integration/repository.test.ts Ensures isolation by cleaning DB before/after integration tests using the new seeder.
docs/INTEGRATION_TEST_IMPLEMENTATION_SUMMARY.md Summarizes the integration test infrastructure additions and usage.
docs/INTEGRATION_TESTING.md Full guide for local + CI integration testing setup and troubleshooting.
docs/INTEGRATION_TESTING_QUICKREF.md Quick reference for common commands and fixes.
database/README.md Adds an integration testing section pointing to the new guides/utilities.
README.md Updates top-level testing instructions to include integration tests.
.env.test Adds a template environment file for local integration test configuration.

Comment thread jest.integration.setup.ts
Comment on lines +44 to +77
// Create database client
globalDb = new DatabaseClient();

// Test database connection
console.log('Testing database connection...');
const isConnected = await globalDb.testConnection();

if (!isConnected) {
throw new Error('Failed to connect to test database. Please ensure PostgreSQL is running.');
}

console.log('✓ Database connection successful');

// Run migrations to ensure schema is up to date
console.log('Running database migrations...');
const migrationRunner = new MigrationRunner(globalDb);

try {
// First, clean up any existing schema
try {
await migrationRunner.down();
console.log('✓ Cleaned up existing schema');
} catch (error) {
// Ignore errors if schema doesn't exist
console.log('No existing schema to clean up');
}

// Apply fresh schema
await migrationRunner.up();
console.log('✓ Database schema initialized');
} catch (error) {
console.error('✗ Migration failed:', error);
throw error;
}
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

globalDb is created in globalSetup but never closed. Because DatabaseClient owns a pg.Pool, leaving it open can keep Jest from exiting (open handle) and leak connections in CI. Consider making the setup client short-lived (run migrations, then await globalDb.close()), or refactor so the same pool is reused and closed in teardown (e.g., via a shared singleton).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already fixed in commit d5464bb. The globalDb connection is now properly closed after migrations (line 81) and in the error path (line 76) to prevent connection leaks and Jest hanging.

Comment thread jest.integration.teardown.ts Outdated
Comment on lines +9 to +10
// Teardown grace period to allow async operations to complete
const TEARDOWN_GRACE_PERIOD_MS = 2000;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TEARDOWN_GRACE_PERIOD_MS is hardcoded, but the PR description states this grace period is configurable via TEARDOWN_GRACE_PERIOD_MS. To match the intended behavior, read it from process.env.TEARDOWN_GRACE_PERIOD_MS with a safe numeric default and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +68
echo "Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if pg_isready -h localhost -p 5432 -U vexel_test_user; then
echo "PostgreSQL is ready!"
break
fi
echo "Attempt $i: PostgreSQL not ready yet..."
sleep 2
done
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "Wait for PostgreSQL" loop doesn't fail the step if the database never becomes ready (it just finishes the loop and continues). Add an explicit failure after the loop (e.g., track readiness and exit 1 if not ready) so the workflow fails fast with a clear message.

Suggested change
echo "Waiting for PostgreSQL to be ready..."
for i in {1..30}; do
if pg_isready -h localhost -p 5432 -U vexel_test_user; then
echo "PostgreSQL is ready!"
break
fi
echo "Attempt $i: PostgreSQL not ready yet..."
sleep 2
done
echo "Waiting for PostgreSQL to be ready..."
postgres_ready=false
for i in {1..30}; do
if pg_isready -h localhost -p 5432 -U vexel_test_user; then
echo "PostgreSQL is ready!"
postgres_ready=true
break
fi
echo "Attempt $i: PostgreSQL not ready yet..."
sleep 2
done
if [ "$postgres_ready" != "true" ]; then
echo "PostgreSQL did not become ready after 30 attempts. Failing the workflow."
exit 1
fi

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/integration-tests.yml Outdated
Comment on lines +74 to +85
- name: Initialize database schema
run: |
echo "Running database migrations..."
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -f database/schema.sql
echo "Database schema initialized successfully"

- name: Verify database schema
run: |
echo "Verifying database tables..."
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -c "\dt"
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -c "\dT"

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This workflow initializes the schema via psql -f database/schema.sql, but jest.integration.setup.ts also performs a down/up cycle using the same schema/rollback scripts. This duplication adds time and increases the chance of drift between CI and local behavior. Consider removing the explicit schema initialization step here and rely on Jest globalSetup for a single source of truth (keeping only a simple connection/health check).

Suggested change
- name: Initialize database schema
run: |
echo "Running database migrations..."
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -f database/schema.sql
echo "Database schema initialized successfully"
- name: Verify database schema
run: |
echo "Verifying database tables..."
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -c "\dt"
psql -h localhost -p 5432 -U vexel_test_user -d vexel_test -c "\dT"

Copilot uses AI. Check for mistakes.
Comment thread src/database/test-seeder.ts Outdated
Comment on lines +36 to +44
await this.db.query('DELETE FROM capability_vectors');
await this.db.query('DELETE FROM agent_status_history');
await this.db.query('DELETE FROM ipfs_metadata');
await this.db.query('DELETE FROM agents');
}

/**
* Seed test agents
*/
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanAll() issues multiple DELETE statements every time it runs. Given the FK relationships are ON DELETE CASCADE, you can simplify this and speed up tests by using a single TRUNCATE agents RESTART IDENTITY CASCADE (or TRUNCATE all tables) instead of multiple deletes. This will significantly reduce test runtime as the integration suite grows.

Suggested change
await this.db.query('DELETE FROM capability_vectors');
await this.db.query('DELETE FROM agent_status_history');
await this.db.query('DELETE FROM ipfs_metadata');
await this.db.query('DELETE FROM agents');
}
/**
* Seed test agents
*/
// Use TRUNCATE with CASCADE to efficiently clear agents and all dependent tables
await this.db.query('TRUNCATE TABLE agents RESTART IDENTITY CASCADE');
}
/**
* Seed test agents
*/
* Seed test agents
*/

Copilot uses AI. Check for mistakes.
Comment thread src/database/test-seeder.ts Outdated
Comment on lines +98 to +100
// Generate unique DID with UUID to prevent collisions
const uniqueId = `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment says "Generate unique DID with UUID" but the implementation uses Date.now() + Math.random(). Either update the comment to match the actual approach, or switch to a real UUID generator to align with the stated intent.

Copilot uses AI. Check for mistakes.
@colleenpridemore
Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

…mize cleanAll

Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 30, 2026

@copilot apply changes based on the comments in this thread

Applied all review feedback in commit d5464bb:

  1. Fixed connection leak - globalDb now closes after migrations to prevent Jest hanging
  2. Configurable grace period - TEARDOWN_GRACE_PERIOD_MS reads from env with 2000ms default
  3. Fail-fast PostgreSQL check - Workflow exits with error if database doesn't become ready
  4. Removed duplicate schema init - Workflow no longer runs schema SQL (Jest setup handles it)
  5. Optimized cleanup - cleanAll() uses TRUNCATE CASCADE instead of multiple DELETEs
  6. Fixed comment - Updated to match actual implementation (timestamp+random, not UUID)

Copilot AI and others added 2 commits January 30, 2026 19:06
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Co-authored-by: colleenpridemore <4281084+colleenpridemore@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@colleenpridemore colleenpridemore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok!

Copy link
Copy Markdown
Contributor

Superseded by #100

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P0] Create Integration Test Workflow with PostgreSQL Service

3 participants