Ctrl K
ComunidadGuías…

tests/cleanup_swap_memory.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { randomUUID } from 'node:crypto'
import { afterAll, describe, expect, it } from 'vitest'
import { cleanupPostgresClient, executeSQL } from './test-utils.ts'

describe('swap memory cleanup functions', () => {
  afterAll(async () => {
    await cleanupPostgresClient()
  })

  it('cleanup_queue_messages skips queues whose archive tables are missing', async () => {
    const queueName = `cleanup_missing_${randomUUID().slice(0, 8)}`
    await executeSQL(
      `INSERT INTO pgmq.meta (queue_name, is_partitioned, is_unlogged)
       VALUES ($1, false, false)`,
      [queueName],
    )

    try {
      await expect(executeSQL(`SELECT public.cleanup_queue_messages()`)).resolves.toBeTruthy()
    }
    finally {
      await executeSQL(`DELETE FROM pgmq.meta WHERE queue_name = $1`, [queueName])
    }
  })

  it('cleanup_queue_messages deletes archived rows older than 2 days in batches', async () => {
    const marker = `swap-cleanup-${randomUUID()}`
    const baseMsgId = BigInt(Date.now()) * 1000n

    await executeSQL(
      `INSERT INTO pgmq.a_on_version_update (msg_id, read_ct, enqueued_at, archived_at, vt, message)
       VALUES
         ($1, 0, now() - interval '10 days', now() - interval '10 days', now(), $3::jsonb),
         ($2, 0, now() - interval '1 hour', now() - interval '1 hour', now(), $4::jsonb)`,
      [
        (baseMsgId + 1n).toString(),
        (baseMsgId + 2n).toString(),
        JSON.stringify({ marker, age: 'old' }),
        JSON.stringify({ marker, age: 'fresh' }),
      ],
    )

    await executeSQL(`SELECT public.cleanup_queue_messages()`)

    const rows = await executeSQL(
      `SELECT message->>'age' AS age
       FROM pgmq.a_on_version_update
       WHERE message->>'marker' = $1
       ORDER BY age`,
      [marker],
    )

    expect(rows).toHaveLength(1)
    expect(rows[0]?.age).toBe('fresh')

    await executeSQL(
      `DELETE FROM pgmq.a_on_version_update WHERE message->>'marker' = $1`,
      [marker],
    )
  })

  it('cleanup_net_http_response truncates net._http_response', async () => {
    const id = BigInt(Date.now()) * 1000n + 7n
    await executeSQL(
      `INSERT INTO net._http_response (id, status_code, content, created)
       VALUES ($1, 200, 'swap-cleanup-test', now())`,
      [id.toString()],
    )

    await executeSQL(`SELECT public.cleanup_net_http_response()`)

    const rows = await executeSQL(
      `SELECT count(*)::int AS n FROM net._http_response`,
    )
    expect(rows[0]?.n).toBe(0)
  })

  it('null_migrated_app_version_manifests clears fully migrated dual-storage arrays', async () => {
    const appId = `com.swap.nullmanifest.${randomUUID().slice(0, 8)}`
    const orgRows = await executeSQL(
      `SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`,
    )
    const orgId = orgRows[0]?.id as string
    expect(orgId).toBeTruthy()

    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-null-manifest', '', $2::uuid)`,
      [appId, orgId],
    )

    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (app_id, name, owner_org, storage_provider, manifest, manifest_count)
       VALUES (
         $1,
         $2,
         $3::uuid,
         'r2',
         ARRAY[ROW('index.html', 'apps/test/index.html', 'abc123')::public.manifest_entry],
         1
       )
       RETURNING id`,
      [appId, `1.0.0-${randomUUID().slice(0, 8)}`, orgId],
    )
    const versionId = versionRows[0]?.id as number
    expect(versionId).toBeTruthy()

    await executeSQL(
      `INSERT INTO public.manifest (app_version_id, file_name, s3_path, file_hash)
       VALUES ($1, 'index.html', 'apps/test/index.html', 'abc123')`,
      [versionId],
    )

    await executeSQL(`SELECT public.null_migrated_app_version_manifests()`)

    const after = await executeSQL(
      `SELECT manifest IS NULL AS is_null, manifest_count
       FROM public.app_versions
       WHERE id = $1`,
      [versionId],
    )
    expect(after[0]?.is_null).toBe(true)
    expect(after[0]?.manifest_count).toBe(1)

    await executeSQL(`DELETE FROM public.manifest WHERE app_version_id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  it('audit_log_trigger strips fat app_versions fields', async () => {
    const appId = `com.swap.auditfat.${randomUUID().slice(0, 8)}`
    const orgRows = await executeSQL(
      `SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`,
    )
    const orgId = orgRows[0]?.id as string

    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-audit', '', $2::uuid)`,
      [appId, orgId],
    )

    const versionName = `1.0.0-${randomUUID().slice(0, 8)}`
    const manifestPath = `orgs/${orgId}/apps/${appId}/delta/hash_a.js`
    const canonicalR2Path = `orgs/${orgId}/apps/${appId}/${versionName}.zip`

    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (
         app_id,
         name,
         owner_org,
         storage_provider,
         comment,
         manifest,
         r2_path,
         native_packages
       )
       VALUES (
         $1,
         $2,
         $3::uuid,
         'r2',
         'before',
         ARRAY[ROW('a.js', $4, 'hash')::public.manifest_entry],
         $5,
         ARRAY['{"name":"cordova-plugin"}'::jsonb]
       )
       RETURNING id`,
      [
        appId,
        versionName,
        orgId,
        manifestPath,
        canonicalR2Path,
      ],
    )
    const versionId = versionRows[0]?.id as number

    await executeSQL(
      `INSERT INTO public.manifest (app_version_id, file_name, s3_path, file_hash)
       VALUES ($1, 'a.js', $2, 'hash')`,
      [versionId, manifestPath],
    )

    await executeSQL(
      `UPDATE public.app_versions
       SET
         comment = 'after',
         manifest = NULL,
         manifest_count = 1
       WHERE id = $1`,
      [versionId],
    )

    const logs = await executeSQL(
      `SELECT new_record, changed_fields
       FROM public.audit_logs
       WHERE table_name = 'app_versions'
         AND record_id = $1
         AND operation = 'UPDATE'
       ORDER BY id DESC
       LIMIT 1`,
      [String(versionId)],
    )

    expect(logs).toHaveLength(1)
    expect(logs[0]?.new_record?.manifest).toBeUndefined()
    expect(logs[0]?.new_record?.native_packages).toBeUndefined()
    expect(logs[0]?.new_record?.comment).toBe('after')
    expect(logs[0]?.changed_fields).toContain('comment')
    // Fat payloads stay stripped, but field names remain for upload-time history.
    expect(logs[0]?.changed_fields).toContain('manifest')

    await executeSQL(`DELETE FROM public.audit_logs WHERE record_id = $1 AND table_name = 'app_versions'`, [String(versionId)])
    await executeSQL(`DELETE FROM public.manifest WHERE app_version_id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  async function seedAuditAppVersion(appId: string, orgId: string) {
    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-audit-skip', '', $2::uuid)`,
      [appId, orgId],
    )
    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (app_id, name, owner_org, storage_provider, comment)
       VALUES ($1, $2, $3::uuid, 'r2-direct', 'seed')
       RETURNING id`,
      [appId, `1.0.0-${randomUUID().slice(0, 8)}`, orgId],
    )
    return versionRows[0]?.id as number
  }

  async function clearVersionAudits(versionId: number) {
    await executeSQL(
      `DELETE FROM public.audit_logs
       WHERE table_name = 'app_versions' AND record_id = $1`,
      [String(versionId)],
    )
  }

  it('audit_log_trigger skips dual-storage migrate finalize', async () => {
    const appId = `com.swap.auditskip.${randomUUID().slice(0, 8)}`
    const orgId = (await executeSQL(`SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`))[0]?.id as string
    const versionName = `1.0.0-${randomUUID().slice(0, 8)}`
    const manifestPath = `orgs/${orgId}/apps/${appId}/delta/hash_a.js`

    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-audit-skip', '', $2::uuid)`,
      [appId, orgId],
    )

    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (
         app_id,
         name,
         owner_org,
         storage_provider,
         comment,
         manifest,
         r2_path
       )
       VALUES (
         $1,
         $2,
         $3::uuid,
         'r2',
         'seed',
         ARRAY[ROW('a.js', $4, 'hash')::public.manifest_entry],
         $5
       )
       RETURNING id`,
      [
        appId,
        versionName,
        orgId,
        manifestPath,
        `orgs/${orgId}/apps/${appId}/${versionName}.zip`,
      ],
    )
    const versionId = versionRows[0]?.id as number
    await clearVersionAudits(versionId)

    await executeSQL(
      `INSERT INTO public.manifest (app_version_id, file_name, s3_path, file_hash)
       VALUES ($1, 'a.js', $2, 'hash')`,
      [versionId, manifestPath],
    )
    await executeSQL(
      `UPDATE public.app_versions
       SET manifest = NULL, manifest_count = 1, updated_at = now()
       WHERE id = $1`,
      [versionId],
    )

    const logs = await executeSQL(
      `SELECT id FROM public.audit_logs
       WHERE table_name = 'app_versions' AND record_id = $1 AND operation = 'UPDATE'`,
      [String(versionId)],
    )
    expect(logs).toHaveLength(0)

    await executeSQL(`DELETE FROM public.manifest WHERE app_version_id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  it('audit_log_trigger skips r2_path and storage_provider bookkeeping', async () => {
    const appId = `com.swap.auditpath.${randomUUID().slice(0, 8)}`
    const orgId = (await executeSQL(`SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`))[0]?.id as string
    const versionId = await seedAuditAppVersion(appId, orgId)
    await clearVersionAudits(versionId)

    const versionRows = await executeSQL(
      `SELECT name FROM public.app_versions WHERE id = $1`,
      [versionId],
    )
    const versionName = versionRows[0]?.name as string
    const canonicalR2Path = `orgs/${orgId}/apps/${appId}/${versionName}.zip`

    await executeSQL(
      `UPDATE public.app_versions
       SET r2_path = $2, updated_at = now()
       WHERE id = $1`,
      [versionId, canonicalR2Path],
    )
    await executeSQL(
      `UPDATE public.app_versions
       SET storage_provider = 'r2', updated_at = now()
       WHERE id = $1`,
      [versionId],
    )

    const logs = await executeSQL(
      `SELECT id, changed_fields FROM public.audit_logs
       WHERE table_name = 'app_versions' AND record_id = $1 AND operation = 'UPDATE'`,
      [String(versionId)],
    )
    expect(logs).toHaveLength(0)

    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  it('audit_log_trigger still records soft-delete', async () => {
    const appId = `com.swap.auditdel.${randomUUID().slice(0, 8)}`
    const orgId = (await executeSQL(`SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`))[0]?.id as string
    const versionId = await seedAuditAppVersion(appId, orgId)
    await clearVersionAudits(versionId)

    await executeSQL(
      `UPDATE public.app_versions
       SET deleted = true, deleted_at = now(), updated_at = now()
       WHERE id = $1`,
      [versionId],
    )

    const logs = await executeSQL(
      `SELECT changed_fields FROM public.audit_logs
       WHERE table_name = 'app_versions' AND record_id = $1 AND operation = 'UPDATE'
       ORDER BY id DESC LIMIT 1`,
      [String(versionId)],
    )
    expect(logs).toHaveLength(1)
    expect(logs[0]?.changed_fields).toContain('deleted')

    await executeSQL(`DELETE FROM public.audit_logs WHERE record_id = $1 AND table_name = 'app_versions'`, [String(versionId)])
    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  it('null_migrated_app_version_manifests skips partially migrated arrays', async () => {
    const appId = `com.swap.partialmanifest.${randomUUID().slice(0, 8)}`
    const orgRows = await executeSQL(
      `SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`,
    )
    const orgId = orgRows[0]?.id as string

    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-partial-manifest', '', $2::uuid)`,
      [appId, orgId],
    )

    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (app_id, name, owner_org, storage_provider, manifest, manifest_count)
       VALUES (
         $1,
         $2,
         $3::uuid,
         'r2',
         ARRAY[
           ROW('index.html', 'apps/test/index.html', 'abc123')::public.manifest_entry,
           ROW('main.js', 'apps/test/main.js', 'def456')::public.manifest_entry
         ],
         2
       )
       RETURNING id`,
      [appId, `1.0.0-${randomUUID().slice(0, 8)}`, orgId],
    )
    const versionId = versionRows[0]?.id as number

    // Only one of two files migrated.
    await executeSQL(
      `INSERT INTO public.manifest (app_version_id, file_name, s3_path, file_hash)
       VALUES ($1, 'index.html', 'apps/test/index.html', 'abc123')`,
      [versionId],
    )

    await executeSQL(`SELECT public.null_migrated_app_version_manifests()`)

    const after = await executeSQL(
      `SELECT manifest IS NULL AS is_null, cardinality(manifest) AS n
       FROM public.app_versions
       WHERE id = $1`,
      [versionId],
    )
    expect(after[0]?.is_null).toBe(false)
    expect(after[0]?.n).toBe(2)

    await executeSQL(`DELETE FROM public.manifest WHERE app_version_id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
    await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
  })

  it('null_migrated_app_version_manifests works when org requires encryption', async () => {
    const appId = `com.swap.encnull.${randomUUID().slice(0, 8)}`
    const orgRows = await executeSQL(
      `SELECT id FROM public.orgs ORDER BY created_at LIMIT 1`,
    )
    const orgId = orgRows[0]?.id as string

    await executeSQL(
      `INSERT INTO public.apps (app_id, name, icon_url, owner_org)
       VALUES ($1, 'swap-enc-null', '', $2::uuid)`,
      [appId, orgId],
    )

    // Create an unencrypted ready bundle while enforcement is off.
    const versionRows = await executeSQL(
      `INSERT INTO public.app_versions (app_id, name, owner_org, storage_provider, session_key, manifest, manifest_count)
       VALUES (
         $1,
         $2,
         $3::uuid,
         'r2',
         NULL,
         ARRAY[ROW('index.html', 'apps/test/index.html', 'abc123')::public.manifest_entry],
         1
       )
       RETURNING id`,
      [appId, `1.0.0-${randomUUID().slice(0, 8)}`, orgId],
    )
    const versionId = versionRows[0]?.id as number

    await executeSQL(
      `INSERT INTO public.manifest (app_version_id, file_name, s3_path, file_hash)
       VALUES ($1, 'index.html', 'apps/test/index.html', 'abc123')`,
      [versionId],
    )

    try {
      await executeSQL(
        `UPDATE public.orgs SET enforce_encrypted_bundles = true WHERE id = $1::uuid`,
        [orgId],
      )

      await executeSQL(`SELECT public.null_migrated_app_version_manifests()`)

      const after = await executeSQL(
        `SELECT manifest IS NULL AS is_null FROM public.app_versions WHERE id = $1`,
        [versionId],
      )
      expect(after[0]?.is_null).toBe(true)
    }
    finally {
      await executeSQL(
        `UPDATE public.orgs SET enforce_encrypted_bundles = false WHERE id = $1::uuid`,
        [orgId],
      )
      await executeSQL(`DELETE FROM public.manifest WHERE app_version_id = $1`, [versionId])
      await executeSQL(`DELETE FROM public.app_versions WHERE id = $1`, [versionId])
      await executeSQL(`DELETE FROM public.apps WHERE app_id = $1`, [appId])
    }
  })

  it('app_versions_manifest_present_idx exists as valid partial index on id', async () => {
    const rows = await executeSQL(
      `SELECT
         i.indisvalid,
         pg_get_indexdef(idx.oid) AS indexdef
       FROM pg_catalog.pg_class AS idx
       JOIN pg_catalog.pg_namespace AS ns ON ns.oid = idx.relnamespace
       JOIN pg_catalog.pg_index AS i ON i.indexrelid = idx.oid
       WHERE ns.nspname = 'public'
         AND idx.relname = 'app_versions_manifest_present_idx'
         AND i.indrelid = 'public.app_versions'::regclass`,
    )
    expect(rows).toHaveLength(1)
    expect(rows[0]?.indisvalid).toBe(true)
    expect(String(rows[0]?.indexdef)).toContain('(id)')
    expect(String(rows[0]?.indexdef).toLowerCase()).toContain('manifest is not null')
  })
})