"use strict"; const test = require("node:test"); const assert = require("node:assert/strict"); const { FakeApi } = require("./helpers"); const { resolveTarget } = require("../src/resolve"); const PROJECTS = [ { projectId: "p1", name: "shop", environments: [ { environmentId: "e1", name: "production", isDefault: true, applications: [{ applicationId: "a1", name: "api", appName: "shop-api-prod" }], compose: [], }, { environmentId: "e2", name: "staging", isDefault: false, applications: [{ applicationId: "a2", name: "api", appName: "shop-api-stage" }], compose: [{ composeId: "c1", name: "worker", appName: "shop-worker" }], }, ], }, { projectId: "p2", name: "blog", environments: [] }, ]; function apiWithProjects(projects = PROJECTS) { return new FakeApi({ "project.all": projects }); } test("an application id is confirmed through application.one", async () => { const api = new FakeApi({ "application.one": { name: "api", appName: "shop-api-prod", environmentId: "e1" }, }); const target = await resolveTarget(api, { applicationId: "a1" }); assert.deepEqual(target, { kind: "application", id: "a1", name: "api", appName: "shop-api-prod", environmentId: "e1" }); assert.deepEqual(api.find("application.one").input, { applicationId: "a1" }); }); test("a compose id is confirmed through compose.one", async () => { const api = new FakeApi({ "compose.one": { name: "worker", appName: "shop-worker", environmentId: "e2" } }); const target = await resolveTarget(api, { composeId: "c1" }); assert.equal(target.kind, "compose"); assert.equal(target.id, "c1"); }); test("a name resolves against the project's default environment", async () => { const api = apiWithProjects(); const target = await resolveTarget(api, { project: "shop", service: "api" }); assert.equal(target.id, "a1"); assert.equal(target.environmentId, "e1"); assert.equal(target.environmentName, "production"); assert.equal(target.appName, "shop-api-prod"); }); test("an explicit environment picks the other copy of the same name", async () => { const api = apiWithProjects(); const target = await resolveTarget(api, { project: "shop", service: "api", environment: "staging" }); assert.equal(target.id, "a2"); assert.equal(target.environmentName, "staging"); }); test("a Compose stack resolves by name", async () => { const api = apiWithProjects(); const target = await resolveTarget(api, { project: "shop", service: "worker", environment: "staging" }); assert.equal(target.kind, "compose"); assert.equal(target.id, "c1"); }); test("the Docker service name works as well as the display name", async () => { const api = apiWithProjects(); const target = await resolveTarget(api, { project: "shop", service: "shop-api-prod" }); assert.equal(target.id, "a1"); }); test("names match case-insensitively", async () => { const api = apiWithProjects(); const target = await resolveTarget(api, { project: "SHOP", service: "API" }); assert.equal(target.id, "a1"); }); test("an unknown project lists the ones that exist", async () => { const api = apiWithProjects(); await assert.rejects( () => resolveTarget(api, { project: "store", service: "api" }), /No project named "store"\. Available: blog, shop\./, ); }); test("an unknown environment lists the ones that exist", async () => { const api = apiWithProjects(); await assert.rejects( () => resolveTarget(api, { project: "shop", service: "api", environment: "qa" }), /no environment named "qa"\. Available: production, staging\./, ); }); test("an unknown service lists the ones in that environment", async () => { const api = apiWithProjects(); await assert.rejects( () => resolveTarget(api, { project: "shop", service: "cron", environment: "staging" }), /No application or Compose stack named "cron" in shop\/staging\. Available: api, worker\./, ); }); test("a name shared by an application and a Compose stack asks for an id", async () => { const api = apiWithProjects([ { projectId: "p1", name: "shop", environments: [ { environmentId: "e1", name: "production", isDefault: true, applications: [{ applicationId: "a1", name: "api", appName: "shop-api" }], compose: [{ composeId: "c1", name: "api", appName: "shop-api-compose" }], }, ], }, ]); await assert.rejects( () => resolveTarget(api, { project: "shop", service: "api" }), /ambiguous in shop\/production \(application and compose\)\. Use `application-id` or `compose-id`/, ); }); test("a project with no environments is reported as such", async () => { const api = apiWithProjects(); await assert.rejects(() => resolveTarget(api, { project: "blog", service: "api" }), /has no environments/); }); test("conflicting or missing target inputs are rejected before any request", async () => { const api = new FakeApi({}); await assert.rejects(() => resolveTarget(api, { applicationId: "a1", composeId: "c1" }), /not both/); await assert.rejects(() => resolveTarget(api, { applicationId: "a1", project: "shop", service: "api" }), /not both/); await assert.rejects(() => resolveTarget(api, {}), /No target/); await assert.rejects(() => resolveTarget(api, { project: "shop" }), /No target/); assert.equal(api.calls.length, 0); });