\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 ( '71000000-0000-4000-8000-000000000001', 'authenticated', 'authenticated', 'recording-owner@example.invalid', crypt('fixture-password', gen_salt('bf')), now(), '{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now() ), ( '71000000-0000-4000-8000-000000000002', 'authenticated', 'authenticated', 'recording-other@example.invalid', crypt('fixture-password', gen_salt('bf')), now(), '{"provider":"email","providers":["email"]}'::jsonb, '{}'::jsonb, now(), now() ); INSERT INTO public.meetings (id, user_id, title, status) VALUES ( '72000000-0000-4000-8000-000000000001', '71000000-0000-4000-8000-000000000001', 'Foreground lifecycle fixture', 'recording' ); INSERT INTO public.audio_files ( id, user_id, meeting_id, source, original_name, storage_key, mime_type, size_bytes, duration_ms, sha256, upload_status ) VALUES ( '73000000-0000-4000-8000-000000000001', '71000000-0000-4000-8000-000000000001', '72000000-0000-4000-8000-000000000001', 'recording', 'fixture.wav', '71000000-0000-4000-8000-000000000001/imports/fixture.wav', 'audio/wav', 32044, 1000, repeat('a', 64), 'uploaded' ); SELECT pg_temp.assert_true( NOT has_function_privilege('anon', 'public.mobile_begin_meeting_recording(uuid)', 'EXECUTE'), 'anonymous users must not mutate meeting recording state' ); SET LOCAL ROLE authenticated; SELECT set_config( 'request.jwt.claims', '{"sub":"71000000-0000-4000-8000-000000000001","role":"authenticated"}', true ); SELECT public.mobile_begin_meeting_recording('72000000-0000-4000-8000-000000000001'); -- Reattach the uploaded fixture after begin_recording intentionally clears stale links. RESET ROLE; UPDATE public.audio_files SET meeting_id = '72000000-0000-4000-8000-000000000001' WHERE id = '73000000-0000-4000-8000-000000000001'; SET LOCAL ROLE authenticated; SELECT set_config( 'request.jwt.claims', '{"sub":"71000000-0000-4000-8000-000000000001","role":"authenticated"}', true ); SELECT public.mobile_queue_meeting_recording( '72000000-0000-4000-8000-000000000001', 1000 ); SELECT public.mobile_begin_meeting_processing( '72000000-0000-4000-8000-000000000001', '73000000-0000-4000-8000-000000000001', 'mobile-meeting:fixture:aaaaaaaa' ); SELECT public.mobile_complete_meeting_processing( '72000000-0000-4000-8000-000000000001', '73000000-0000-4000-8000-000000000001', 'mobile-meeting:fixture:aaaaaaaa', 'real mobile audio transcript', 'en', 'fixture-stt', 1000, 120 ); SELECT pg_temp.assert_true( EXISTS ( SELECT 1 FROM public.meetings WHERE id = '72000000-0000-4000-8000-000000000001' AND status = 'completed' AND raw_transcript = 'real mobile audio transcript' AND audio_storage_key = '71000000-0000-4000-8000-000000000001/imports/fixture.wav' ), 'meeting completion links the transcript and audio atomically' ); SELECT pg_temp.assert_true( EXISTS ( SELECT 1 FROM public.transcripts WHERE meeting_id = '72000000-0000-4000-8000-000000000001' AND segment_index = 0 AND text = 'real mobile audio transcript' ), 'meeting transcript segment is persisted' ); SELECT pg_temp.assert_true( EXISTS ( SELECT 1 FROM public.processing_jobs WHERE meeting_id = '72000000-0000-4000-8000-000000000001' AND audio_file_id = '73000000-0000-4000-8000-000000000001' AND status = 'succeeded' AND progress = 100 ), 'processing job reaches succeeded only after atomic completion' ); DO $$ BEGIN PERFORM set_config( 'request.jwt.claims', '{"sub":"71000000-0000-4000-8000-000000000002","role":"authenticated"}', true ); BEGIN PERFORM public.mobile_begin_meeting_recording( '72000000-0000-4000-8000-000000000001' ); RAISE EXCEPTION 'assertion_failed: another user changed the meeting'; EXCEPTION WHEN insufficient_privilege THEN NULL; END; END; $$; RESET ROLE; ROLLBACK;