2020-07-21 15:25:47 +00:00
|
|
|
process.env.DOCKER_HOST = 'unix:///your/dockerode/mocks/are/not/working';
|
|
|
|
|
2020-07-22 09:53:50 +00:00
|
|
|
import * as dockerode from 'dockerode';
|
2020-08-13 12:25:39 +00:00
|
|
|
import { Stream } from 'stream';
|
|
|
|
import _ = require('lodash');
|
|
|
|
import { TypedError } from 'typed-error';
|
|
|
|
|
|
|
|
export class NotFoundError extends TypedError {
|
|
|
|
public statusCode: number;
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.statusCode = 404;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const overrides: Dictionary<(...args: any[]) => Resolvable<any>> = {};
|
|
|
|
|
2020-10-30 21:38:19 +00:00
|
|
|
interface Action {
|
|
|
|
name: string;
|
|
|
|
parameters: Dictionary<any>;
|
|
|
|
}
|
|
|
|
|
|
|
|
export let actions: Action[] = [];
|
|
|
|
|
|
|
|
export function resetHistory() {
|
|
|
|
actions = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
function addAction(name: string, parameters: Dictionary<any>) {
|
|
|
|
actions.push({
|
|
|
|
name,
|
|
|
|
parameters,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-08-13 12:25:39 +00:00
|
|
|
type DockerodeFunction = keyof dockerode;
|
|
|
|
for (const fn of Object.getOwnPropertyNames(dockerode.prototype)) {
|
|
|
|
if (
|
|
|
|
fn !== 'constructor' &&
|
|
|
|
typeof (dockerode.prototype as any)[fn] === 'function'
|
|
|
|
) {
|
|
|
|
(dockerode.prototype as any)[fn] = async function (...args: any[]) {
|
|
|
|
console.log(`🐳 Calling ${fn}...`);
|
|
|
|
if (overrides[fn] != null) {
|
|
|
|
return overrides[fn](args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return promise */
|
|
|
|
return Promise.resolve([]);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// default overrides needed to startup...
|
|
|
|
registerOverride('listImages', async () => []);
|
|
|
|
registerOverride(
|
|
|
|
'getEvents',
|
|
|
|
async () =>
|
|
|
|
new Stream.Readable({
|
|
|
|
read: () => {
|
|
|
|
return _.noop();
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
export function registerOverride<
|
|
|
|
T extends DockerodeFunction,
|
|
|
|
P extends Parameters<dockerode[T]>,
|
|
|
|
R extends ReturnType<dockerode[T]>
|
|
|
|
>(name: T, fn: (...args: P) => R) {
|
|
|
|
console.log(`Overriding ${name}...`);
|
|
|
|
overrides[name] = fn;
|
|
|
|
}
|
2020-07-22 09:53:50 +00:00
|
|
|
|
|
|
|
export interface TestData {
|
|
|
|
networks: Dictionary<any>;
|
|
|
|
images: Dictionary<any>;
|
2020-11-19 01:37:34 +00:00
|
|
|
containers: Dictionary<any>;
|
2020-07-22 09:53:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function createMockedDockerode(data: TestData) {
|
|
|
|
const mockedDockerode = dockerode.prototype;
|
2020-11-19 01:37:34 +00:00
|
|
|
mockedDockerode.getContainer = (id: string) => {
|
|
|
|
addAction('getContainer', { id });
|
|
|
|
return {
|
|
|
|
start: async () => {
|
|
|
|
addAction('start', {});
|
|
|
|
data.containers = data.containers.map((c: any) => {
|
|
|
|
if (c.containerId === id) {
|
|
|
|
c.status = 'Installing';
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
stop: async () => {
|
|
|
|
addAction('stop', {});
|
|
|
|
data.containers = data.containers.map((c: any) => {
|
|
|
|
if (c.containerId === id) {
|
|
|
|
c.status = 'Stopping';
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
remove: async () => {
|
|
|
|
addAction('remove', {});
|
|
|
|
data.containers = data.containers.map((c: any) => {
|
|
|
|
if (c.containerId === id) {
|
|
|
|
c.status = 'removing';
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
} as dockerode.Container;
|
|
|
|
};
|
2020-07-22 09:53:50 +00:00
|
|
|
mockedDockerode.getNetwork = (id: string) => {
|
2020-10-30 21:38:19 +00:00
|
|
|
addAction('getNetwork', { id });
|
2020-07-22 09:53:50 +00:00
|
|
|
return {
|
|
|
|
inspect: async () => {
|
2020-10-30 21:38:19 +00:00
|
|
|
addAction('inspect', {});
|
2020-07-22 09:53:50 +00:00
|
|
|
return data.networks[id];
|
|
|
|
},
|
|
|
|
} as dockerode.Network;
|
|
|
|
};
|
|
|
|
|
|
|
|
mockedDockerode.getImage = (name: string) => {
|
2020-10-30 21:38:19 +00:00
|
|
|
addAction('getImage', { name });
|
2020-07-22 09:53:50 +00:00
|
|
|
return {
|
|
|
|
inspect: async () => {
|
2020-10-30 21:38:19 +00:00
|
|
|
addAction('inspect', {});
|
2020-07-22 09:53:50 +00:00
|
|
|
return data.images[name];
|
|
|
|
},
|
2020-10-30 21:38:19 +00:00
|
|
|
remove: async () => {
|
|
|
|
addAction('remove', {});
|
|
|
|
data.images = _.reject(data.images, {
|
|
|
|
name,
|
|
|
|
});
|
|
|
|
},
|
2020-07-22 09:53:50 +00:00
|
|
|
} as dockerode.Image;
|
|
|
|
};
|
|
|
|
|
|
|
|
return mockedDockerode;
|
|
|
|
}
|
|
|
|
|
|
|
|
export async function testWithData(
|
|
|
|
data: Partial<TestData>,
|
|
|
|
test: () => Promise<any>,
|
|
|
|
) {
|
|
|
|
const mockedData: TestData = {
|
|
|
|
...{
|
|
|
|
networks: {},
|
|
|
|
images: {},
|
|
|
|
containers: {},
|
|
|
|
},
|
|
|
|
...data,
|
|
|
|
};
|
|
|
|
|
|
|
|
// grab the original prototype...
|
|
|
|
const basePrototype = dockerode.prototype;
|
|
|
|
|
|
|
|
// @ts-expect-error setting a RO property
|
|
|
|
dockerode.prototype = createMockedDockerode(mockedData);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// run the test...
|
|
|
|
await test();
|
|
|
|
} finally {
|
|
|
|
// reset the original prototype...
|
|
|
|
// @ts-expect-error setting a RO property
|
|
|
|
dockerode.prototype = basePrototype;
|
|
|
|
}
|
|
|
|
}
|