mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-01-19 19:28:59 +00:00
Run new prettier on code base
Signed-off-by: Theodor Gherzan <theodor@balena.io>
This commit is contained in:
parent
80ddcbebd4
commit
54e9c2edd8
@ -143,9 +143,15 @@ export class APIBinder {
|
||||
}
|
||||
|
||||
public async initClient() {
|
||||
const { unmanaged, apiEndpoint, currentApiKey } = await this.config.getMany(
|
||||
['unmanaged', 'apiEndpoint', 'currentApiKey'],
|
||||
);
|
||||
const {
|
||||
unmanaged,
|
||||
apiEndpoint,
|
||||
currentApiKey,
|
||||
} = await this.config.getMany([
|
||||
'unmanaged',
|
||||
'apiEndpoint',
|
||||
'currentApiKey',
|
||||
]);
|
||||
|
||||
if (unmanaged) {
|
||||
log.debug('Unmanaged mode is set, skipping API client initialization');
|
||||
@ -325,10 +331,12 @@ export class APIBinder {
|
||||
registered_at: Math.floor(Date.now() / 1000),
|
||||
});
|
||||
|
||||
return (await this.balenaApi
|
||||
.post({ resource: 'device', body: device })
|
||||
// TODO: Remove the `as number` when we fix the config typings
|
||||
.timeout(conf.apiTimeout)) as Device;
|
||||
return (
|
||||
(await this.balenaApi
|
||||
.post({ resource: 'device', body: device })
|
||||
// TODO: Remove the `as number` when we fix the config typings
|
||||
.timeout(conf.apiTimeout)) as Device
|
||||
);
|
||||
}
|
||||
|
||||
public async getTargetState(): Promise<DeviceApplicationState> {
|
||||
@ -535,9 +543,7 @@ export class APIBinder {
|
||||
// the watchdog to kill the supervisor - and killing the supervisor will
|
||||
// not help in this situation
|
||||
log.error(
|
||||
`Non-200 response from the API! Status code: ${
|
||||
e.statusCode
|
||||
} - message:`,
|
||||
`Non-200 response from the API! Status code: ${e.statusCode} - message:`,
|
||||
e,
|
||||
);
|
||||
} else {
|
||||
@ -614,9 +620,10 @@ export class APIBinder {
|
||||
|
||||
private async pollTargetState(isInitialCall: boolean = false): Promise<void> {
|
||||
// TODO: Remove the checkInt here with the config changes
|
||||
const { appUpdatePollInterval, instantUpdates } = await this.config.getMany(
|
||||
['appUpdatePollInterval', 'instantUpdates'],
|
||||
);
|
||||
const {
|
||||
appUpdatePollInterval,
|
||||
instantUpdates,
|
||||
} = await this.config.getMany(['appUpdatePollInterval', 'instantUpdates']);
|
||||
|
||||
// We add jitter to the poll interval so that it's between 0.5 and 1.5 times
|
||||
// the configured interval
|
||||
@ -885,9 +892,7 @@ export class APIBinder {
|
||||
'Attempting to provision a device without an initialized API client',
|
||||
);
|
||||
}
|
||||
this.balenaApi.passthrough.headers.Authorization = `Bearer ${
|
||||
opts.deviceApiKey
|
||||
}`;
|
||||
this.balenaApi.passthrough.headers.Authorization = `Bearer ${opts.deviceApiKey}`;
|
||||
|
||||
const configToUpdate = {
|
||||
registered_at: opts.registered_at,
|
||||
|
@ -111,7 +111,7 @@ export function generateStep<T extends CompositionStepAction>(
|
||||
}
|
||||
|
||||
type Executors<T extends CompositionStepAction> = {
|
||||
[key in T]: (step: CompositionStep<key>) => Promise<unknown>
|
||||
[key in T]: (step: CompositionStep<key>) => Promise<unknown>;
|
||||
};
|
||||
type LockingFn = (
|
||||
// TODO: Once the entire codebase is typescript, change
|
||||
|
@ -580,9 +580,11 @@ export class Images extends (EventEmitter as new () => ImageEventEmitter) {
|
||||
image = this.format(image);
|
||||
// TODO: Get rid of this janky cast once the database is
|
||||
// more strongly typed
|
||||
await this.db.upsertModel('image', image, (image as unknown) as Dictionary<
|
||||
unknown
|
||||
>);
|
||||
await this.db.upsertModel(
|
||||
'image',
|
||||
image,
|
||||
(image as unknown) as Dictionary<unknown>,
|
||||
);
|
||||
}
|
||||
|
||||
private format(image: MaybeImage): Image {
|
||||
|
@ -96,9 +96,9 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
public async get(service: Service) {
|
||||
// Get the container ids for special network handling
|
||||
const containerIds = await this.getContainerIdMap(service.appId!);
|
||||
const services = (await this.getAll(
|
||||
`service-id=${service.serviceId}`,
|
||||
)).filter(currentService =>
|
||||
const services = (
|
||||
await this.getAll(`service-id=${service.serviceId}`)
|
||||
).filter(currentService =>
|
||||
currentService.isEqualConfig(service, containerIds),
|
||||
);
|
||||
|
||||
@ -158,9 +158,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const svc = await this.get(service);
|
||||
if (svc.containerId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`No containerId provided for service ${
|
||||
service.serviceName
|
||||
} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
`No containerId provided for service ${service.serviceName} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -184,9 +182,9 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
public async killAllLegacy(): Promise<void> {
|
||||
// Containers haven't been normalized (this is an updated supervisor)
|
||||
// so we need to stop and remove them
|
||||
const supervisorImageId = (await this.docker
|
||||
.getImage(constants.supervisorImage)
|
||||
.inspect()).Id;
|
||||
const supervisorImageId = (
|
||||
await this.docker.getImage(constants.supervisorImage).inspect()
|
||||
).Id;
|
||||
|
||||
for (const container of await this.docker.listContainers({ all: true })) {
|
||||
if (container.ImageID !== supervisorImageId) {
|
||||
@ -212,9 +210,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
|
||||
if (existingService.containerId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`No containerId provided for service ${
|
||||
service.serviceName
|
||||
} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
`No containerId provided for service ${service.serviceName} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -248,9 +244,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const existing = await this.get(service);
|
||||
if (existing.containerId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`No containerId provided for service ${
|
||||
service.serviceName
|
||||
} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
`No containerId provided for service ${service.serviceName} in ServiceManager.updateMetadata. Service: ${service}`,
|
||||
);
|
||||
}
|
||||
return this.docker.getContainer(existing.containerId);
|
||||
@ -371,9 +365,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const imageId = service.imageId;
|
||||
if (serviceId == null || imageId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`serviceId and imageId not defined for service: ${
|
||||
service.serviceName
|
||||
} in ServiceManager.start`,
|
||||
`serviceId and imageId not defined for service: ${service.serviceName} in ServiceManager.start`,
|
||||
);
|
||||
}
|
||||
|
||||
@ -439,9 +431,7 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const imageId = service.imageId;
|
||||
if (serviceId == null || imageId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`serviceId and imageId not defined for service: ${
|
||||
service.serviceName
|
||||
} in ServiceManager.listenToEvents`,
|
||||
`serviceId and imageId not defined for service: ${service.serviceName} in ServiceManager.listenToEvents`,
|
||||
);
|
||||
}
|
||||
this.logger.attach(this.docker, data.id, {
|
||||
@ -488,17 +478,13 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const imageId = service.imageId;
|
||||
if (serviceId == null || imageId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`serviceId and imageId not defined for service: ${
|
||||
service.serviceName
|
||||
} in ServiceManager.start`,
|
||||
`serviceId and imageId not defined for service: ${service.serviceName} in ServiceManager.start`,
|
||||
);
|
||||
}
|
||||
|
||||
if (service.containerId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`containerId not defined for service: ${
|
||||
service.serviceName
|
||||
} in ServiceManager.attachToRunning`,
|
||||
`containerId not defined for service: ${service.serviceName} in ServiceManager.attachToRunning`,
|
||||
);
|
||||
}
|
||||
this.logger.attach(this.docker, service.containerId, {
|
||||
@ -638,17 +624,13 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
const svc = await this.get(service);
|
||||
if (svc.containerId == null) {
|
||||
throw new InternalInconsistencyError(
|
||||
`No containerId provided for service ${
|
||||
service.serviceName
|
||||
} in ServiceManager.prepareForHandover. Service: ${service}`,
|
||||
`No containerId provided for service ${service.serviceName} in ServiceManager.prepareForHandover. Service: ${service}`,
|
||||
);
|
||||
}
|
||||
const container = this.docker.getContainer(svc.containerId);
|
||||
await container.update({ RestartPolicy: {} });
|
||||
return await container.rename({
|
||||
name: `old_${service.serviceName}_${service.imageId}_${service.imageId}_${
|
||||
service.releaseId
|
||||
}`,
|
||||
name: `old_${service.serviceName}_${service.imageId}_${service.imageId}_${service.releaseId}`,
|
||||
});
|
||||
}
|
||||
|
||||
@ -670,17 +652,13 @@ export class ServiceManager extends (EventEmitter as new () => ServiceManagerEve
|
||||
return wait();
|
||||
} else {
|
||||
log.info(
|
||||
`Handover timeout has passed, assuming handover was completed for service ${
|
||||
service.serviceName
|
||||
}`,
|
||||
`Handover timeout has passed, assuming handover was completed for service ${service.serviceName}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
log.info(
|
||||
`Waiting for handover to be completed for service: ${
|
||||
service.serviceName
|
||||
}`,
|
||||
`Waiting for handover to be completed for service: ${service.serviceName}`,
|
||||
);
|
||||
|
||||
return wait().then(() => {
|
||||
|
@ -337,9 +337,7 @@ export class Service {
|
||||
config.cpus = Math.round(Number(config.cpus) * 10 ** 9);
|
||||
if (_.isNaN(config.cpus)) {
|
||||
log.warn(
|
||||
`config.cpus value cannot be parsed. Ignoring.\n Value:${
|
||||
config.cpus
|
||||
}`,
|
||||
`config.cpus value cannot be parsed. Ignoring.\n Value:${config.cpus}`,
|
||||
);
|
||||
config.cpus = undefined;
|
||||
}
|
||||
@ -713,9 +711,7 @@ export class Service {
|
||||
// Add some console output for why a service is not matching
|
||||
// so that if we end up in a restart loop, we know exactly why
|
||||
log.debug(
|
||||
`Replacing container for service ${
|
||||
this.serviceName
|
||||
} because of config changes:`,
|
||||
`Replacing container for service ${this.serviceName} because of config changes:`,
|
||||
);
|
||||
if (!nonArrayEquals) {
|
||||
// Try not to leak any sensitive information
|
||||
|
@ -343,9 +343,9 @@ export function addFeaturesFromLabels(
|
||||
`${constants.dockerSocket}:${constants.dockerSocket}`,
|
||||
);
|
||||
if (service.config.environment['DOCKER_HOST'] == null) {
|
||||
service.config.environment['DOCKER_HOST'] = `unix://${
|
||||
constants.dockerSocket
|
||||
}`;
|
||||
service.config.environment[
|
||||
'DOCKER_HOST'
|
||||
] = `unix://${constants.dockerSocket}`;
|
||||
}
|
||||
// We keep balena.sock for backwards compatibility
|
||||
if (constants.dockerSocket !== '/var/run/balena.sock') {
|
||||
|
@ -30,9 +30,7 @@ function remountAndWriteAtomic(file: string, data: string): Promise<void> {
|
||||
// Here's the dangerous part:
|
||||
return Promise.resolve(
|
||||
childProcess.execAsync(
|
||||
`mount -t vfat -o remount,rw ${
|
||||
constants.bootBlockDevice
|
||||
} ${bootMountPoint}`,
|
||||
`mount -t vfat -o remount,rw ${constants.bootBlockDevice} ${bootMountPoint}`,
|
||||
),
|
||||
)
|
||||
.then(() => {
|
||||
@ -76,9 +74,7 @@ export abstract class DeviceConfigBackend {
|
||||
}
|
||||
|
||||
export class RPiConfigBackend extends DeviceConfigBackend {
|
||||
private static bootConfigVarPrefix = `${
|
||||
constants.hostConfigVarPrefix
|
||||
}CONFIG_`;
|
||||
private static bootConfigVarPrefix = `${constants.hostConfigVarPrefix}CONFIG_`;
|
||||
private static bootConfigPath = `${bootMountPoint}/config.txt`;
|
||||
|
||||
public static bootConfigVarRegex = new RegExp(
|
||||
@ -206,9 +202,7 @@ export class RPiConfigBackend extends DeviceConfigBackend {
|
||||
}
|
||||
|
||||
export class ExtlinuxConfigBackend extends DeviceConfigBackend {
|
||||
private static bootConfigVarPrefix = `${
|
||||
constants.hostConfigVarPrefix
|
||||
}EXTLINUX_`;
|
||||
private static bootConfigVarPrefix = `${constants.hostConfigVarPrefix}EXTLINUX_`;
|
||||
private static bootConfigPath = `${bootMountPoint}/extlinux/extlinux.conf`;
|
||||
|
||||
public static bootConfigVarRegex = new RegExp(
|
||||
|
@ -27,10 +27,10 @@ interface ConfigOpts {
|
||||
}
|
||||
|
||||
export type ConfigMap<T extends SchemaTypeKey> = {
|
||||
[key in T]: SchemaReturn<key>
|
||||
[key in T]: SchemaReturn<key>;
|
||||
};
|
||||
export type ConfigChangeMap<T extends SchemaTypeKey> = {
|
||||
[key in T]?: SchemaReturn<key>
|
||||
[key in T]?: SchemaReturn<key>;
|
||||
};
|
||||
|
||||
// Export this type renamed, for storing config keys
|
||||
@ -173,9 +173,11 @@ export class Config extends (EventEmitter as new () => ConfigEventEmitter) {
|
||||
})
|
||||
.then(() => {
|
||||
if (!_.isEmpty(configJsonVals)) {
|
||||
return this.configJsonBackend.set(configJsonVals as {
|
||||
[key in Schema.SchemaKey]: unknown
|
||||
});
|
||||
return this.configJsonBackend.set(
|
||||
configJsonVals as {
|
||||
[key in Schema.SchemaKey]: unknown;
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -208,9 +208,10 @@ export class DeviceConfig {
|
||||
'Non-dictionary passed to DeviceConfig.setBootConfig',
|
||||
);
|
||||
}
|
||||
await this.setBootConfig(configBackend, step.target as Dictionary<
|
||||
string
|
||||
>);
|
||||
await this.setBootConfig(
|
||||
configBackend,
|
||||
step.target as Dictionary<string>,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -276,9 +277,9 @@ export class DeviceConfig {
|
||||
}
|
||||
|
||||
public async getCurrent() {
|
||||
const conf = await this.config.getMany(['deviceType'].concat(
|
||||
_.keys(DeviceConfig.configKeys),
|
||||
) as SchemaTypeKey[]);
|
||||
const conf = await this.config.getMany(
|
||||
['deviceType'].concat(_.keys(DeviceConfig.configKeys)) as SchemaTypeKey[],
|
||||
);
|
||||
|
||||
const configBackend = await this.getConfigBackend();
|
||||
|
||||
|
@ -84,9 +84,7 @@ export class DockerUtils extends DockerToolbelt {
|
||||
|
||||
if (!_.includes([2, 3], deltaOpts.deltaVersion)) {
|
||||
logFn(
|
||||
`Unsupported delta version: ${
|
||||
deltaOpts.deltaVersion
|
||||
}. Failling back to regular pull`,
|
||||
`Unsupported delta version: ${deltaOpts.deltaVersion}. Failling back to regular pull`,
|
||||
);
|
||||
return await this.fetchImageWithProgress(imgDest, deltaOpts, onProgress);
|
||||
}
|
||||
@ -117,9 +115,7 @@ export class DockerUtils extends DockerToolbelt {
|
||||
},
|
||||
};
|
||||
|
||||
const url = `${deltaOpts.deltaEndpoint}/api/v${
|
||||
deltaOpts.deltaVersion
|
||||
}/delta?src=${deltaOpts.deltaSource}&dest=${imgDest}`;
|
||||
const url = `${deltaOpts.deltaEndpoint}/api/v${deltaOpts.deltaVersion}/delta?src=${deltaOpts.deltaSource}&dest=${imgDest}`;
|
||||
|
||||
const [res, data] = await (await request.getRequestInstance()).getAsync(
|
||||
url,
|
||||
@ -140,9 +136,7 @@ export class DockerUtils extends DockerToolbelt {
|
||||
)
|
||||
) {
|
||||
throw new Error(
|
||||
`Got ${
|
||||
res.statusCode
|
||||
} when requesting an image from delta server.`,
|
||||
`Got ${res.statusCode} when requesting an image from delta server.`,
|
||||
);
|
||||
}
|
||||
const deltaUrl = res.headers['location'];
|
||||
@ -164,9 +158,7 @@ export class DockerUtils extends DockerToolbelt {
|
||||
case 3:
|
||||
if (res.statusCode !== 200) {
|
||||
throw new Error(
|
||||
`Got ${
|
||||
res.statusCode
|
||||
} when requesting v3 delta from delta server.`,
|
||||
`Got ${res.statusCode} when requesting v3 delta from delta server.`,
|
||||
);
|
||||
}
|
||||
let name;
|
||||
@ -340,16 +332,11 @@ export class DockerUtils extends DockerToolbelt {
|
||||
},
|
||||
json: true,
|
||||
};
|
||||
const tokenUrl = `${tokenEndpoint}?service=${
|
||||
dstInfo.registry
|
||||
}&scope=repository:${dstInfo.imageName}:pull&scope=repository:${
|
||||
srcInfo.imageName
|
||||
}:pull`;
|
||||
const tokenUrl = `${tokenEndpoint}?service=${dstInfo.registry}&scope=repository:${dstInfo.imageName}:pull&scope=repository:${srcInfo.imageName}:pull`;
|
||||
|
||||
const tokenResponseBody = (await (await request.getRequestInstance()).getAsync(
|
||||
tokenUrl,
|
||||
tokenOpts,
|
||||
))[1];
|
||||
const tokenResponseBody = (
|
||||
await (await request.getRequestInstance()).getAsync(tokenUrl, tokenOpts)
|
||||
)[1];
|
||||
const token = tokenResponseBody != null ? tokenResponseBody.token : null;
|
||||
|
||||
if (token == null) {
|
||||
|
@ -152,9 +152,7 @@ export async function normaliseLegacyDatabase(
|
||||
|
||||
if (releases.length === 0) {
|
||||
log.warn(
|
||||
`No compatible releases found in API, removing ${
|
||||
app.appId
|
||||
} from target state`,
|
||||
`No compatible releases found in API, removing ${app.appId} from target state`,
|
||||
);
|
||||
await db
|
||||
.models('app')
|
||||
@ -171,9 +169,7 @@ export async function normaliseLegacyDatabase(
|
||||
: `${image.is_stored_at__image_location}@${image.content_hash}`;
|
||||
|
||||
log.debug(
|
||||
`Found a release with releaseId ${release.id}, imageId ${
|
||||
image.id
|
||||
}, serviceId ${serviceId}\nImage location is ${imageUrl}`,
|
||||
`Found a release with releaseId ${release.id}, imageId ${image.id}, serviceId ${serviceId}\nImage location is ${imageUrl}`,
|
||||
);
|
||||
|
||||
const imageFromDocker = await application.docker
|
||||
|
@ -60,9 +60,7 @@ export class BalenaLogBackend extends LogBackend {
|
||||
this.flush();
|
||||
if (this.dropCount > 0) {
|
||||
this.write({
|
||||
message: `Warning: Suppressed ${
|
||||
this.dropCount
|
||||
} message(s) due to high load`,
|
||||
message: `Warning: Suppressed ${this.dropCount} message(s) due to high load`,
|
||||
timestamp: Date.now(),
|
||||
isSystem: true,
|
||||
isStdErr: true,
|
||||
|
@ -38,34 +38,35 @@ export class ContainerLogs extends (EventEmitter as new () => LogsEventEmitter)
|
||||
const stdoutStream = await container.logs(stdoutLogOpts);
|
||||
const stderrStream = await container.logs(stderrLogOpts);
|
||||
|
||||
[[stdoutStream, true], [stderrStream, false]].forEach(
|
||||
([stream, isStdout]: [Stream.Readable, boolean]) => {
|
||||
stream
|
||||
.on('error', err => {
|
||||
this.emit(
|
||||
'error',
|
||||
new Error(`Error on container logs: ${err} ${err.stack}`),
|
||||
);
|
||||
})
|
||||
.pipe(es.split())
|
||||
.on('data', (logBuf: Buffer | string) => {
|
||||
if (_.isString(logBuf)) {
|
||||
logBuf = Buffer.from(logBuf);
|
||||
}
|
||||
const logMsg = ContainerLogs.extractMessage(logBuf);
|
||||
if (logMsg != null) {
|
||||
this.emit('log', { isStdout, ...logMsg });
|
||||
}
|
||||
})
|
||||
.on('error', err => {
|
||||
this.emit(
|
||||
'error',
|
||||
new Error(`Error on container logs: ${err} ${err.stack}`),
|
||||
);
|
||||
})
|
||||
.on('end', () => this.emit('closed'));
|
||||
},
|
||||
);
|
||||
[
|
||||
[stdoutStream, true],
|
||||
[stderrStream, false],
|
||||
].forEach(([stream, isStdout]: [Stream.Readable, boolean]) => {
|
||||
stream
|
||||
.on('error', err => {
|
||||
this.emit(
|
||||
'error',
|
||||
new Error(`Error on container logs: ${err} ${err.stack}`),
|
||||
);
|
||||
})
|
||||
.pipe(es.split())
|
||||
.on('data', (logBuf: Buffer | string) => {
|
||||
if (_.isString(logBuf)) {
|
||||
logBuf = Buffer.from(logBuf);
|
||||
}
|
||||
const logMsg = ContainerLogs.extractMessage(logBuf);
|
||||
if (logMsg != null) {
|
||||
this.emit('log', { isStdout, ...logMsg });
|
||||
}
|
||||
})
|
||||
.on('error', err => {
|
||||
this.emit(
|
||||
'error',
|
||||
new Error(`Error on container logs: ${err} ${err.stack}`),
|
||||
);
|
||||
})
|
||||
.on('end', () => this.emit('closed'));
|
||||
});
|
||||
}
|
||||
|
||||
private static extractMessage(
|
||||
|
@ -178,9 +178,9 @@ describe('LocalModeManager', () => {
|
||||
const stubEngineObjectMethods = (
|
||||
removeThrows: boolean,
|
||||
): Array<sinon.SinonStubbedInstance<EngineStubbedObject>> => {
|
||||
const resArray: Array<
|
||||
sinon.SinonStubbedInstance<EngineStubbedObject>
|
||||
> = [];
|
||||
const resArray: Array<sinon.SinonStubbedInstance<
|
||||
EngineStubbedObject
|
||||
>> = [];
|
||||
|
||||
const stub = <T>(
|
||||
c: sinon.StubbableType<EngineStubbedObject>,
|
||||
|
Loading…
Reference in New Issue
Block a user