Files
foxhunt/migrations/tests/test_trading_events.sql
jgrusewski 0d9f890aa6 🗄️ Wave 112: Migration cleanup and new schemas
- Deprecated/broken migration files archived
- New auth_schema migration (015)
- Trading service events migration (016)
- Migration renumbering utility
- Migration test suite
2025-10-05 22:23:37 +02:00

453 lines
14 KiB
PL/PgSQL

-- ================================================================================================
-- Migration Test Suite: Trading Events (Migration 001)
-- PostgreSQL 16.10 + TimescaleDB 2.22.1
-- Tests constraint violations, valid insertions, partitioning, and index usage
-- ================================================================================================
-- Setup test transaction (rollback at end to avoid polluting database)
BEGIN;
-- ================================================================================================
-- TEST 1: Valid Trading Event Insertion
-- Should succeed with all required fields
-- ================================================================================================
DO $$
DECLARE
v_test_id UUID := uuid_generate_v4();
v_correlation_id UUID := uuid_generate_v4();
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
INSERT INTO trading_events (
id,
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
v_test_id,
v_correlation_id,
v_current_ns,
v_current_ns + 1000,
v_current_ns + 2000,
'order_submitted',
'trading_engine',
'AAPL',
'{"order_id": "TEST001", "price": 150.00, "quantity": 100}'::jsonb,
encode(sha256('test_data'::bytea), 'hex'),
'node-01',
12345
);
RAISE NOTICE 'TEST 1 PASS: Valid trading event inserted successfully';
EXCEPTION
WHEN OTHERS THEN
RAISE EXCEPTION 'TEST 1 FAIL: Valid insertion failed - %', SQLERRM;
END $$;
-- ================================================================================================
-- TEST 2: Constraint Violation - Invalid ns_timestamp (negative value)
-- Should fail with CHECK constraint violation
-- ================================================================================================
DO $$
BEGIN
INSERT INTO trading_events (
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
uuid_generate_v4(),
-1000, -- INVALID: negative timestamp
1000000000,
1000000000,
'order_submitted',
'trading_engine',
'AAPL',
'{}'::jsonb,
encode(sha256('test'::bytea), 'hex'),
'node-01',
12345
);
RAISE EXCEPTION 'TEST 2 FAIL: Should have rejected negative timestamp';
EXCEPTION
WHEN check_violation THEN
RAISE NOTICE 'TEST 2 PASS: Correctly rejected negative ns_timestamp';
WHEN OTHERS THEN
RAISE EXCEPTION 'TEST 2 FAIL: Wrong error type - %', SQLERRM;
END $$;
-- ================================================================================================
-- TEST 3: Constraint Violation - Missing NOT NULL field
-- Should fail with NOT NULL constraint violation
-- ================================================================================================
DO $$
BEGIN
INSERT INTO trading_events (
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
-- symbol is missing (NOT NULL constraint)
event_data,
event_hash,
node_id,
process_id
) VALUES (
uuid_generate_v4(),
1000000000,
1000000000,
1000000000,
'order_submitted',
'trading_engine',
'{}'::jsonb,
encode(sha256('test'::bytea), 'hex'),
'node-01',
12345
);
RAISE EXCEPTION 'TEST 3 FAIL: Should have rejected missing symbol';
EXCEPTION
WHEN not_null_violation THEN
RAISE NOTICE 'TEST 3 PASS: Correctly rejected NULL symbol';
WHEN OTHERS THEN
RAISE EXCEPTION 'TEST 3 FAIL: Wrong error type - %', SQLERRM;
END $$;
-- ================================================================================================
-- TEST 4: Enum Constraint Violation - Invalid event_type
-- Should fail with invalid input for enum type
-- ================================================================================================
DO $$
BEGIN
INSERT INTO trading_events (
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
uuid_generate_v4(),
1000000000,
1000000000,
1000000000,
'invalid_event_type', -- INVALID: not in enum
'trading_engine',
'AAPL',
'{}'::jsonb,
encode(sha256('test'::bytea), 'hex'),
'node-01',
12345
);
RAISE EXCEPTION 'TEST 4 FAIL: Should have rejected invalid event_type';
EXCEPTION
WHEN invalid_text_representation THEN
RAISE NOTICE 'TEST 4 PASS: Correctly rejected invalid event_type enum value';
WHEN OTHERS THEN
RAISE EXCEPTION 'TEST 4 FAIL: Wrong error type - %', SQLERRM;
END $$;
-- ================================================================================================
-- TEST 5: Timestamp Ordering Constraint
-- Processing timestamp should be >= received timestamp >= event timestamp
-- ================================================================================================
DO $$
DECLARE
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
-- Should fail: received < event
INSERT INTO trading_events (
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
uuid_generate_v4(),
v_current_ns,
v_current_ns - 1000, -- INVALID: received before event
v_current_ns,
'order_submitted',
'trading_engine',
'AAPL',
'{}'::jsonb,
encode(sha256('test'::bytea), 'hex'),
'node-01',
12345
);
RAISE EXCEPTION 'TEST 5 FAIL: Should have rejected invalid timestamp ordering';
EXCEPTION
WHEN check_violation THEN
RAISE NOTICE 'TEST 5 PASS: Correctly rejected invalid timestamp ordering';
WHEN OTHERS THEN
RAISE EXCEPTION 'TEST 5 FAIL: Wrong error type - %', SQLERRM;
END $$;
-- ================================================================================================
-- TEST 6: Partition Routing Test
-- Verify events are routed to correct partitions by date
-- ================================================================================================
DO $$
DECLARE
v_test_id UUID := uuid_generate_v4();
v_correlation_id UUID := uuid_generate_v4();
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
v_partition_count INTEGER;
v_expected_date DATE;
BEGIN
-- Insert event
INSERT INTO trading_events (
id,
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
v_test_id,
v_correlation_id,
v_current_ns,
v_current_ns,
v_current_ns,
'order_submitted',
'trading_engine',
'AAPL',
'{"test": "partition_routing"}'::jsonb,
encode(sha256('partition_test'::bytea), 'hex'),
'node-01',
12345
);
-- Verify event_date was auto-populated
SELECT event_date INTO v_expected_date
FROM trading_events
WHERE id = v_test_id;
IF v_expected_date = CURRENT_DATE THEN
RAISE NOTICE 'TEST 6 PASS: Event routed to correct partition (event_date = %)', v_expected_date;
ELSE
RAISE EXCEPTION 'TEST 6 FAIL: Event_date mismatch (expected: %, got: %)', CURRENT_DATE, v_expected_date;
END IF;
-- Check partition exists
SELECT COUNT(*) INTO v_partition_count
FROM pg_tables
WHERE tablename LIKE 'trading_events_%'
AND tablename = 'trading_events_' || to_char(CURRENT_DATE, 'YYYY_MM_DD');
IF v_partition_count > 0 THEN
RAISE NOTICE 'TEST 6 INFO: Partition exists for today (trading_events_%)', to_char(CURRENT_DATE, 'YYYY_MM_DD');
ELSE
RAISE NOTICE 'TEST 6 WARNING: Expected partition not found';
END IF;
END $$;
-- ================================================================================================
-- TEST 7: Index Usage Verification - Symbol Index
-- Verify index is used for symbol queries (EXPLAIN ANALYZE)
-- ================================================================================================
DO $$
DECLARE
v_plan_row RECORD;
v_uses_index BOOLEAN := FALSE;
BEGIN
-- Check query plan for index usage
FOR v_plan_row IN
EXPLAIN (FORMAT TEXT)
SELECT * FROM trading_events WHERE symbol = 'AAPL' LIMIT 100
LOOP
IF v_plan_row."QUERY PLAN" LIKE '%Index%' OR v_plan_row."QUERY PLAN" LIKE '%Bitmap%' THEN
v_uses_index := TRUE;
RAISE NOTICE 'TEST 7 PASS: Index detected - %', v_plan_row."QUERY PLAN";
END IF;
END LOOP;
IF NOT v_uses_index THEN
RAISE NOTICE 'TEST 7 WARNING: No index scan detected (may be seq scan for small tables)';
END IF;
END $$;
-- ================================================================================================
-- TEST 8: JSONB Operations - Event Data Query
-- Verify JSONB indexing and query performance
-- ================================================================================================
DO $$
DECLARE
v_test_id UUID := uuid_generate_v4();
v_correlation_id UUID := uuid_generate_v4();
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
v_result JSONB;
BEGIN
-- Insert event with complex JSONB
INSERT INTO trading_events (
id,
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
v_test_id,
v_correlation_id,
v_current_ns,
v_current_ns,
v_current_ns,
'order_submitted',
'trading_engine',
'AAPL',
'{"order_id": "TEST008", "price": 150.50, "quantity": 1000, "metadata": {"source": "algo"}}'::jsonb,
encode(sha256('jsonb_test'::bytea), 'hex'),
'node-01',
12345
);
-- Query using JSONB operators
SELECT event_data INTO v_result
FROM trading_events
WHERE id = v_test_id
AND event_data->>'order_id' = 'TEST008';
IF v_result IS NOT NULL THEN
RAISE NOTICE 'TEST 8 PASS: JSONB query successful, retrieved: %', v_result;
ELSE
RAISE EXCEPTION 'TEST 8 FAIL: JSONB query failed';
END IF;
END $$;
-- ================================================================================================
-- TEST 9: Order Lifecycle Validation
-- Test complete order workflow: submit -> accept -> fill
-- ================================================================================================
DO $$
DECLARE
v_order_id UUID := uuid_generate_v4();
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
BEGIN
-- Create order
INSERT INTO orders (
id, symbol, side, order_type, time_in_force,
quantity, limit_price, account_id, venue
) VALUES (
v_order_id, 'AAPL', 'buy', 'limit', 'day',
100, 15000, 'ACC001', 'NASDAQ'
);
-- Verify order was created
IF EXISTS (SELECT 1 FROM orders WHERE id = v_order_id AND status = 'pending') THEN
RAISE NOTICE 'TEST 9 PASS: Order created with pending status';
ELSE
RAISE EXCEPTION 'TEST 9 FAIL: Order creation failed';
END IF;
-- Verify trading event was auto-generated by trigger
IF EXISTS (SELECT 1 FROM trading_events WHERE correlation_id = v_order_id AND event_type = 'order_submitted') THEN
RAISE NOTICE 'TEST 9 PASS: Order submission event auto-generated';
ELSE
RAISE EXCEPTION 'TEST 9 FAIL: Order event not generated';
END IF;
END $$;
-- ================================================================================================
-- TEST 10: Performance - Bulk Insert
-- Verify performance of bulk insertions
-- ================================================================================================
DO $$
DECLARE
v_start_time TIMESTAMP;
v_end_time TIMESTAMP;
v_duration INTERVAL;
v_correlation_id UUID := uuid_generate_v4();
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
i INTEGER;
BEGIN
v_start_time := clock_timestamp();
-- Insert 100 events
FOR i IN 1..100 LOOP
INSERT INTO trading_events (
correlation_id,
event_timestamp,
received_timestamp,
processing_timestamp,
event_type,
event_source,
symbol,
event_data,
event_hash,
node_id,
process_id
) VALUES (
v_correlation_id,
v_current_ns + i,
v_current_ns + i,
v_current_ns + i,
'order_submitted',
'trading_engine',
'BULK' || (i % 10),
format('{"order_id": "BULK%s"}', i)::jsonb,
encode(sha256(('bulk' || i)::bytea), 'hex'),
'node-01',
12345
);
END LOOP;
v_end_time := clock_timestamp();
v_duration := v_end_time - v_start_time;
RAISE NOTICE 'TEST 10 PASS: Bulk insert of 100 events completed in %', v_duration;
IF v_duration > INTERVAL '1 second' THEN
RAISE WARNING 'TEST 10 WARNING: Bulk insert took > 1 second, may indicate performance issue';
END IF;
END $$;
-- ================================================================================================
-- Cleanup: Rollback all test data
-- ================================================================================================
ROLLBACK;
-- Test Summary
SELECT 'Trading Events Test Suite Completed - Review NOTICE messages above for results' AS test_summary;