balena-supervisor/test/lib/mocked-dockerode.ts
Rich Bayliss 96c68166a1
application-manager: Convert to a singleton
Change-type: patch
Signed-off-by: Rich Bayliss <rich@balena.io>
Signed-off-by: Cameron Diver <cameron@balena.io>
2020-09-14 11:23:36 +01:00

111 lines
2.4 KiB
TypeScript

process.env.DOCKER_HOST = 'unix:///your/dockerode/mocks/are/not/working';
import * as dockerode from 'dockerode';
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>> = {};
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;
}
export interface TestData {
networks: Dictionary<any>;
images: Dictionary<any>;
}
function createMockedDockerode(data: TestData) {
const mockedDockerode = dockerode.prototype;
mockedDockerode.getNetwork = (id: string) => {
return {
inspect: async () => {
return data.networks[id];
},
} as dockerode.Network;
};
mockedDockerode.getImage = (name: string) => {
return {
inspect: async () => {
return data.images[name];
},
} 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;
}
}