console/integration-tests/testkit/utils.ts
2026-03-11 10:03:44 +01:00

159 lines
3.9 KiB
TypeScript

import asyncRetry from 'async-retry';
import Docker from 'dockerode';
import { humanId } from 'human-id';
let docker: Docker | null = null;
function getDockerConnection() {
if (!docker) {
docker = new Docker();
}
return docker;
}
const LOCAL_SERVICES = {
server: 3001,
clickhouse: 8123,
emails: 6260,
composition_federation_2: 3069,
usage: 4001,
schema: 6500,
external_composition: 3012,
mock_server: 3042,
'otel-collector': 4318,
workflows: 3014,
} as const;
export type KnownServices = keyof typeof LOCAL_SERVICES;
export function getCDNPort() {
if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') {
return 9000;
}
return 8083;
}
export function getAppBaseUrl() {
if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') {
return 'localhost:3000';
}
return 'localhost:8080';
}
export async function getServiceHost(
serviceName: KnownServices,
servicePort: number,
localhost = true,
): Promise<string> {
if (process.env.RUN_AGAINST_LOCAL_SERVICES === '1') {
return `localhost:${LOCAL_SERVICES[serviceName]}`;
}
const actualHost = localhost ? 'localhost' : serviceName;
const docker = getDockerConnection();
const containers = await docker.listContainers({
filters: JSON.stringify({
label: [`com.docker.compose.service=${serviceName}`],
}),
});
if (containers.length === 0) {
throw new Error(`Failed to locate Docker container for service "${serviceName}"!`);
}
const container = containers[0];
const ports = container.Ports || [];
if (ports.length === 0) {
throw new Error(
`Container "${container.Id}" for service "${serviceName}" does not expose any ports!`,
);
}
const publicPort = ports.find(p => p.PublicPort === servicePort);
const privatePort = ports.find(p => p.PrivatePort === servicePort);
if (!publicPort && !privatePort) {
throw new Error(
`Container "${container.Id}" for service "${serviceName}" does not expose port "${servicePort}"!`,
);
}
if (publicPort) {
return `${actualHost}:${publicPort.PublicPort}`;
}
if (privatePort) {
console.warn(
`Container "${container.Id}" (service: "${serviceName}") expose port "${servicePort}" as "${privatePort.PublicPort}", please consider to update your setup!`,
);
return `${actualHost}:${privatePort.PublicPort}`;
}
return `${actualHost}:${servicePort}`;
}
export function generateUnique() {
return humanId({
separator: '',
adjectiveCount: 1,
addAdverb: true,
capitalize: false,
});
}
export function assertNonNull<T>(
value: T | null,
message = 'Expected non-null value.',
): asserts value is T {
if (value === null) {
throw new Error(message);
}
}
export function assertNonNullish<T>(
value: T | null | undefined,
message = 'Expected non-null value.',
): asserts value is T {
if (value === null) {
throw new Error(message);
}
}
export async function pollForEmailVerificationLink(input: string | { email: string; now: number }) {
const email = typeof input === 'string' ? input : input.email;
const now = new Date(typeof input === 'string' ? Date.now() - 10_000 : input.now).toISOString();
const url = new URL('http://localhost:3014/_history');
url.searchParams.set('after', now);
return await asyncRetry(
async () => {
const emails = await fetch(url.toString())
.then(res => res.json())
.then(emails =>
emails.filter((e: any) => e.to === email && e.subject === 'Verify your email'),
);
if (emails.length === 0) {
throw new Error('Could not find email');
}
// take the latest one
const result = emails[emails.length - 1];
const urlMatch = result.body.match(/href=\"(http:\/\/[^\s"]+)/);
if (!urlMatch) throw new Error('No URL found in email');
return new URL(urlMatch[1]);
},
{
retries: 10,
minTimeout: 1000,
maxTimeout: 10000,
},
);
}