diff --git a/.gitea/workflows/docker-build.yml b/.gitea/workflows/docker-build.yml index ed5b91e..5003fd3 100644 --- a/.gitea/workflows/docker-build.yml +++ b/.gitea/workflows/docker-build.yml @@ -51,30 +51,23 @@ jobs: sleep 2 done - - name: 🧪 Test image - Verify extensions + - name: ⚙️ Setup Tests run: | - # Wait a bit more for init scripts to complete - sleep 5 - - # Check extensions are installed - RESULT=$(docker exec test-pg${{ matrix.pg_version }} psql -U postgres -t -c \ - "SELECT count(*) FROM pg_extension WHERE extname IN ('timescaledb', 'vector', 'vchord');") - - EXTENSIONS=$(echo $RESULT | tr -d ' ') - echo "Found $EXTENSIONS extensions" - - if [ "$EXTENSIONS" -eq "3" ]; then - echo "✅ All 3 extensions are installed!" - else - echo "❌ Expected 3 extensions, found $EXTENSIONS" - docker exec test-pg${{ matrix.pg_version }} psql -U postgres -c \ - "SELECT extname, extversion FROM pg_extension;" - exit 1 - fi - - # Show extension versions - docker exec test-pg${{ matrix.pg_version }} psql -U postgres -c \ - "SELECT extname, extversion FROM pg_extension WHERE extname IN ('timescaledb', 'vector', 'vchord');" + # Wait for valid startup + sleep 10 + docker cp tests/ test-pg${{ matrix.pg_version }}:/tmp/tests/ + + - name: "🧪 Test 1: Configuration" + run: docker exec test-pg${{ matrix.pg_version }} psql -U postgres -f /tmp/tests/test-1-config.sql + + - name: "🧪 Test 2: TimescaleDB" + run: docker exec test-pg${{ matrix.pg_version }} psql -U postgres -f /tmp/tests/test-2-timescale.sql + + - name: "🧪 Test 3: VectorChord" + run: docker exec test-pg${{ matrix.pg_version }} psql -U postgres -f /tmp/tests/test-3-vector.sql + + - name: "🧪 Test 4: Hybrid Scenarios" + run: docker exec test-pg${{ matrix.pg_version }} psql -U postgres -f /tmp/tests/test-4-hybrid.sql - name: 🧹 Cleanup test container if: always() @@ -101,4 +94,10 @@ jobs: tags: | gitea.killinger.fr/maxime.killinger/postgres-ts-vectors:latest + - name: 🧹 Cleanup Docker images + if: always() + run: | + docker rmi postgres-ts-vectors:pg${{ matrix.pg_version }}-test || true + docker image prune -f + diff --git a/tests/test-1-config.sql b/tests/test-1-config.sql new file mode 100644 index 0000000..cc2caca --- /dev/null +++ b/tests/test-1-config.sql @@ -0,0 +1,17 @@ +-- Test 1: Configuration +\set ON_ERROR_STOP on + +SELECT version(); +SELECT extname, extversion FROM pg_extension; + +DO $$ +DECLARE + preload_libs text; +BEGIN + SELECT setting INTO preload_libs FROM pg_settings WHERE name = 'shared_preload_libraries'; + IF preload_libs NOT LIKE '%timescaledb%' OR preload_libs NOT LIKE '%vchord%' THEN + RAISE EXCEPTION 'Missing shared_preload_libraries config. Found: %', preload_libs; + END IF; + RAISE NOTICE 'Configuration Check: OK'; +END +$$; diff --git a/tests/test-2-timescale.sql b/tests/test-2-timescale.sql new file mode 100644 index 0000000..68f22f5 --- /dev/null +++ b/tests/test-2-timescale.sql @@ -0,0 +1,31 @@ +-- Test 2: TimescaleDB +\set ON_ERROR_STOP on + +DROP TABLE IF EXISTS sensors CASCADE; + +CREATE TABLE sensors ( + time TIMESTAMPTZ NOT NULL, + sensor_id INTEGER, + temperature DOUBLE PRECISION +); + +-- Convert to hypertable +SELECT create_hypertable('sensors', 'time'); + +-- Insert data +INSERT INTO sensors (time, sensor_id, temperature) VALUES + (NOW(), 1, 20.0), + (NOW() + INTERVAL '1 hour', 1, 22.0); + +-- Query data +DO $$ +DECLARE + count int; +BEGIN + SELECT count(*) INTO count FROM sensors; + IF count != 2 THEN + RAISE EXCEPTION 'Hypertable insert failed'; + END IF; + RAISE NOTICE 'TimescaleDB Check: OK'; +END +$$; diff --git a/tests/test-3-vector.sql b/tests/test-3-vector.sql new file mode 100644 index 0000000..67a6b3b --- /dev/null +++ b/tests/test-3-vector.sql @@ -0,0 +1,27 @@ +-- Test 3: VectorChord / pgvector +\set ON_ERROR_STOP on + +DROP TABLE IF EXISTS items; + +CREATE TABLE items ( + id bigserial PRIMARY KEY, + embedding vector(3) +); + +INSERT INTO items (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'), ('[1.1, 2.1, 3.1]'); + +-- Create VectorChord Index +CREATE INDEX ON items USING vchordrq (embedding vector_l2_ops); + +-- Search +DO $$ +DECLARE + closest_id int; +BEGIN + SELECT id INTO closest_id FROM items ORDER BY embedding <-> '[1,2,3]' LIMIT 1; + IF closest_id != 1 THEN + RAISE EXCEPTION 'Vector search failed. Expected ID 1, got %', closest_id; + END IF; + RAISE NOTICE 'Vector Check: OK'; +END +$$; diff --git a/tests/test-4-hybrid.sql b/tests/test-4-hybrid.sql new file mode 100644 index 0000000..3dc0f8e --- /dev/null +++ b/tests/test-4-hybrid.sql @@ -0,0 +1,40 @@ +-- Test 4: Hybrid (Timescale + Vector) +\set ON_ERROR_STOP on + +DROP TABLE IF EXISTS hybrid_logs; + +CREATE TABLE hybrid_logs ( + time TIMESTAMPTZ NOT NULL, + msg TEXT, + vec vector(2) +); + +SELECT create_hypertable('hybrid_logs', 'time'); + +INSERT INTO hybrid_logs (time, msg, vec) VALUES + (NOW(), 'log1', '[0,0]'), + (NOW() - INTERVAL '1 day', 'old_log', '[1,1]'); + +-- Index +CREATE INDEX ON hybrid_logs USING vchordrq (vec vector_l2_ops); + +-- Hybrid Query +DO $$ +DECLARE + res_count int; +BEGIN + -- Recent logs similar to [0.1, 0.1] + SELECT count(*) INTO res_count + FROM ( + SELECT * FROM hybrid_logs + WHERE time > NOW() - INTERVAL '1 hour' + ORDER BY vec <-> '[0.1, 0.1]' + LIMIT 1 + ) sub; + + IF res_count != 1 THEN + RAISE EXCEPTION 'Hybrid query failed'; + END IF; + RAISE NOTICE 'Hybrid Check: OK'; +END +$$;