\set ON_ERROR_STOP on BEGIN; CREATE OR REPLACE FUNCTION pg_temp.assert_true(condition boolean, message text) RETURNS void LANGUAGE plpgsql AS $$ BEGIN IF condition IS NOT TRUE THEN RAISE EXCEPTION 'assertion_failed: %', message; END IF; END; $$; INSERT INTO auth.users ( id, aud, role, email, encrypted_password, email_confirmed_at, raw_app_meta_data, raw_user_meta_data, created_at, updated_at ) VALUES ( '20000000-0000-4000-8000-000000000001', 'authenticated', 'authenticated', 'runtime-one@example.invalid', crypt('fixture-password', gen_salt('bf')), now(), '{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now() ), ( '20000000-0000-4000-8000-000000000002', 'authenticated', 'authenticated', 'runtime-two@example.invalid', crypt('fixture-password', gen_salt('bf')), now(), '{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now() ); UPDATE public.subscriptions SET tier = 'free', status = 'active', overage_credits = 0 WHERE user_id IN ( '20000000-0000-4000-8000-000000000001', '20000000-0000-4000-8000-000000000002' ); SELECT pg_temp.assert_true( NOT has_function_privilege( 'authenticated', 'public.grant_verified_ad_reward(uuid,text,text,text,text,integer)', 'EXECUTE' ), 'authenticated users must not grant their own ad rewards' ); SELECT pg_temp.assert_true( NOT has_table_privilege('authenticated', 'public.ad_reward_receipts', 'SELECT'), 'authenticated users must not read verified ad callback receipts' ); SELECT pg_temp.assert_true( has_function_privilege('authenticated', 'public.mobile_dashboard_stats()', 'EXECUTE'), 'authenticated users must be able to read their dashboard aggregate' ); SELECT pg_temp.assert_true( NOT has_function_privilege('anon', 'public.mobile_dashboard_stats()', 'EXECUTE'), 'anonymous users must not execute dashboard aggregates' ); DO $$ DECLARE first_claim jsonb; duplicate_claim jsonb; cooldown_claim jsonb; cooldown_replay jsonb; capped_claim jsonb; balance integer; BEGIN first_claim := public.grant_verified_ad_reward( '20000000-0000-4000-8000-000000000001', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-reward-transaction-0001', 50 ); PERFORM pg_temp.assert_true((first_claim->>'granted')::boolean, 'first reward is granted'); duplicate_claim := public.grant_verified_ad_reward( '20000000-0000-4000-8000-000000000001', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-reward-transaction-0001', 50 ); PERFORM pg_temp.assert_true( duplicate_claim->>'reason' = 'duplicate', 'transaction replay is idempotent' ); cooldown_claim := public.grant_verified_ad_reward( '20000000-0000-4000-8000-000000000001', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-reward-transaction-0002', 50 ); PERFORM pg_temp.assert_true( cooldown_claim->>'reason' = 'cooldown', 'distinct immediate callback is rate limited' ); cooldown_replay := public.grant_verified_ad_reward( '20000000-0000-4000-8000-000000000001', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-reward-transaction-0002', 50 ); PERFORM pg_temp.assert_true( cooldown_replay->>'reason' = 'duplicate', 'a cooldown receipt remains consumed and can never become grantable' ); PERFORM pg_temp.assert_true( (SELECT count(*) FROM public.ad_reward_claims WHERE transaction_id = 'runtime-reward-transaction-0002') = 0, 'a replayed cooldown receipt never creates a grant claim' ); SELECT overage_credits INTO balance FROM public.subscriptions WHERE user_id = '20000000-0000-4000-8000-000000000001'; PERFORM pg_temp.assert_true(balance = 50, 'only one callback changes the balance'); INSERT INTO public.ad_reward_claims ( user_id, network, placement, ad_unit_id, transaction_id, reward_tokens, verified_at ) SELECT '20000000-0000-4000-8000-000000000002', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-cap-' || lpad(number::text, 3, '0'), 50, date_trunc('day', now()) + (number * interval '20 seconds') FROM generate_series(1, 20) AS number; capped_claim := public.grant_verified_ad_reward( '20000000-0000-4000-8000-000000000002', 'admob:fixture', 'rewarded_video_quota', '5224354917', 'runtime-cap-overflow-transaction', 50 ); PERFORM pg_temp.assert_true( capped_claim->>'reason' = 'daily_cap', 'daily reward cap is enforced before another credit grant' ); END; $$; INSERT INTO public.history ( id, user_id, title, original_text, mode, status, duration, word_count, app_version, created_at, updated_at ) VALUES ( '21000000-0000-4000-8000-000000000001', '20000000-0000-4000-8000-000000000001', 'Today', 'today transcript', 'dictation', 'completed', 60, 10, '1.0.0', now(), now() ), ( '21000000-0000-4000-8000-000000000002', '20000000-0000-4000-8000-000000000001', 'Yesterday', 'yesterday transcript', 'file-transcription', 'completed', 120, 20, '1.0.0', now() - interval '1 day', now() - interval '1 day' ), ( '21000000-0000-4000-8000-000000000003', '20000000-0000-4000-8000-000000000001', 'Older', 'older transcript', 'dictation', 'completed', 30, 5, '1.0.0', now() - interval '3 days', now() - interval '3 days' ), ( '21000000-0000-4000-8000-000000000004', '20000000-0000-4000-8000-000000000001', 'Error', 'failed transcript', 'dictation', 'error', 999, 999, '1.0.0', now(), now() ), ( '21000000-0000-4000-8000-000000000005', '20000000-0000-4000-8000-000000000002', 'Other user', 'private transcript', 'dictation', 'completed', 500, 500, '1.0.0', now(), now() ); SET LOCAL ROLE authenticated; SELECT set_config( 'request.jwt.claims', '{"sub":"20000000-0000-4000-8000-000000000001","role":"authenticated"}', true ); DO $$ DECLARE stats jsonb := public.mobile_dashboard_stats(); BEGIN PERFORM pg_temp.assert_true((stats->>'total_sessions')::integer = 3, 'completed own sessions counted'); PERFORM pg_temp.assert_true((stats->>'total_recording_seconds')::numeric = 210, 'duration is exact'); PERFORM pg_temp.assert_true((stats->>'total_word_count')::integer = 35, 'word count is exact'); PERFORM pg_temp.assert_true((stats->>'today_sessions')::integer = 1, 'UTC today count is exact'); PERFORM pg_temp.assert_true((stats->>'streak_days')::integer = 2, 'consecutive streak stops at gap'); PERFORM pg_temp.assert_true(jsonb_array_length(stats->'recent_history') = 3, 'recent history excludes errors and other users'); END; $$; RESET ROLE; ROLLBACK;