Files
docker/test/test.nonci.node+deno.ts

326 lines
9.2 KiB
TypeScript
Raw Normal View History

import { expect, tap } from '@git.zone/tstest/tapbundle';
2024-06-10 00:15:01 +02:00
import { Qenv } from '@push.rocks/qenv';
const testQenv = new Qenv('./', './.nogit/');
import * as plugins from '../ts/plugins.js';
import * as paths from '../ts/paths.js';
2022-10-17 09:36:35 +02:00
import * as docker from '../ts/index.js';
2020-10-01 14:59:37 +00:00
let testDockerHost: docker.DockerHost;
tap.test('should create a new Dockersock instance', async () => {
2024-06-05 23:56:02 +02:00
testDockerHost = new docker.DockerHost({});
await testDockerHost.start();
2022-10-17 09:36:35 +02:00
return expect(testDockerHost).toBeInstanceOf(docker.DockerHost);
2020-10-01 14:59:37 +00:00
});
tap.test('should create a docker swarm', async () => {
await testDockerHost.activateSwarm();
});
// Containers
tap.test('should list containers', async () => {
const containers = await testDockerHost.listContainers();
2020-10-01 14:59:37 +00:00
console.log(containers);
});
// Networks
tap.test('should list networks', async () => {
const networks = await testDockerHost.listNetworks();
2020-10-01 14:59:37 +00:00
console.log(networks);
});
tap.test('should create a network', async () => {
const newNetwork = await testDockerHost.createNetwork({
2020-10-01 14:59:37 +00:00
Name: 'webgateway',
});
2022-10-17 09:36:35 +02:00
expect(newNetwork).toBeInstanceOf(docker.DockerNetwork);
expect(newNetwork.Name).toEqual('webgateway');
2020-10-01 14:59:37 +00:00
});
tap.test('should remove a network', async () => {
const webgateway = await testDockerHost.getNetworkByName('webgateway');
2020-10-01 14:59:37 +00:00
await webgateway.remove();
});
// Images
tap.test('should pull an image from imagetag', async () => {
const image = await testDockerHost.createImageFromRegistry({
imageUrl: 'hosttoday/ht-docker-node',
imageTag: 'alpine',
2020-10-01 14:59:37 +00:00
});
2022-10-17 09:36:35 +02:00
expect(image).toBeInstanceOf(docker.DockerImage);
2020-10-01 14:59:37 +00:00
console.log(image);
});
tap.test('should return a change Observable', async (tools) => {
const testObservable = await testDockerHost.getEventObservable();
const subscription = testObservable.subscribe((changeObject) => {
console.log(changeObject);
});
await tools.delayFor(2000);
subscription.unsubscribe();
});
// SECRETS
tap.test('should create a secret', async () => {
const mySecret = await testDockerHost.createSecret({
2020-10-01 14:59:37 +00:00
name: 'testSecret',
version: '1.0.3',
contentArg: `{ "hi": "wow"}`,
labels: {},
});
console.log(mySecret);
});
tap.test('should remove a secret by name', async () => {
const mySecret = await testDockerHost.getSecretByName('testSecret');
2020-10-01 14:59:37 +00:00
await mySecret.remove();
});
// SERVICES
tap.test('should activate swarm mode', async () => {
await testDockerHost.activateSwarm();
});
tap.test('should list all services', async (tools) => {
const services = await testDockerHost.listServices();
2020-10-01 14:59:37 +00:00
console.log(services);
});
tap.test('should create a service', async () => {
const testNetwork = await testDockerHost.createNetwork({
2020-10-01 14:59:37 +00:00
Name: 'testNetwork',
});
const testSecret = await testDockerHost.createSecret({
2020-10-01 14:59:37 +00:00
name: 'testSecret',
version: '0.0.1',
labels: {},
contentArg: '{"hi": "wow"}',
});
const testImage = await testDockerHost.createImageFromRegistry({
imageUrl: 'code.foss.global/host.today/ht-docker-node:latest',
});
const testService = await testDockerHost.createService({
2020-10-01 14:59:37 +00:00
image: testImage,
labels: {},
name: 'testService',
networks: [testNetwork],
networkAlias: 'testService',
secrets: [testSecret],
ports: ['3000:80'],
});
await testService.remove();
await testNetwork.remove();
await testSecret.remove();
});
tap.test('should export images', async (toolsArg) => {
const done = toolsArg.defer();
const testImage = await testDockerHost.createImageFromRegistry({
imageUrl: 'code.foss.global/host.today/ht-docker-node:latest',
});
const fsWriteStream = plugins.smartfile.fsStream.createWriteStream(
plugins.path.join(paths.nogitDir, 'testimage.tar'),
);
const exportStream = await testImage.exportToTarStream();
exportStream.pipe(fsWriteStream).on('finish', () => {
done.resolve();
});
await done.promise;
});
tap.test('should import images', async () => {
const fsReadStream = plugins.smartfile.fsStream.createReadStream(
plugins.path.join(paths.nogitDir, 'testimage.tar'),
);
const importedImage = await testDockerHost.createImageFromTarStream(
fsReadStream,
{
imageUrl: 'code.foss.global/host.today/ht-docker-node:latest',
},
);
expect(importedImage).toBeInstanceOf(docker.DockerImage);
});
tap.test('should expose a working DockerImageStore', async () => {
2024-06-10 00:15:01 +02:00
// lets first add am s3 target
const s3Descriptor = {
endpoint: await testQenv.getEnvVarOnDemand('S3_ENDPOINT'),
accessKey: await testQenv.getEnvVarOnDemand('S3_ACCESSKEY'),
accessSecret: await testQenv.getEnvVarOnDemand('S3_ACCESSSECRET'),
bucketName: await testQenv.getEnvVarOnDemand('S3_BUCKET'),
};
await testDockerHost.addS3Storage(s3Descriptor);
// Use the new public API instead of direct imageStore access
await testDockerHost.storeImage(
'hello2',
plugins.smartfile.fsStream.createReadStream(
plugins.path.join(paths.nogitDir, 'testimage.tar'),
),
);
});
// CONTAINER GETTERS
tap.test('should return undefined for non-existent container', async () => {
const container = await testDockerHost.getContainerById('invalid-container-id-12345');
expect(container).toEqual(undefined);
});
tap.test('should return container for valid container ID', async () => {
const containers = await testDockerHost.listContainers();
if (containers.length > 0) {
const validId = containers[0].Id;
const container = await testDockerHost.getContainerById(validId);
expect(container).toBeInstanceOf(docker.DockerContainer);
expect(container?.Id).toEqual(validId);
}
});
// CONTAINER STREAMING FEATURES
let testContainer: docker.DockerContainer;
tap.test('should get an existing container for streaming tests', async () => {
const containers = await testDockerHost.listContainers();
// Use the first running container we find
testContainer = containers.find((c) => c.State === 'running');
if (!testContainer) {
throw new Error('No running containers found for streaming tests');
}
expect(testContainer).toBeInstanceOf(docker.DockerContainer);
console.log('Using existing container for tests:', testContainer.Names[0], testContainer.Id);
});
tap.test('should stream container logs', async (tools) => {
const done = tools.defer();
const logStream = await testContainer.streamLogs({
stdout: true,
stderr: true,
timestamps: true,
});
let receivedData = false;
logStream.on('data', (chunk) => {
console.log('Received log chunk:', chunk.toString().slice(0, 100));
receivedData = true;
});
logStream.on('error', (error) => {
console.error('Stream error:', error);
done.resolve();
});
// Wait for 2 seconds to collect logs, then close
await tools.delayFor(2000);
logStream.destroy();
done.resolve();
await done.promise;
console.log('Log streaming test completed. Received data:', receivedData);
});
tap.test('should get container logs (one-shot)', async () => {
const logs = await testContainer.logs({
stdout: true,
stderr: true,
tail: 10,
});
expect(typeof logs).toEqual('string');
console.log('Container logs (last 10 lines):', logs.slice(0, 200));
});
tap.test('should execute command in container', async (tools) => {
const done = tools.defer();
const { stream, close } = await testContainer.exec('echo "Hello from exec"', {
tty: false,
attachStdout: true,
attachStderr: true,
});
let output = '';
stream.on('data', (chunk) => {
output += chunk.toString();
console.log('Exec output:', chunk.toString());
});
stream.on('end', async () => {
await close();
console.log('Exec completed. Full output:', output);
done.resolve();
});
stream.on('error', async (error) => {
console.error('Exec error:', error);
await close();
done.resolve();
});
await done.promise;
expect(output.length).toBeGreaterThan(0);
});
tap.test('should attach to container', async (tools) => {
const done = tools.defer();
const { stream, close } = await testContainer.attach({
stream: true,
stdout: true,
stderr: true,
stdin: false,
});
let receivedData = false;
stream.on('data', (chunk) => {
console.log('Attach received:', chunk.toString().slice(0, 100));
receivedData = true;
});
stream.on('error', async (error) => {
console.error('Attach error:', error);
await close();
done.resolve();
});
// Monitor for 2 seconds then detach
await tools.delayFor(2000);
await close();
done.resolve();
await done.promise;
console.log('Attach test completed. Received data:', receivedData);
});
tap.test('should get container stats', async () => {
const stats = await testContainer.stats({ stream: false });
expect(stats).toBeInstanceOf(Object);
console.log('Container stats keys:', Object.keys(stats));
});
tap.test('should inspect container', async () => {
const inspection = await testContainer.inspect();
expect(inspection).toBeInstanceOf(Object);
expect(inspection.Id).toEqual(testContainer.Id);
console.log('Container state:', inspection.State?.Status);
});
tap.test('should complete container tests', async () => {
// Using existing container, no cleanup needed
console.log('Container streaming tests completed');
});
tap.test('cleanup', async () => {
await testDockerHost.stop();
});
export default tap.start();