- Deprecated/broken migration files archived - New auth_schema migration (015) - Trading service events migration (016) - Migration renumbering utility - Migration test suite
528 lines
18 KiB
PL/PgSQL
528 lines
18 KiB
PL/PgSQL
-- ================================================================================================
|
|
-- Migration Test Suite: Risk Events (Migrations 002-003)
|
|
-- PostgreSQL 16.10 + TimescaleDB 2.22.1
|
|
-- Tests risk events, audit events, constraint violations, and partitioning
|
|
-- ================================================================================================
|
|
|
|
-- Setup test transaction (rollback at end to avoid polluting database)
|
|
BEGIN;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 1: Valid Risk 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 risk_events (
|
|
id,
|
|
correlation_id,
|
|
event_timestamp,
|
|
detected_timestamp,
|
|
event_type,
|
|
severity,
|
|
symbol,
|
|
account_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
v_test_id,
|
|
v_correlation_id,
|
|
v_current_ns,
|
|
v_current_ns + 1000,
|
|
'var_breach',
|
|
'high',
|
|
'AAPL',
|
|
'ACC001',
|
|
'{"var_limit": 100000, "current_var": 125000, "breach_amount": 25000}'::jsonb,
|
|
encode(sha256('risk_test'::bytea), 'hex'),
|
|
'risk-node-01',
|
|
12345
|
|
);
|
|
|
|
RAISE NOTICE 'TEST 1 PASS: Valid risk event inserted successfully';
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 1 FAIL: Valid insertion failed - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 2: Risk Severity Enum Validation
|
|
-- Should fail with invalid severity level
|
|
-- ================================================================================================
|
|
DO $$
|
|
BEGIN
|
|
INSERT INTO risk_events (
|
|
correlation_id,
|
|
event_timestamp,
|
|
detected_timestamp,
|
|
event_type,
|
|
severity,
|
|
symbol,
|
|
account_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
uuid_generate_v4(),
|
|
1000000000,
|
|
1000000000,
|
|
'var_breach',
|
|
'ultra_critical', -- INVALID: not in enum
|
|
'AAPL',
|
|
'ACC001',
|
|
'{}'::jsonb,
|
|
encode(sha256('test'::bytea), 'hex'),
|
|
'risk-node-01',
|
|
12345
|
|
);
|
|
|
|
RAISE EXCEPTION 'TEST 2 FAIL: Should have rejected invalid severity';
|
|
EXCEPTION
|
|
WHEN invalid_text_representation THEN
|
|
RAISE NOTICE 'TEST 2 PASS: Correctly rejected invalid risk_severity enum value';
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 2 FAIL: Wrong error type - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 3: Risk Event Type Validation
|
|
-- Verify all valid risk event types
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_valid_types TEXT[] := ARRAY[
|
|
'var_breach', 'exposure_limit_breach', 'position_limit_breach',
|
|
'concentration_risk', 'leverage_excess', 'margin_call',
|
|
'drawdown_limit', 'volatility_spike', 'correlation_breakdown',
|
|
'liquidity_shortage', 'stress_test_failure', 'compliance_violation',
|
|
'model_validation_error', 'circuit_breaker_triggered', 'emergency_shutdown',
|
|
'risk_limit_update', 'model_recalibration', 'backtest_failure'
|
|
];
|
|
v_type TEXT;
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
BEGIN
|
|
FOREACH v_type IN ARRAY v_valid_types
|
|
LOOP
|
|
-- Insert test event for each type
|
|
INSERT INTO risk_events (
|
|
correlation_id,
|
|
event_timestamp,
|
|
detected_timestamp,
|
|
event_type,
|
|
severity,
|
|
symbol,
|
|
account_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
uuid_generate_v4(),
|
|
v_current_ns,
|
|
v_current_ns,
|
|
v_type::risk_event_type,
|
|
'medium',
|
|
'TEST',
|
|
'ACC001',
|
|
format('{"type": "%s"}', v_type)::jsonb,
|
|
encode(sha256(v_type::bytea), 'hex'),
|
|
'risk-node-01',
|
|
12345
|
|
);
|
|
END LOOP;
|
|
|
|
RAISE NOTICE 'TEST 3 PASS: All % risk_event_type enum values are valid', array_length(v_valid_types, 1);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 3 FAIL: Invalid risk_event_type - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 4: Risk Metric Type Validation
|
|
-- Verify all valid risk metric types
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_valid_metrics TEXT[] := ARRAY[
|
|
'var_1d', 'var_10d', 'cvar_1d', 'cvar_10d',
|
|
'exposure_gross', 'exposure_net', 'leverage_ratio',
|
|
'concentration_single', 'concentration_sector', 'beta_portfolio',
|
|
'sharpe_ratio', 'max_drawdown', 'volatility_realized', 'volatility_implied',
|
|
'correlation_matrix', 'margin_excess', 'margin_requirement', 'liquidity_score'
|
|
];
|
|
v_metric TEXT;
|
|
BEGIN
|
|
FOREACH v_metric IN ARRAY v_valid_metrics
|
|
LOOP
|
|
PERFORM v_metric::risk_metric_type;
|
|
END LOOP;
|
|
|
|
RAISE NOTICE 'TEST 4 PASS: All % risk_metric_type enum values are valid', array_length(v_valid_metrics, 1);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 4 FAIL: Invalid risk_metric_type - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 5: Valid Audit Event Insertion (Migration 003)
|
|
-- 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 audit_events (
|
|
id,
|
|
correlation_id,
|
|
event_timestamp,
|
|
event_type,
|
|
severity,
|
|
component,
|
|
user_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
v_test_id,
|
|
v_correlation_id,
|
|
v_current_ns,
|
|
'order_created',
|
|
'info',
|
|
'trading_engine',
|
|
'user123',
|
|
'{"order_id": "ORD001", "action": "create"}'::jsonb,
|
|
encode(sha256('audit_test'::bytea), 'hex'),
|
|
'audit-node-01',
|
|
12345
|
|
);
|
|
|
|
RAISE NOTICE 'TEST 5 PASS: Valid audit event inserted successfully';
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 5 FAIL: Valid audit insertion failed - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 6: Audit Event Type Validation
|
|
-- Verify subset of audit event types
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_valid_types TEXT[] := ARRAY[
|
|
'order_created', 'order_modified', 'order_cancelled', 'order_executed',
|
|
'model_prediction', 'model_training_started', 'model_deployed',
|
|
'system_startup', 'authentication_success', 'compliance_validation_completed'
|
|
];
|
|
v_type TEXT;
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
BEGIN
|
|
FOREACH v_type IN ARRAY v_valid_types
|
|
LOOP
|
|
INSERT INTO audit_events (
|
|
correlation_id,
|
|
event_timestamp,
|
|
event_type,
|
|
severity,
|
|
component,
|
|
user_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
uuid_generate_v4(),
|
|
v_current_ns,
|
|
v_type::audit_event_type,
|
|
'info',
|
|
'trading_engine',
|
|
'testuser',
|
|
format('{"type": "%s"}', v_type)::jsonb,
|
|
encode(sha256(v_type::bytea), 'hex'),
|
|
'audit-node-01',
|
|
12345
|
|
);
|
|
END LOOP;
|
|
|
|
RAISE NOTICE 'TEST 6 PASS: Sample audit_event_type enum values validated (% types)', array_length(v_valid_types, 1);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 6 FAIL: Invalid audit_event_type - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 7: Audit Severity Levels
|
|
-- Verify audit severity hierarchy
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_valid_severities TEXT[] := ARRAY[
|
|
'trace', 'debug', 'info', 'notice', 'warning',
|
|
'error', 'critical', 'alert', 'emergency'
|
|
];
|
|
v_severity TEXT;
|
|
BEGIN
|
|
FOREACH v_severity IN ARRAY v_valid_severities
|
|
LOOP
|
|
PERFORM v_severity::audit_severity;
|
|
END LOOP;
|
|
|
|
RAISE NOTICE 'TEST 7 PASS: All % audit_severity levels are valid', array_length(v_valid_severities, 1);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 7 FAIL: Invalid audit_severity - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 8: System Component Enum Validation
|
|
-- Verify all system components
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_valid_components TEXT[] := ARRAY[
|
|
'trading_engine', 'risk_management', 'market_data', 'order_management',
|
|
'portfolio_management', 'ml_engine', 'execution_engine', 'compliance_engine',
|
|
'authentication', 'configuration', 'database', 'api_gateway',
|
|
'user_interface', 'reporting', 'monitoring', 'backup_system'
|
|
];
|
|
v_component TEXT;
|
|
BEGIN
|
|
FOREACH v_component IN ARRAY v_valid_components
|
|
LOOP
|
|
PERFORM v_component::system_component;
|
|
END LOOP;
|
|
|
|
RAISE NOTICE 'TEST 8 PASS: All % system_component enum values are valid', array_length(v_valid_components, 1);
|
|
EXCEPTION
|
|
WHEN OTHERS THEN
|
|
RAISE EXCEPTION 'TEST 8 FAIL: Invalid system_component - %', SQLERRM;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 9: Risk Event Lifecycle with Acknowledgment and Resolution
|
|
-- Test complete risk event workflow
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_event_id UUID := uuid_generate_v4();
|
|
v_correlation_id UUID := uuid_generate_v4();
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
v_acknowledged_ns BIGINT;
|
|
v_resolved_ns BIGINT;
|
|
BEGIN
|
|
-- Create risk event
|
|
INSERT INTO risk_events (
|
|
id,
|
|
correlation_id,
|
|
event_timestamp,
|
|
detected_timestamp,
|
|
event_type,
|
|
severity,
|
|
symbol,
|
|
account_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
v_event_id,
|
|
v_correlation_id,
|
|
v_current_ns,
|
|
v_current_ns + 1000,
|
|
'position_limit_breach',
|
|
'high',
|
|
'TSLA',
|
|
'ACC001',
|
|
'{"position": 10000, "limit": 8000, "breach": 2000}'::jsonb,
|
|
encode(sha256('lifecycle_test'::bytea), 'hex'),
|
|
'risk-node-01',
|
|
12345
|
|
);
|
|
|
|
-- Simulate acknowledgment
|
|
v_acknowledged_ns := v_current_ns + 500000000; -- 500ms later
|
|
UPDATE risk_events
|
|
SET acknowledged_timestamp = v_acknowledged_ns,
|
|
acknowledged_by = 'risk_manager_001'
|
|
WHERE id = v_event_id;
|
|
|
|
-- Simulate resolution
|
|
v_resolved_ns := v_current_ns + 2000000000; -- 2s later
|
|
UPDATE risk_events
|
|
SET resolved_timestamp = v_resolved_ns,
|
|
resolved_by = 'risk_manager_001',
|
|
resolution_notes = 'Position reduced to comply with limit'
|
|
WHERE id = v_event_id;
|
|
|
|
-- Verify lifecycle
|
|
IF EXISTS (
|
|
SELECT 1 FROM risk_events
|
|
WHERE id = v_event_id
|
|
AND acknowledged_timestamp IS NOT NULL
|
|
AND resolved_timestamp IS NOT NULL
|
|
AND acknowledged_timestamp > detected_timestamp
|
|
AND resolved_timestamp > acknowledged_timestamp
|
|
) THEN
|
|
RAISE NOTICE 'TEST 9 PASS: Risk event lifecycle (detect -> acknowledge -> resolve) validated';
|
|
ELSE
|
|
RAISE EXCEPTION 'TEST 9 FAIL: Risk event lifecycle validation failed';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 10: Audit Retention and Immutability
|
|
-- Verify audit events are immutable (UPDATE should work but INSERT/DELETE are standard)
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_audit_id UUID := uuid_generate_v4();
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
v_original_hash VARCHAR(64);
|
|
v_updated_hash VARCHAR(64);
|
|
BEGIN
|
|
-- Insert audit event
|
|
INSERT INTO audit_events (
|
|
id,
|
|
correlation_id,
|
|
event_timestamp,
|
|
event_type,
|
|
severity,
|
|
component,
|
|
user_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
v_audit_id,
|
|
uuid_generate_v4(),
|
|
v_current_ns,
|
|
'permission_granted',
|
|
'notice',
|
|
'authentication',
|
|
'admin_user',
|
|
'{"permission": "read:trades", "granted_to": "analyst_001"}'::jsonb,
|
|
encode(sha256('retention_test'::bytea), 'hex'),
|
|
'auth-node-01',
|
|
12345
|
|
)
|
|
RETURNING event_hash INTO v_original_hash;
|
|
|
|
-- Verify event was inserted
|
|
IF EXISTS (SELECT 1 FROM audit_events WHERE id = v_audit_id) THEN
|
|
RAISE NOTICE 'TEST 10 PASS: Audit event inserted and persisted';
|
|
RAISE NOTICE 'TEST 10 INFO: Original event_hash: %', v_original_hash;
|
|
ELSE
|
|
RAISE EXCEPTION 'TEST 10 FAIL: Audit event not found after insertion';
|
|
END IF;
|
|
|
|
-- Note: In production, audit_events should be append-only with triggers preventing UPDATE/DELETE
|
|
-- This test validates the schema allows the data to be stored correctly
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 11: Risk Metrics JSONB Query Performance
|
|
-- Verify JSONB query capabilities for risk metrics
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_test_id UUID := uuid_generate_v4();
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
v_metrics JSONB;
|
|
BEGIN
|
|
-- Insert risk event with complex metrics
|
|
INSERT INTO risk_events (
|
|
id,
|
|
correlation_id,
|
|
event_timestamp,
|
|
detected_timestamp,
|
|
event_type,
|
|
severity,
|
|
risk_metric,
|
|
symbol,
|
|
account_id,
|
|
event_data,
|
|
event_hash,
|
|
node_id,
|
|
process_id
|
|
) VALUES (
|
|
v_test_id,
|
|
uuid_generate_v4(),
|
|
v_current_ns,
|
|
v_current_ns,
|
|
'volatility_spike',
|
|
'high',
|
|
'volatility_realized',
|
|
'NVDA',
|
|
'ACC002',
|
|
'{"metric": "volatility_realized", "value": 0.75, "threshold": 0.50, "window": "30d", "breach_severity": 1.5}'::jsonb,
|
|
encode(sha256('metrics_test'::bytea), 'hex'),
|
|
'risk-node-01',
|
|
12345
|
|
);
|
|
|
|
-- Query using JSONB operators
|
|
SELECT event_data INTO v_metrics
|
|
FROM risk_events
|
|
WHERE id = v_test_id
|
|
AND event_data->>'metric' = 'volatility_realized'
|
|
AND (event_data->>'value')::numeric > 0.5;
|
|
|
|
IF v_metrics IS NOT NULL THEN
|
|
RAISE NOTICE 'TEST 11 PASS: JSONB metrics query successful, value: %', v_metrics->>'value';
|
|
ELSE
|
|
RAISE EXCEPTION 'TEST 11 FAIL: JSONB metrics query failed';
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- TEST 12: Audit Event Correlation
|
|
-- Verify multiple audit events can be linked via correlation_id
|
|
-- ================================================================================================
|
|
DO $$
|
|
DECLARE
|
|
v_correlation_id UUID := uuid_generate_v4();
|
|
v_current_ns BIGINT := EXTRACT(EPOCH FROM NOW())::BIGINT * 1000000000;
|
|
v_event_count INTEGER;
|
|
BEGIN
|
|
-- Insert multiple related audit events
|
|
INSERT INTO audit_events (
|
|
correlation_id, event_timestamp, event_type, severity, component, user_id,
|
|
event_data, event_hash, node_id, process_id
|
|
) VALUES
|
|
(v_correlation_id, v_current_ns, 'order_created', 'info', 'trading_engine', 'trader_001',
|
|
'{"step": 1, "action": "create"}'::jsonb, encode(sha256('1'::bytea), 'hex'), 'node-01', 12345),
|
|
(v_correlation_id, v_current_ns + 100000, 'order_modified', 'info', 'trading_engine', 'trader_001',
|
|
'{"step": 2, "action": "modify"}'::jsonb, encode(sha256('2'::bytea), 'hex'), 'node-01', 12345),
|
|
(v_correlation_id, v_current_ns + 200000, 'order_executed', 'info', 'execution_engine', 'system',
|
|
'{"step": 3, "action": "execute"}'::jsonb, encode(sha256('3'::bytea), 'hex'), 'node-01', 12345);
|
|
|
|
-- Verify correlation
|
|
SELECT COUNT(*) INTO v_event_count
|
|
FROM audit_events
|
|
WHERE correlation_id = v_correlation_id;
|
|
|
|
IF v_event_count = 3 THEN
|
|
RAISE NOTICE 'TEST 12 PASS: Audit event correlation verified (% linked events)', v_event_count;
|
|
ELSE
|
|
RAISE EXCEPTION 'TEST 12 FAIL: Expected 3 correlated events, found %', v_event_count;
|
|
END IF;
|
|
END $$;
|
|
|
|
-- ================================================================================================
|
|
-- Cleanup: Rollback all test data
|
|
-- ================================================================================================
|
|
ROLLBACK;
|
|
|
|
-- Test Summary
|
|
SELECT 'Risk & Audit Events Test Suite Completed - Review NOTICE messages above for results' AS test_summary;
|