import assert from "node:assert/strict"; import { test } from "node:test"; import { UniqueID } from "@repo/rdx-ddd"; import { normalizeSearchText } from "@repo/rdx-utils"; import { CreateGlobalApplicationRequestSchema, ListApplicationCandidatesRequestSchema, ListApplicationCandidatesResponseSchema, ResolveApplicationReferencesRequestSchema, ResolveApplicationReferencesResponseSchema, SoftwareReferenceSchema, } from "../../common"; import { globalApplicationTemplateEligible } from "./global-application-template-policy"; import { ResourceGlobalGatesSchema, globalResourcePurposeEnabled } from "./resource-global-gates"; import { paginateResourceMetadata } from "./resource-reference-pagination"; const id = () => UniqueID.generateNewID().toPrimitive(); test("elegibilidad global exige serie exacta y campos globales; las copias no elevan ámbito", () => { const template = { kind: "template", stockKey: "template:application", companyId: null, hasLocalFields: false, }; assert.equal(globalApplicationTemplateEligible(template), true); for (const change of [ { stockKey: null }, { stockKey: "template:os" }, { stockKey: "template:software_license" }, { stockKey: "template:APPLICATION" }, { kind: "field" }, { companyId: id() }, { hasLocalFields: true }, ]) { assert.equal(globalApplicationTemplateEligible({ ...template, ...change }), false); } }); test("schemas discriminan owner, propósito, OS local y proyecciones privadas", () => { const reference = { id: id(), templateId: id(), name: "Aplicación", active: true, kind: "application", scope: "global", companyId: null, }; assert.equal(SoftwareReferenceSchema.safeParse(reference).success, true); for (const change of [ { companyId: id() }, { kind: "os" }, { notes: "Privado" }, { history: [] }, { scope: "GLOBAL" }, ]) { assert.equal(SoftwareReferenceSchema.safeParse({ ...reference, ...change }).success, false); } const os = { ...reference, kind: "os", scope: "company", companyId: id() }; const payload = { items: [{ id: os.id, status: "resolved", reference: os }] }; assert.equal( ResolveApplicationReferencesResponseSchema.safeParse({ ...payload, purpose: "software-installation", }).success, true ); assert.equal( ResolveApplicationReferencesResponseSchema.safeParse({ ...payload, purpose: "application-configuration", }).success, false ); assert.equal( ListApplicationCandidatesResponseSchema.safeParse({ purpose: "application-configuration", items: [{ ...os, provider: null }], nextCursor: null, }).success, false ); }); test("requests acotan lotes, consulta, paginación y rechazan privilegios o integración", () => { const ids = Array.from({ length: 101 }, id); const query = { purpose: "software-installation" }; for (const input of [[], ids, [ids[0], ids[0]], ["invalid"]]) { assert.equal( ResolveApplicationReferencesRequestSchema.safeParse({ ...query, ids: input }).success, false ); } assert.equal( ResolveApplicationReferencesRequestSchema.safeParse({ ...query, ids: ids.slice(0, 100) }) .success, true ); for (const extra of [ { pageSize: 0 }, { pageSize: 101 }, { search: "a".repeat(101) }, { cursor: "a".repeat(2049) }, { purpose: "remote" }, { canManageGlobalResources: true }, ]) { assert.equal( ListApplicationCandidatesRequestSchema.safeParse({ ...query, ...extra }).success, false ); } const create = { creationId: id(), values: { name: "Producto", templateId: id(), active: true, notes: "", characteristics: {} }, }; assert.equal(CreateGlobalApplicationRequestSchema.safeParse(create).success, true); for (const extra of [ { scope: "global" }, { companyId: null }, { isInitialAdmin: true }, { actorId: id() }, ]) { assert.equal( CreateGlobalApplicationRequestSchema.safeParse({ ...create, ...extra }).success, false ); } assert.equal( CreateGlobalApplicationRequestSchema.safeParse({ ...create, values: { ...create.values, integration: {} }, }).success, false ); }); test("búsqueda literal conserva ñ, puntuación y espacios; pagina tras filtrar con desempate UUID", () => { assert.equal(normalizeSearchText(" ÁÉÏõÜ Ñ %_ "), "aeiou ñ %_"); const rows = Array.from({ length: 51 }, (_, index) => ({ id: id(), name: index < 25 ? "Aplicación Ágil %_" : "Aplicación Ágil", provider: "Fábrica", })); const base = { search: "%_", pageSize: 7, sort: "name", direction: "asc", context: "company-A/software", } as const; const seen = new Set(); let cursor: string | undefined; do { const page = paginateResourceMetadata(rows, { ...base, cursor }); assert.ok(page.isSuccess); for (const item of page.data.items) { assert.equal(seen.has(item.id), false); seen.add(item.id); } cursor = page.data.nextCursor ?? undefined; if (cursor) { assert.equal( paginateResourceMetadata(rows, { ...base, cursor, context: "company-B/software" }) .isSuccess, false ); assert.equal( paginateResourceMetadata(rows, { ...base, cursor, search: "otra" }).isSuccess, false ); } } while (cursor); assert.equal(seen.size, 25); assert.equal(paginateResourceMetadata(rows, { ...base, cursor: "corrupto" }).isSuccess, false); }); test("R2.5 admite gates configurables; los valores predeterminados siguen cerrados", () => { const gates = { catalog: false, administration: false, mixedSelection: false, software: false, profile: false, }; assert.equal(ResourceGlobalGatesSchema.safeParse(gates).success, true); assert.equal( ResourceGlobalGatesSchema.safeParse({ ...gates, catalog: true, administration: true }).success, true ); assert.equal(ResourceGlobalGatesSchema.safeParse({ ...gates, profile: true }).success, true); }); test("R2.5: software y perfil se habilitan por separado y requieren catálogo", () => { const open = { catalog: true, administration: true, mixedSelection: true, software: true, profile: false, } as const; assert.ok(ResourceGlobalGatesSchema.safeParse(open).success); assert.equal(globalResourcePurposeEnabled("software-installation", open), true); assert.equal( globalResourcePurposeEnabled("software-installation", { ...open, catalog: false }), false ); assert.equal(globalResourcePurposeEnabled("application-configuration", open), false); assert.ok(ResourceGlobalGatesSchema.safeParse({ ...open, mixedSelection: false }).success); assert.ok(ResourceGlobalGatesSchema.safeParse({ ...open, software: false }).success); assert.equal(ResourceGlobalGatesSchema.safeParse({ ...open, profile: true }).success, true); }); test("R2.5: perfil no depende de software ni abre asociaciones con catálogo cerrado", () => { const profileOnly = { catalog: true, administration: false, mixedSelection: false, software: false, profile: true, }; assert.equal(globalResourcePurposeEnabled("application-configuration", profileOnly), true); assert.equal(globalResourcePurposeEnabled("software-installation", profileOnly), false); assert.equal( globalResourcePurposeEnabled("application-configuration", { ...profileOnly, catalog: false }), false ); });