2025-08-18 03:07:12 +00:00
|
|
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
2024-10-16 14:35:38 +02:00
|
|
|
import * as helpers from './helpers/index.js';
|
2024-06-05 14:13:03 +02:00
|
|
|
|
2024-10-16 14:35:38 +02:00
|
|
|
import * as cloudly from '../ts/index.js';
|
2026-04-25 15:03:12 +00:00
|
|
|
import * as cloudlyApiClient from '@serve.zone/api';
|
2024-06-05 14:13:03 +02:00
|
|
|
|
2024-10-16 14:35:38 +02:00
|
|
|
let testCloudly: cloudly.Cloudly;
|
2024-06-05 14:13:03 +02:00
|
|
|
let testClient: cloudlyApiClient.CloudlyApiClient;
|
|
|
|
|
|
2026-05-08 13:56:20 +00:00
|
|
|
const logErrorDetails = (errorArg: unknown) => {
|
|
|
|
|
if (errorArg instanceof Error) {
|
|
|
|
|
console.error(` - Error message: ${errorArg.message}`);
|
|
|
|
|
console.error(` - Error stack:`, errorArg.stack);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
console.error(` - Error:`, errorArg);
|
|
|
|
|
};
|
|
|
|
|
|
2024-10-16 14:35:38 +02:00
|
|
|
tap.preTask('should start cloudly', async () => {
|
|
|
|
|
testCloudly = await helpers.createCloudly();
|
|
|
|
|
await testCloudly.start();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tap.preTask('should create a new machine user for testing', async () => {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('🔵 PreTask: Creating first machine user...');
|
2024-10-16 14:35:38 +02:00
|
|
|
const machineUser = new testCloudly.authManager.CUser();
|
|
|
|
|
machineUser.id = await testCloudly.authManager.CUser.getNewId();
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log(` - User ID: ${machineUser.id}`);
|
2024-10-16 14:35:38 +02:00
|
|
|
machineUser.data = {
|
|
|
|
|
type: 'machine',
|
|
|
|
|
username: 'test',
|
|
|
|
|
password: 'test',
|
|
|
|
|
tokens: [{
|
|
|
|
|
token: 'test',
|
|
|
|
|
expiresAt: Date.now() + 3600 * 1000 * 24 * 365,
|
|
|
|
|
assignedRoles: ['admin'],
|
|
|
|
|
}],
|
|
|
|
|
role: 'admin',
|
|
|
|
|
};
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log(` - Username: ${machineUser.data.username}`);
|
|
|
|
|
console.log(` - Role: ${machineUser.data.role}`);
|
|
|
|
|
console.log(` - Token: 'test'`);
|
2026-05-08 13:56:20 +00:00
|
|
|
console.log(` - Token roles: ${machineUser.data.tokens?.[0]?.assignedRoles?.join(', ') ?? ''}`);
|
2024-10-16 14:35:38 +02:00
|
|
|
await machineUser.save();
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('✅ PreTask: First machine user saved successfully');
|
2024-10-16 14:35:38 +02:00
|
|
|
});
|
|
|
|
|
|
2024-06-05 14:13:03 +02:00
|
|
|
tap.test('should create a new cloudlyApiClient', async () => {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('🔵 Test: Creating CloudlyApiClient...');
|
2024-06-05 14:13:03 +02:00
|
|
|
testClient = new cloudlyApiClient.CloudlyApiClient({
|
|
|
|
|
registerAs: 'api',
|
2024-11-06 17:19:43 +01:00
|
|
|
cloudlyUrl: `http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`,
|
2024-06-05 14:13:03 +02:00
|
|
|
});
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log(` - URL: http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`);
|
2024-10-16 14:35:38 +02:00
|
|
|
await testClient.start();
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('✅ CloudlyApiClient started successfully');
|
2024-06-05 14:13:03 +02:00
|
|
|
expect(testClient).toBeTruthy();
|
|
|
|
|
});
|
|
|
|
|
|
2025-08-18 21:11:28 +00:00
|
|
|
tap.test('DEBUG: Check existing users', async () => {
|
|
|
|
|
console.log('🔍 DEBUG: Checking existing users in database...');
|
|
|
|
|
const allUsers = await testCloudly.authManager.CUser.getInstances({});
|
|
|
|
|
console.log(` - Total users found: ${allUsers.length}`);
|
|
|
|
|
for (const user of allUsers) {
|
|
|
|
|
console.log(` - User: ${user.data.username} (ID: ${user.id})`);
|
|
|
|
|
console.log(` - Type: ${user.data.type}`);
|
|
|
|
|
console.log(` - Role: ${user.data.role}`);
|
2026-04-28 15:07:08 +00:00
|
|
|
console.log(` - Tokens: ${user.data.tokens?.length ?? 0}`);
|
|
|
|
|
for (const token of user.data.tokens ?? []) {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log(` - Token: '${token.token}' | Roles: ${token.assignedRoles?.join(', ')}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-10-16 14:35:38 +02:00
|
|
|
|
2024-08-25 14:29:26 +02:00
|
|
|
tap.test('should get an identity', async () => {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('🔵 Test: Getting identity by token...');
|
|
|
|
|
console.log(` - Using token: 'test'`);
|
|
|
|
|
console.log(` - API URL: http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const identity = await testClient.getIdentityByToken('test');
|
|
|
|
|
console.log('✅ Identity retrieved successfully:');
|
|
|
|
|
console.log(` - Identity exists: ${!!identity}`);
|
|
|
|
|
if (identity) {
|
|
|
|
|
console.log(` - Identity data:`, JSON.stringify(identity, null, 2));
|
|
|
|
|
}
|
|
|
|
|
expect(identity).toBeTruthy();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('❌ Failed to get identity:');
|
2026-05-08 13:56:20 +00:00
|
|
|
logErrorDetails(error);
|
2025-08-18 21:11:28 +00:00
|
|
|
throw error;
|
|
|
|
|
}
|
2024-08-25 14:29:26 +02:00
|
|
|
});
|
|
|
|
|
|
2026-04-28 15:23:51 +00:00
|
|
|
tap.test('should expose the OCI registry endpoint', async () => {
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/`,
|
|
|
|
|
);
|
|
|
|
|
expect(response.status).toEqual(200);
|
|
|
|
|
expect(response.headers.get('docker-distribution-api-version')).toEqual('registry/2.0');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tap.test('should require authentication for OCI registry tokens', async () => {
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/app:pull`,
|
|
|
|
|
);
|
|
|
|
|
expect(response.status).toEqual(401);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tap.test('should issue OCI registry tokens for the initial admin', async () => {
|
|
|
|
|
const credentials = Buffer.from(
|
|
|
|
|
`${helpers.testCloudlyAdminAccount.username}:${helpers.testCloudlyAdminAccount.password}`,
|
|
|
|
|
).toString('base64');
|
|
|
|
|
const response = await fetch(
|
|
|
|
|
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/app:pull,push`,
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: `Basic ${credentials}`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
const body = await response.json();
|
|
|
|
|
expect(response.status).toEqual(200);
|
|
|
|
|
expect(body.token).toBeTruthy();
|
|
|
|
|
expect(body.access_token).toEqual(body.token);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
tap.test('should deny OCI registry push tokens for non-admin users', async () => {
|
|
|
|
|
const readonlyUsername = 'registry-readonly';
|
|
|
|
|
const readonlyToken = 'registry-readonly-token';
|
|
|
|
|
const readonlyUser = new testCloudly.authManager.CUser();
|
|
|
|
|
readonlyUser.id = await testCloudly.authManager.CUser.getNewId();
|
|
|
|
|
readonlyUser.data = {
|
|
|
|
|
type: 'machine',
|
|
|
|
|
username: readonlyUsername,
|
|
|
|
|
password: readonlyToken,
|
|
|
|
|
tokens: [{
|
|
|
|
|
token: readonlyToken,
|
|
|
|
|
expiresAt: Date.now() + 3600 * 1000,
|
|
|
|
|
assignedRoles: [],
|
|
|
|
|
}],
|
|
|
|
|
role: 'user',
|
|
|
|
|
};
|
|
|
|
|
await readonlyUser.save();
|
|
|
|
|
|
|
|
|
|
const credentials = Buffer.from(`${readonlyUsername}:${readonlyToken}`).toString('base64');
|
|
|
|
|
const pullResponse = await fetch(
|
|
|
|
|
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/readonly:pull`,
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: `Basic ${credentials}`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
expect(pullResponse.status).toEqual(200);
|
|
|
|
|
|
|
|
|
|
const pushResponse = await fetch(
|
|
|
|
|
`http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}/v2/token?service=cloudly&scope=repository:test/readonly:pull,push`,
|
|
|
|
|
{
|
|
|
|
|
headers: {
|
|
|
|
|
Authorization: `Basic ${credentials}`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
expect(pushResponse.status).toEqual(403);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-28 15:50:59 +00:00
|
|
|
tap.test('should expose generated service registry targets', async () => {
|
|
|
|
|
const image = await testClient.image.createImage({
|
|
|
|
|
name: 'Registry Target Test Image',
|
|
|
|
|
description: 'Image used by the registry target test',
|
|
|
|
|
});
|
|
|
|
|
const service = await testClient.services.createService({
|
|
|
|
|
name: 'Registry Target Test Service',
|
|
|
|
|
description: 'Service used by the registry target test',
|
|
|
|
|
imageId: image.id,
|
|
|
|
|
imageVersion: 'latest',
|
|
|
|
|
environment: {},
|
|
|
|
|
secretBundleId: '',
|
|
|
|
|
serviceCategory: 'workload',
|
|
|
|
|
deploymentStrategy: 'custom',
|
|
|
|
|
scaleFactor: 1,
|
|
|
|
|
balancingStrategy: 'round-robin',
|
|
|
|
|
ports: {
|
|
|
|
|
web: 3000,
|
|
|
|
|
},
|
|
|
|
|
domains: [],
|
|
|
|
|
deploymentIds: [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const registryTarget = await testClient.services.getRegistryTarget(service.id, 'latest');
|
|
|
|
|
expect(registryTarget.protocol).toEqual('oci');
|
|
|
|
|
expect(registryTarget.registryHost).toEqual(`${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`);
|
|
|
|
|
expect(registryTarget.repository.startsWith('workloads/registry-target-test-service-')).toBeTrue();
|
2026-04-28 19:46:44 +00:00
|
|
|
expect(registryTarget.repository.split('/').every((partArg) => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(partArg))).toBeTrue();
|
2026-04-28 15:50:59 +00:00
|
|
|
expect(registryTarget.imageUrl).toEqual(`${registryTarget.registryHost}/${registryTarget.repository}:latest`);
|
|
|
|
|
|
|
|
|
|
const refreshedService = await testClient.services.getServiceById(service.id);
|
|
|
|
|
expect(refreshedService.data.registryTarget?.imageUrl).toEqual(registryTarget.imageUrl);
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-29 01:39:40 +00:00
|
|
|
tap.test('should trim truncated registry repository suffixes', async () => {
|
|
|
|
|
const registryTarget = testCloudly.registryManager.getServiceRegistryTarget({
|
|
|
|
|
id: 'service-5gv-123456',
|
|
|
|
|
data: {
|
|
|
|
|
name: 'Registry Target Test Service',
|
|
|
|
|
},
|
|
|
|
|
} as any);
|
|
|
|
|
|
|
|
|
|
expect(registryTarget.repository).toEqual('workloads/registry-target-test-service-service-5gv');
|
|
|
|
|
expect(registryTarget.repository.split('/').every((partArg) => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(partArg))).toBeTrue();
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-28 16:02:05 +00:00
|
|
|
tap.test('should push service config updates to connected coreflows', async (toolsArg) => {
|
|
|
|
|
const cluster = await testClient.cluster.createCluster('Registry Config Push Test Cluster');
|
|
|
|
|
const persistedCluster = await testCloudly.clusterManager.getConfigBy_ConfigID(cluster.id);
|
|
|
|
|
const clusterUser = await testCloudly.authManager.CUser.getInstance({
|
|
|
|
|
id: persistedCluster.data.userId,
|
|
|
|
|
});
|
|
|
|
|
const clusterToken = clusterUser.data.tokens?.[0]?.token;
|
|
|
|
|
expect(clusterToken).toBeTruthy();
|
|
|
|
|
const coreflowClient = new cloudlyApiClient.CloudlyApiClient({
|
|
|
|
|
registerAs: 'coreflow',
|
|
|
|
|
cloudlyUrl: `http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`,
|
|
|
|
|
});
|
|
|
|
|
const configUpdates: any[] = [];
|
|
|
|
|
let subscription: { unsubscribe: () => void } | undefined;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await coreflowClient.start();
|
|
|
|
|
await coreflowClient.getIdentityByToken(clusterToken!, {
|
|
|
|
|
statefullIdentity: true,
|
|
|
|
|
tagConnection: true,
|
|
|
|
|
});
|
|
|
|
|
subscription = coreflowClient.configUpdateSubject.subscribe((updateArg) => {
|
|
|
|
|
configUpdates.push(updateArg);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const image = await testClient.image.createImage({
|
|
|
|
|
name: 'Registry Config Push Test Image',
|
|
|
|
|
description: 'Image used by the config push test',
|
|
|
|
|
});
|
|
|
|
|
const service = await testClient.services.createService({
|
|
|
|
|
name: 'Registry Config Push Test Service',
|
|
|
|
|
description: 'Service used by the config push test',
|
|
|
|
|
imageId: image.id,
|
|
|
|
|
imageVersion: 'latest',
|
|
|
|
|
environment: {},
|
|
|
|
|
secretBundleId: '',
|
|
|
|
|
serviceCategory: 'workload',
|
|
|
|
|
deploymentStrategy: 'custom',
|
|
|
|
|
scaleFactor: 1,
|
|
|
|
|
balancingStrategy: 'round-robin',
|
|
|
|
|
ports: {
|
|
|
|
|
web: 3000,
|
|
|
|
|
},
|
|
|
|
|
domains: [],
|
|
|
|
|
deploymentIds: [],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await toolsArg.delayFor(100);
|
|
|
|
|
expect(configUpdates[0]?.configData.id).toEqual(cluster.id);
|
|
|
|
|
expect(configUpdates[0]?.services.find((serviceArg: any) => serviceArg.id === service.id)).toBeTruthy();
|
|
|
|
|
} finally {
|
|
|
|
|
subscription?.unsubscribe();
|
|
|
|
|
await coreflowClient.stop();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-28 16:57:54 +00:00
|
|
|
tap.test('should allow cluster coreflows to read deployment inputs', async () => {
|
|
|
|
|
const cluster = await testClient.cluster.createCluster('Registry Coreflow Read Test Cluster');
|
|
|
|
|
const persistedCluster = await testCloudly.clusterManager.getConfigBy_ConfigID(cluster.id);
|
|
|
|
|
const clusterUser = await testCloudly.authManager.CUser.getInstance({
|
|
|
|
|
id: persistedCluster.data.userId,
|
|
|
|
|
});
|
|
|
|
|
const clusterToken = clusterUser.data.tokens?.[0]?.token;
|
|
|
|
|
expect(clusterToken).toBeTruthy();
|
|
|
|
|
|
|
|
|
|
const image = await testClient.image.createImage({
|
|
|
|
|
name: 'Registry Coreflow Read Test Image',
|
|
|
|
|
description: 'Image used by the coreflow read test',
|
|
|
|
|
});
|
|
|
|
|
const secretBundle = await testClient.secretbundle.createSecretBundle({
|
|
|
|
|
name: 'Registry Coreflow Read Test Secret Bundle',
|
|
|
|
|
description: 'Secret bundle used by the coreflow read test',
|
|
|
|
|
type: 'service',
|
|
|
|
|
includedSecretGroupIds: [],
|
|
|
|
|
includedTags: [],
|
|
|
|
|
imageClaims: [],
|
|
|
|
|
authorizations: [
|
|
|
|
|
{
|
|
|
|
|
environment: 'production',
|
|
|
|
|
secretAccessKey: 'registry-coreflow-read-test',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const coreflowClient = new cloudlyApiClient.CloudlyApiClient({
|
|
|
|
|
registerAs: 'coreflow',
|
|
|
|
|
cloudlyUrl: `http://${helpers.testCloudlyConfig.publicUrl}:${helpers.testCloudlyConfig.publicPort}`,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
await coreflowClient.start();
|
|
|
|
|
await coreflowClient.getIdentityByToken(clusterToken!, {
|
|
|
|
|
statefullIdentity: true,
|
|
|
|
|
tagConnection: true,
|
|
|
|
|
});
|
|
|
|
|
const clusterImage = await coreflowClient.image.getImageById(image.id);
|
|
|
|
|
const clusterSecretBundle = await coreflowClient.secretbundle.getSecretBundleById(secretBundle.id);
|
|
|
|
|
expect(clusterImage.id).toEqual(image.id);
|
|
|
|
|
expect(clusterSecretBundle.id).toEqual(secretBundle.id);
|
|
|
|
|
} finally {
|
|
|
|
|
await coreflowClient.stop();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-28 12:18:12 +00:00
|
|
|
tap.test('should expose platform desired state', async () => {
|
|
|
|
|
const capabilitiesResponse = await testClient.platform.getPlatformCapabilities();
|
|
|
|
|
expect(capabilitiesResponse.capabilities.find((capability) => capability.id === 'database')).toBeTruthy();
|
|
|
|
|
|
|
|
|
|
const desiredState = await testClient.platform.getPlatformDesiredState();
|
|
|
|
|
expect(desiredState.capabilities).toBeTruthy();
|
|
|
|
|
expect(desiredState.providerConfigs).toBeTruthy();
|
|
|
|
|
expect(desiredState.bindings).toBeTruthy();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let platformProviderConfigId: string;
|
|
|
|
|
let platformBindingId: string;
|
|
|
|
|
tap.test('should upsert platform provider config and binding', async () => {
|
|
|
|
|
const providerConfigResponse = await testClient.platform.upsertPlatformProviderConfig({
|
|
|
|
|
id: '',
|
|
|
|
|
capability: 'database',
|
|
|
|
|
providerType: 'docker',
|
|
|
|
|
name: 'Local Docker Database',
|
|
|
|
|
enabled: true,
|
|
|
|
|
});
|
|
|
|
|
platformProviderConfigId = providerConfigResponse.providerConfig.id;
|
|
|
|
|
expect(platformProviderConfigId).toBeTruthy();
|
|
|
|
|
|
|
|
|
|
const bindingResponse = await testClient.platform.upsertPlatformBinding({
|
|
|
|
|
id: '',
|
|
|
|
|
serviceId: 'test-service',
|
|
|
|
|
capability: 'database',
|
|
|
|
|
desiredState: 'enabled',
|
|
|
|
|
status: 'requested',
|
|
|
|
|
providerConfigId: platformProviderConfigId,
|
|
|
|
|
});
|
|
|
|
|
platformBindingId = bindingResponse.binding.id;
|
|
|
|
|
expect(platformBindingId).toBeTruthy();
|
|
|
|
|
|
|
|
|
|
const statusResponse = await testClient.platform.updatePlatformBindingStatus({
|
|
|
|
|
bindingId: platformBindingId,
|
|
|
|
|
status: 'ready',
|
|
|
|
|
endpoints: [
|
|
|
|
|
{
|
|
|
|
|
name: 'primary',
|
|
|
|
|
capability: 'database',
|
|
|
|
|
protocol: 'mongodb',
|
|
|
|
|
internalUrl: 'mongodb://platform-database:27017/test-service',
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
expect(statusResponse.binding.status).toEqual('ready');
|
|
|
|
|
|
|
|
|
|
const bindingsResponse = await testClient.platform.getPlatformBindings({
|
|
|
|
|
serviceId: 'test-service',
|
|
|
|
|
});
|
|
|
|
|
expect(bindingsResponse.bindings.find((binding) => binding.id === platformBindingId)).toBeTruthy();
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-25 15:03:12 +00:00
|
|
|
let image: any;
|
2024-10-16 14:35:38 +02:00
|
|
|
tap.test('should create and upload an image', async () => {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('🔵 Test: Creating and uploading image...');
|
|
|
|
|
console.log(` - Image name: 'test'`);
|
|
|
|
|
console.log(` - Image description: 'test'`);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
image = await testClient.image.createImage({
|
|
|
|
|
name: 'test',
|
|
|
|
|
description: 'test'
|
|
|
|
|
});
|
|
|
|
|
console.log('✅ Image created successfully:');
|
|
|
|
|
console.log(` - Image ID: ${image?.id}`);
|
|
|
|
|
console.log(` - Image data:`, image);
|
2026-04-25 15:03:12 +00:00
|
|
|
expect(image).toBeTruthy();
|
2025-08-18 21:11:28 +00:00
|
|
|
} catch (error) {
|
|
|
|
|
console.error('❌ Failed to create image:');
|
2026-05-08 13:56:20 +00:00
|
|
|
logErrorDetails(error);
|
2025-08-18 21:11:28 +00:00
|
|
|
throw error;
|
|
|
|
|
}
|
2024-06-05 14:13:03 +02:00
|
|
|
})
|
|
|
|
|
|
2024-10-16 14:35:38 +02:00
|
|
|
tap.test('should upload an image version', async () => {
|
2025-08-18 21:11:28 +00:00
|
|
|
console.log('🔵 Test: Uploading image version...');
|
|
|
|
|
console.log(` - Version: 'v1.0.0'`);
|
|
|
|
|
console.log(` - Image exists: ${!!image}`);
|
|
|
|
|
console.log(` - Image ID: ${image?.id}`);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const imageStream = await helpers.getAlpineImageReadableStream();
|
|
|
|
|
console.log(' - Image stream obtained successfully');
|
|
|
|
|
|
|
|
|
|
await image.pushImageVersion('v1.0.0', imageStream);
|
|
|
|
|
console.log('✅ Image version uploaded successfully');
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('❌ Failed to upload image version:');
|
2026-05-08 13:56:20 +00:00
|
|
|
logErrorDetails(error);
|
2025-08-18 21:11:28 +00:00
|
|
|
throw error;
|
|
|
|
|
}
|
2024-10-16 14:35:38 +02:00
|
|
|
});
|
|
|
|
|
|
2024-08-25 14:29:26 +02:00
|
|
|
tap.test('should stop the apiclient', async (toolsArg) => {
|
2024-10-16 14:35:38 +02:00
|
|
|
await toolsArg.delayFor(10000);
|
2024-11-06 03:56:46 +01:00
|
|
|
await helpers.stopCloudly();
|
2024-06-05 14:13:03 +02:00
|
|
|
await testClient.stop();
|
2024-10-16 14:35:38 +02:00
|
|
|
await testCloudly.stop();
|
2024-06-05 14:13:03 +02:00
|
|
|
})
|
|
|
|
|
|
2026-04-25 15:03:12 +00:00
|
|
|
export default tap.start();
|