-- ================================================================================================ -- 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;