Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,242 changes: 27 additions & 1,215 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"scripts": {
"generate": "openapi-generator-cli generate -i swagger.yaml -c openapi-config.yaml -o lib && npm run format.types",
"build": "npm run generate && tsdown",
"test": "vitest run --coverage",
"test": "node --import tsx --experimental-test-coverage --test 'test/**/*.test.ts'",
"typecheck": "tsc --noEmit",
"lint": "oxlint --type-aware",
"format": "prettier --write .",
Expand All @@ -57,13 +57,12 @@
"@types/node": "^24.5.2",
"@types/ssh2": "^1.15.5",
"@types/tar-stream": "^3.1.4",
"@vitest/coverage-v8": "^3.2.4",
"oxlint": "^1.16.0",
"oxlint-tsgolint": "^0.2.0",
"prettier": "^3.6.2",
"tsdown": "^0.15.6",
"typescript": "^5.9.2",
"vitest": "^3.2.4"
"tsx": "^4.20.6",
"typescript": "^5.9.2"
},
"engines": {
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
Expand Down
6 changes: 3 additions & 3 deletions test-integration/cjs-project/import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ const assert = require('node:assert/strict');
const { DockerClient } = require('@docker/node-sdk');

test('CJS module should import correctly', () => {
assert.equal(typeof DockerClient, 'function');
assert.equal(typeof DockerClient.fromDockerConfig, 'function');
assert.strictEqual(typeof DockerClient, 'function');
assert.strictEqual(typeof DockerClient.fromDockerConfig, 'function');
});

test('CJS module should import functional client', async () => {
const docker = await DockerClient.fromDockerConfig();
const apiVersion = await docker.systemPing();
assert.ok(apiVersion);
assert.notStrictEqual(apiVersion, null);
console.log(` Docker API version: ${apiVersion}`);
});
94 changes: 52 additions & 42 deletions test/build.test.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,64 @@
import { expect, test } from 'vitest';
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { DockerClient } from '../lib/docker-client.js';
import { pack as createTarPack } from 'tar-stream';
import { Readable } from 'node:stream';

test('imageBuild: build image from Dockerfile with tar-stream context', async () => {
const client = await DockerClient.fromDockerConfig();
const testImageName = 'test-build-image';
const testTag = 'latest';
test(
'imageBuild: build image from Dockerfile with tar-stream context',
{ timeout: 60000 },
async () => {
const client = await DockerClient.fromDockerConfig();
const testImageName = 'test-build-image';
const testTag = 'latest';

try {
const pack = createTarPack();
pack.entry(
{ name: 'Dockerfile' },
`FROM scratch
try {
const pack = createTarPack();
pack.entry(
{ name: 'Dockerfile' },
`FROM scratch
COPY test.txt /test.txt
`,
);
pack.entry({ name: 'test.txt' }, 'Hello from Docker build test!');
pack.finalize();
);
pack.entry({ name: 'test.txt' }, 'Hello from Docker build test!');
pack.finalize();

const builtImage = await client
.imageBuild(
Readable.toWeb(pack, { strategy: { highWaterMark: 16384 } }),
{
tag: `${testImageName}:${testTag}`,
rm: true,
forcerm: true,
},
)
.wait();
const builtImage = await client
.imageBuild(
Readable.toWeb(pack, {
strategy: { highWaterMark: 16384 },
}),
{
tag: `${testImageName}:${testTag}`,
rm: true,
forcerm: true,
},
)
.wait();

// Inspect the built builtImage to confirm it was created successfully
console.log(` Inspecting built image ${builtImage}`);
const imageInspect = await client.imageInspect(builtImage || '');
console.log(' Image found! Build was successful.');
// Inspect the built builtImage to confirm it was created successfully
console.log(` Inspecting built image ${builtImage}`);
const imageInspect = await client.imageInspect(builtImage || '');
console.log(' Image found! Build was successful.');

expect(imageInspect.RepoTags).toContain(`${testImageName}:${testTag}`);
console.log(` Image size: ${imageInspect.Size} bytes`);
} finally {
// Clean up: delete the test image
console.log(' Cleaning up test image...');
try {
await client.imageDelete(`${testImageName}:${testTag}`, {
force: true,
});
console.log(' Test image deleted successfully');
} catch (cleanupError) {
console.log(
` Warning: Failed to delete test image: ${(cleanupError as any)?.message}`,
assert.notStrictEqual(
imageInspect.RepoTags?.includes(`${testImageName}:${testTag}`),
false,
);
console.log(` Image size: ${imageInspect.Size} bytes`);
} finally {
// Clean up: delete the test image
console.log(' Cleaning up test image...');
try {
await client.imageDelete(`${testImageName}:${testTag}`, {
force: true,
});
console.log(' Test image deleted successfully');
} catch (cleanupError) {
console.log(
` Warning: Failed to delete test image: ${(cleanupError as any)?.message}`,
);
}
}
}
}, 60000); // 60 second timeout
},
);
94 changes: 52 additions & 42 deletions test/concurrency.test.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
import { assert, test } from 'vitest';
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { DockerClient } from '../lib/docker-client.js';

test('concurrent requests should execute in parallel', async () => {
const client = await DockerClient.fromDockerConfig();
const startTime = Date.now();

// Make 5 concurrent API calls
const promises = [
client.systemPing(),
client.systemInfo(),
client.systemVersion(),
client.containerList({ all: true }),
client.imageList(),
];

// Execute all requests concurrently
const results = await Promise.all(promises);
const totalTime = Date.now() - startTime;

// Verify all requests completed successfully
assert.isNotNull(results[0]); // systemPing result
assert.isNotNull(results[1]); // systemInfo result
assert.isNotNull(results[2]); // systemVersion result
assert.isNotNull(results[3]); // containerList result
assert.isNotNull(results[4]); // imageList result

console.log(` Completed 5 concurrent requests in ${totalTime}ms`);

// Concurrent requests should be faster than sequential ones
// This is a rough check - concurrent should typically be < 80% of sequential time
assert.isTrue(
totalTime < 10000,
'Concurrent requests should complete within reasonable time',
);
}, 15000);
test(
'concurrent requests should execute in parallel',
{ timeout: 15000 },
async () => {
const client = await DockerClient.fromDockerConfig();
const startTime = Date.now();

// Make 5 concurrent API calls
const promises = [
client.systemPing(),
client.systemInfo(),
client.systemVersion(),
client.containerList({ all: true }),
client.imageList(),
];

// Execute all requests concurrently
const results = await Promise.all(promises);
const totalTime = Date.now() - startTime;

// Verify all requests completed successfully
assert.notStrictEqual(results[0], null); // systemPing result
assert.notStrictEqual(results[1], null); // systemInfo result
assert.notStrictEqual(results[2], null); // systemVersion result
assert.notStrictEqual(results[3], null); // containerList result
assert.notStrictEqual(results[4], null); // imageList result

console.log(` Completed 5 concurrent requests in ${totalTime}ms`);

// Concurrent requests should be faster than sequential ones
// This is a rough check - concurrent should typically be < 80% of sequential time
assert.ok(
totalTime < 10000,
'Concurrent requests should complete within reasonable time',
);
},
);

test('high concurrency stress test', async () => {
test('high concurrency stress test', { timeout: 20000 }, async () => {
const client = await DockerClient.fromDockerConfig();
const startTime = Date.now();

Expand All @@ -48,20 +53,24 @@ test('high concurrency stress test', async () => {

// Verify all requests completed successfully
results.forEach((result, index) => {
assert.isNotNull(result, `Request ${index} should return a result`);
assert.notStrictEqual(
result,
null,
`Request ${index} should return a result`,
);
});

console.log(` Completed 20 concurrent ping requests in ${totalTime}ms`);
console.log(` Average time per request: ${(totalTime / 20).toFixed(1)}ms`);

// All requests should complete within reasonable time
assert.isTrue(
assert.ok(
totalTime < 15000,
'High concurrency requests should complete within reasonable time',
);
}, 20000);
});

test('mixed concurrent operations', async () => {
test('mixed concurrent operations', { timeout: 18000 }, async () => {
const client = await DockerClient.fromDockerConfig();

// Test different types of concurrent operations
Expand All @@ -86,17 +95,18 @@ test('mixed concurrent operations', async () => {

// Verify all requests completed successfully
results.forEach((result, index) => {
assert.isNotNull(
assert.notStrictEqual(
result,
null,
`Mixed operation ${index} should return a result`,
);
});

console.log(` Completed 10 mixed concurrent operations in ${totalTime}ms`);

// Should handle mixed operations efficiently
assert.isTrue(
assert.ok(
totalTime < 12000,
'Mixed concurrent operations should complete efficiently',
);
}, 18000);
});
Loading