162 lines
4.8 KiB
TypeScript
162 lines
4.8 KiB
TypeScript
|
|
import assert from "node:assert/strict";
|
||
|
|
import { test } from "node:test";
|
||
|
|
|
||
|
|
import { UniqueID } from "@repo/rdx-ddd";
|
||
|
|
import { Maybe } from "@repo/rdx-utils";
|
||
|
|
|
||
|
|
import { AccessItem } from "../domain/access/access-item.entity";
|
||
|
|
import { AccessValues } from "../domain/access/access-values.vo";
|
||
|
|
import { AccessWorkspace } from "../domain/access/access-workspace.aggregate";
|
||
|
|
import { LocalIdentityMapper } from "../infrastructure/persistence/local-identity.mapper";
|
||
|
|
|
||
|
|
import type { DirectoryContextSnapshot } from "./directory-context-plan";
|
||
|
|
import { planLocalIdentity } from "./local-identity-plan";
|
||
|
|
|
||
|
|
function fixture() {
|
||
|
|
const company = UniqueID.generateNewID();
|
||
|
|
const actor = UniqueID.generateNewID();
|
||
|
|
const asset = UniqueID.generateNewID();
|
||
|
|
const audit = { actorId: actor, recordedAt: "2026-10-20T12:00:00.000Z" };
|
||
|
|
const sys = AccessValues.create({ kind: "system", name: "Sistema renombrable", active: true });
|
||
|
|
|
||
|
|
assert.ok(sys.isSuccess);
|
||
|
|
const system = AccessItem.create(Maybe.some(company), sys.data, audit);
|
||
|
|
const env = AccessValues.create({
|
||
|
|
kind: "environment",
|
||
|
|
systemId: system.id.toPrimitive(),
|
||
|
|
name: "Equipo",
|
||
|
|
active: true,
|
||
|
|
});
|
||
|
|
|
||
|
|
assert.ok(env.isSuccess);
|
||
|
|
const environment = AccessItem.create(Maybe.some(company), env.data, audit);
|
||
|
|
const workspace = AccessWorkspace.rehydrate(
|
||
|
|
Maybe.some(company),
|
||
|
|
[system, environment],
|
||
|
|
UniqueID.generateNewID()
|
||
|
|
);
|
||
|
|
const snapshot: DirectoryContextSnapshot = {
|
||
|
|
workspace,
|
||
|
|
actors: new Map(),
|
||
|
|
context: { catalog: [], people: [], today: "2026-10-20" },
|
||
|
|
directorySystems: [],
|
||
|
|
directoryEnvironments: [],
|
||
|
|
};
|
||
|
|
const command = {
|
||
|
|
action: "associate",
|
||
|
|
assetId: asset.toPrimitive(),
|
||
|
|
environmentId: environment.id.toPrimitive(),
|
||
|
|
} as const;
|
||
|
|
|
||
|
|
return { company, actor, asset, audit, snapshot, command, environment, system };
|
||
|
|
}
|
||
|
|
|
||
|
|
test("identidad local: vínculo por UUID, alta y retirada idempotentes con identidad e historial protegidos", () => {
|
||
|
|
const f = fixture();
|
||
|
|
const linked = planLocalIdentity(
|
||
|
|
f.snapshot,
|
||
|
|
f.command,
|
||
|
|
f.company,
|
||
|
|
f.actor,
|
||
|
|
f.audit.recordedAt,
|
||
|
|
[]
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.ok(linked.isSuccess);
|
||
|
|
assert.equal(linked.data.link.id.toPrimitive()[14], "7");
|
||
|
|
const repeat = planLocalIdentity(f.snapshot, f.command, f.company, f.actor, f.audit.recordedAt, [
|
||
|
|
linked.data.link,
|
||
|
|
]);
|
||
|
|
|
||
|
|
assert.ok(repeat.isSuccess);
|
||
|
|
assert.equal(repeat.data.link, linked.data.link);
|
||
|
|
const moved = planLocalIdentity(
|
||
|
|
f.snapshot,
|
||
|
|
{ ...f.command, assetId: UniqueID.generateNewID().toPrimitive() },
|
||
|
|
f.company,
|
||
|
|
f.actor,
|
||
|
|
f.audit.recordedAt,
|
||
|
|
[linked.data.link]
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.equal(moved.isSuccess, false);
|
||
|
|
const retired = linked.data.link.retire(f.actor, f.audit.recordedAt);
|
||
|
|
|
||
|
|
assert.ok(retired.isSuccess);
|
||
|
|
const replay = retired.data.retire(f.actor, "invalid");
|
||
|
|
|
||
|
|
assert.ok(replay.isSuccess);
|
||
|
|
assert.equal(replay.data, retired.data);
|
||
|
|
assert.equal(
|
||
|
|
planLocalIdentity(f.snapshot, f.command, f.company, f.actor, f.audit.recordedAt, [retired.data])
|
||
|
|
.isSuccess,
|
||
|
|
false
|
||
|
|
);
|
||
|
|
const mapper = new LocalIdentityMapper();
|
||
|
|
|
||
|
|
assert.deepEqual(
|
||
|
|
mapper.toDomain(mapper.toPersistence(retired.data)).toPrimitive(),
|
||
|
|
retired.data.toPrimitive()
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("identidad local: clasificación explícita rechaza AD por sistema o entorno, sin comparar etiquetas", () => {
|
||
|
|
const f = fixture();
|
||
|
|
|
||
|
|
for (const snapshot of [
|
||
|
|
{ ...f.snapshot, directorySystems: [f.system.id.toPrimitive()] },
|
||
|
|
{ ...f.snapshot, directoryEnvironments: [f.environment.id.toPrimitive()] },
|
||
|
|
]) {
|
||
|
|
assert.equal(
|
||
|
|
planLocalIdentity(snapshot, f.command, f.company, f.actor, f.audit.recordedAt, []).isSuccess,
|
||
|
|
false
|
||
|
|
);
|
||
|
|
}
|
||
|
|
assert.equal(
|
||
|
|
planLocalIdentity(
|
||
|
|
f.snapshot,
|
||
|
|
{ ...f.command, environmentId: f.system.id.toPrimitive() },
|
||
|
|
f.company,
|
||
|
|
f.actor,
|
||
|
|
f.audit.recordedAt,
|
||
|
|
[]
|
||
|
|
).isSuccess,
|
||
|
|
false
|
||
|
|
);
|
||
|
|
assert.equal(
|
||
|
|
planLocalIdentity(
|
||
|
|
f.snapshot,
|
||
|
|
f.command,
|
||
|
|
UniqueID.generateNewID(),
|
||
|
|
f.actor,
|
||
|
|
f.audit.recordedAt,
|
||
|
|
[]
|
||
|
|
).isSuccess,
|
||
|
|
false
|
||
|
|
);
|
||
|
|
});
|
||
|
|
|
||
|
|
test("identidad local: crear entorno utiliza AccessWorkspace y conserva cuentas y sistema existentes", () => {
|
||
|
|
const f = fixture();
|
||
|
|
const created = planLocalIdentity(
|
||
|
|
f.snapshot,
|
||
|
|
{
|
||
|
|
action: "create",
|
||
|
|
systemId: f.system.id.toPrimitive(),
|
||
|
|
assetId: f.asset.toPrimitive(),
|
||
|
|
name: "Segundo entorno",
|
||
|
|
},
|
||
|
|
f.company,
|
||
|
|
f.actor,
|
||
|
|
f.audit.recordedAt,
|
||
|
|
[]
|
||
|
|
);
|
||
|
|
|
||
|
|
assert.ok(created.isSuccess);
|
||
|
|
assert.equal(created.data.workspace.items.length, 3);
|
||
|
|
assert.equal(created.data.workspace.items[0], f.system);
|
||
|
|
assert.equal(created.data.workspace.items[1], f.environment);
|
||
|
|
assert.equal(created.data.link.toPrimitive().systemId, f.system.id.toPrimitive());
|
||
|
|
assert.equal(created.data.link.toPrimitive().identityScope, "local-device");
|
||
|
|
});
|