@@ -109,10 +109,22 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
109109 entity_id text NOT NULL, permission_type text NOT NULL);
110110 CREATE TABLE permission_group (id text PRIMARY KEY, organization_id text,
111111 config jsonb, updated_at timestamp);
112- CREATE TABLE workspace_files (id text PRIMARY KEY, project_id text,
113- workspace_id text, context text NOT NULL, size_bytes bigint, deleted_at timestamp);
114- CREATE TABLE workspace_file_version (id text PRIMARY KEY,
115- file_id text REFERENCES workspace_files(id) ON DELETE CASCADE, size_bytes bigint NOT NULL);
112+ CREATE TABLE "user" (id text PRIMARY KEY);
113+ CREATE TABLE folder (LIKE public.folder INCLUDING DEFAULTS, PRIMARY KEY (id));
114+ CREATE TABLE workspace_files (LIKE public.workspace_files INCLUDING DEFAULTS, PRIMARY KEY (id));
115+ ALTER TABLE workspace_files
116+ ALTER COLUMN user_id SET DEFAULT 'user-a',
117+ ALTER COLUMN key SET DEFAULT 'fixture-key',
118+ ALTER COLUMN original_name SET DEFAULT 'fixture.txt',
119+ ALTER COLUMN content_type SET DEFAULT 'text/plain';
120+ CREATE TABLE workspace_file_version (LIKE public.workspace_file_version INCLUDING DEFAULTS,
121+ PRIMARY KEY (id), FOREIGN KEY (file_id) REFERENCES workspace_files(id) ON DELETE CASCADE,
122+ UNIQUE (file_id, version));
123+ ALTER TABLE workspace_file_version
124+ ALTER COLUMN version SET DEFAULT 1,
125+ ALTER COLUMN key SET DEFAULT 'history-key',
126+ ALTER COLUMN content_type SET DEFAULT 'text/plain',
127+ ALTER COLUMN source SET DEFAULT 'unknown';
116128 CREATE TABLE knowledge_base (id text PRIMARY KEY, workspace_id text);
117129 CREATE TABLE document (id text PRIMARY KEY, knowledge_base_id text, connector_id text,
118130 file_size bigint, deleted_at timestamp);
@@ -123,7 +135,8 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
123135
124136 beforeEach ( async ( ) => {
125137 vi . stubEnv ( 'FREE_STORAGE_LIMIT_GB' , '1' )
126- await sql `TRUNCATE workspace_file_version, workspace_files, project, workspace, organization, user_stats, member, subscription, project_workspace, permissions, permission_group`
138+ await sql `TRUNCATE "user", folder, workspace_file_version, workspace_files, project, workspace, organization, user_stats, member, subscription, project_workspace, permissions, permission_group`
139+ await sql `INSERT INTO "user" (id) VALUES ('user-a'), ('user-b')`
127140 await sql `INSERT INTO organization (id) VALUES ('organization-a'), ('organization-b')`
128141 await sql `INSERT INTO user_stats (id, user_id) VALUES ('stats-a', 'user-a'), ('stats-b', 'user-b')`
129142 await sql `INSERT INTO project (id, owner_id, organization_id)
@@ -301,19 +314,32 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
301314 await releaseWrite . promise
302315 } )
303316 await Promise . race ( [ written . promise , write ] )
304- const teardown = database . transaction ( async ( tx ) => {
305- const [ connection ] = await tx . execute < { pid : number } > (
306- query `SELECT pg_backend_pid() AS pid`
317+ const teardown = database
318+ . transaction ( async ( tx ) => {
319+ const [ connection ] = await tx . execute < { pid : number } > (
320+ query `SELECT pg_backend_pid() AS pid`
321+ )
322+ teardownPid . resolve ( connection . pid )
323+ await prepareProjectsForAccountDeletion ( tx , 'user-a' , [ ] )
324+ } )
325+ . then (
326+ ( ) => null ,
327+ ( error : unknown ) => error
307328 )
308- teardownPid . resolve ( connection . pid )
309- await prepareProjectsForAccountDeletion ( tx , 'user-a' , [ ] )
310- } )
311329 try {
312- await waitForDatabaseLock ( await teardownPid . promise )
330+ await Promise . race ( [
331+ waitForDatabaseLock ( await teardownPid . promise ) ,
332+ teardown . then ( ( error ) => {
333+ if ( error ) throw error
334+ throw new Error ( 'Account teardown completed before waiting for the Project write' )
335+ } ) ,
336+ ] )
313337 } finally {
314338 releaseWrite . resolve ( )
339+ await Promise . all ( [ write , teardown ] )
315340 }
316- await Promise . all ( [ write , teardown ] )
341+ const teardownError = await teardown
342+ if ( teardownError ) throw teardownError
317343 expect (
318344 await sql `SELECT user_id, storage_used_bytes::integer AS bytes FROM user_stats ORDER BY user_id`
319345 ) . toEqual ( [
@@ -323,6 +349,9 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
323349 expect ( ( await sql `SELECT owner_id FROM project WHERE id = 'project-a'` ) [ 0 ] . owner_id ) . toBe (
324350 'user-b'
325351 )
352+ expect (
353+ ( await sql `SELECT user_id FROM workspace_files WHERE id = 'project-file'` ) [ 0 ] . user_id
354+ ) . toBe ( 'user-b' )
326355 expect (
327356 ( await sql `SELECT billed_account_user_id FROM workspace WHERE id = 'workspace-a'` ) [ 0 ]
328357 . billed_account_user_id
@@ -404,9 +433,11 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
404433 await database . transaction ( async ( tx ) => {
405434 const prepared = await prepareProjectStorageMutationInTx ( tx , context ( ) )
406435 await tx . execute (
407- query `INSERT INTO workspace_files VALUES ('file', 'project-a', NULL, 'project', 100, NULL)`
436+ query `INSERT INTO workspace_files (id, project_id, workspace_id, context, size_bytes, deleted_at) VALUES ('file', 'project-a', NULL, 'project', 100, NULL)`
437+ )
438+ await tx . execute (
439+ query `INSERT INTO workspace_file_version (id, file_id, size_bytes) VALUES ('version', 'file', 500)`
408440 )
409- await tx . execute ( query `INSERT INTO workspace_file_version VALUES ('version', 'file', 500)` )
410441 await prepared . applyDelta ( 100 )
411442 } )
412443 await database . transaction ( async ( tx ) => {
@@ -441,11 +472,11 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
441472 check (
442473 'moves exact Project heads once across payers, including archived heads but excluding versions' ,
443474 async ( ) => {
444- await sql `INSERT INTO workspace_files VALUES
475+ await sql `INSERT INTO workspace_files (id, project_id, workspace_id, context, size_bytes, deleted_at) VALUES
445476 ('active', 'project-a', NULL, 'project', 40, NULL),
446477 ('archived', 'project-a', NULL, 'project', 60, now()),
447478 ('other', 'project-b', NULL, 'project', 25, NULL)`
448- await sql `INSERT INTO workspace_file_version VALUES ('version', 'active', 900)`
479+ await sql `INSERT INTO workspace_file_version (id, file_id, size_bytes) VALUES ('version', 'active', 900)`
449480 await sql `UPDATE organization SET storage_used_bytes = 125 WHERE id = 'organization-a'`
450481 await database . transaction ( ( tx ) =>
451482 changeProjectStoragePayersInTx ( tx , [
@@ -484,12 +515,12 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
484515 check (
485516 'reconciliation adds Project heads once and refuses incomplete canonical size metadata' ,
486517 async ( ) => {
487- await sql `INSERT INTO workspace_files VALUES
518+ await sql `INSERT INTO workspace_files (id, project_id, workspace_id, context, size_bytes, deleted_at) VALUES
488519 ('workspace-file', NULL, 'workspace-a', 'workspace', 20, NULL),
489520 ('project-file', 'project-a', NULL, 'project', 40, NULL),
490521 ('archived', 'project-a', NULL, 'project', 60, now()),
491522 ('chat', NULL, 'workspace-a', 'mothership', 999, NULL)`
492- await sql `INSERT INTO workspace_file_version VALUES ('version', 'project-file', 900)`
523+ await sql `INSERT INTO workspace_file_version (id, file_id, size_bytes) VALUES ('version', 'project-file', 900)`
493524 const store = createPostgresStorageReconciliationStore ( sql )
494525 await store . reconcileWorkspaces ( [ 'workspace-a' ] )
495526 await store . reconcileOrganization ( 'organization-a' )
@@ -512,7 +543,7 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
512543 const write = database . transaction ( async ( tx ) => {
513544 const prepared = await prepareProjectStorageMutationInTx ( tx , context ( ) )
514545 await tx . execute (
515- query `INSERT INTO workspace_files VALUES ('file', 'project-a', NULL, 'project', 40, NULL)`
546+ query `INSERT INTO workspace_files (id, project_id, workspace_id, context, size_bytes, deleted_at) VALUES ('file', 'project-a', NULL, 'project', 40, NULL)`
516547 )
517548 await prepared . applyDelta ( 40 )
518549 changed . resolve ( )
@@ -549,7 +580,7 @@ describe('Project storage admission, transfer, and reconciliation in PostgreSQL'
549580 const write = database . transaction ( async ( tx ) => {
550581 const prepared = await prepareProjectStorageMutationInTx ( tx , context ( ) )
551582 await tx . execute (
552- query `INSERT INTO workspace_files VALUES ('file', 'project-a', NULL, 'project', 40, NULL)`
583+ query `INSERT INTO workspace_files (id, project_id, workspace_id, context, size_bytes, deleted_at) VALUES ('file', 'project-a', NULL, 'project', 40, NULL)`
553584 )
554585 await prepared . applyDelta ( 40 )
555586 changed . resolve ( )
0 commit comments