141 lines
4.2 KiB
PL/PgSQL
141 lines
4.2 KiB
PL/PgSQL
\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;
|