mirror of
https://github.com/balena-io/balena-cli.git
synced 2024-12-23 23:42:24 +00:00
33552724a1
Change-type: patch Resolves: #1530 Signed-off-by: Scott Lowe <scott@balena.io>
283 lines
6.6 KiB
TypeScript
283 lines
6.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2019 Balena Ltd.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
import * as _ from 'lodash';
|
|
import * as nock from 'nock';
|
|
|
|
export class BalenaAPIMock {
|
|
public static basePathPattern = /api\.balena-cloud\.com/;
|
|
public readonly scope: nock.Scope;
|
|
// Expose `scope` as `expect` to allow for better semantics in tests
|
|
public readonly expect = this.scope;
|
|
|
|
// For debugging tests
|
|
get unfulfilledCallCount(): number {
|
|
return this.scope.pendingMocks().length;
|
|
}
|
|
|
|
constructor() {
|
|
nock.cleanAll();
|
|
|
|
if (!nock.isActive()) {
|
|
nock.activate();
|
|
}
|
|
|
|
this.scope = nock(BalenaAPIMock.basePathPattern);
|
|
|
|
nock.emitter.on('no match', this.handleUnexpectedRequest);
|
|
}
|
|
|
|
public done() {
|
|
// scope.done() will throw an error if there are expected api calls that have not happened.
|
|
// So ensures that all expected calls have been made.
|
|
this.scope.done();
|
|
// Remove 'no match' handler, for tests using nock without this module
|
|
nock.emitter.removeListener('no match', this.handleUnexpectedRequest);
|
|
// Restore unmocked behaviour
|
|
nock.cleanAll();
|
|
nock.restore();
|
|
}
|
|
|
|
public expectTestApp() {
|
|
this.scope
|
|
.get(/^\/v\d+\/application($|\?)/)
|
|
.reply(200, { d: [{ id: 1234567 }] });
|
|
}
|
|
|
|
public expectTestDevice(
|
|
fullUUID = 'f63fd7d7812c34c4c14ae023fdff05f5',
|
|
inaccessibleApp = false,
|
|
) {
|
|
const id = 7654321;
|
|
this.scope.get(/^\/v\d+\/device($|\?)/).reply(200, {
|
|
d: [
|
|
{
|
|
id,
|
|
uuid: fullUUID,
|
|
belongs_to__application: inaccessibleApp
|
|
? []
|
|
: [{ app_name: 'test' }],
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
public expectAppEnvVars() {
|
|
this.scope
|
|
.get(/^\/v\d+\/application_environment_variable($|\?)/)
|
|
.reply(200, {
|
|
d: [
|
|
{
|
|
id: 120101,
|
|
name: 'var1',
|
|
value: 'var1-val',
|
|
},
|
|
{
|
|
id: 120102,
|
|
name: 'var2',
|
|
value: '22',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
public expectAppConfigVars() {
|
|
this.scope.get(/^\/v\d+\/application_config_variable($|\?)/).reply(200, {
|
|
d: [
|
|
{
|
|
id: 120300,
|
|
name: 'RESIN_SUPERVISOR_NATIVE_LOGGER',
|
|
value: 'false',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
public expectAppServiceVars() {
|
|
this.scope
|
|
.get(/^\/v\d+\/service_environment_variable($|\?)/)
|
|
.reply(function(uri, _requestBody) {
|
|
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
|
const serviceName = (match && match[1]) || undefined;
|
|
let varArray: any[];
|
|
if (serviceName) {
|
|
const varObj = appServiceVarsByService[serviceName];
|
|
varArray = varObj ? [varObj] : [];
|
|
} else {
|
|
varArray = _.map(appServiceVarsByService, value => value);
|
|
}
|
|
return [200, { d: varArray }];
|
|
});
|
|
}
|
|
|
|
public expectDeviceEnvVars() {
|
|
this.scope.get(/^\/v\d+\/device_environment_variable($|\?)/).reply(200, {
|
|
d: [
|
|
{
|
|
id: 120203,
|
|
name: 'var3',
|
|
value: 'var3-val',
|
|
},
|
|
{
|
|
id: 120204,
|
|
name: 'var4',
|
|
value: '44',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
public expectDeviceConfigVars() {
|
|
this.scope.get(/^\/v\d+\/device_config_variable($|\?)/).reply(200, {
|
|
d: [
|
|
{
|
|
id: 120400,
|
|
name: 'RESIN_SUPERVISOR_POLL_INTERVAL',
|
|
value: '900900',
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
public expectDeviceServiceVars() {
|
|
this.scope
|
|
.get(/^\/v\d+\/device_service_environment_variable($|\?)/)
|
|
.reply(function(uri, _requestBody) {
|
|
const match = uri.match(/service_name%20eq%20%27(.+?)%27/);
|
|
const serviceName = (match && match[1]) || undefined;
|
|
let varArray: any[];
|
|
if (serviceName) {
|
|
const varObj = deviceServiceVarsByService[serviceName];
|
|
varArray = varObj ? [varObj] : [];
|
|
} else {
|
|
varArray = _.map(deviceServiceVarsByService, value => value);
|
|
}
|
|
return [200, { d: varArray }];
|
|
});
|
|
}
|
|
|
|
public expectConfigVars() {
|
|
this.scope.get('/config/vars').reply(200, {
|
|
reservedNames: [],
|
|
reservedNamespaces: [],
|
|
invalidRegex: '/^d|W/',
|
|
whiteListedNames: [],
|
|
whiteListedNamespaces: [],
|
|
blackListedNames: [],
|
|
configVarSchema: [],
|
|
});
|
|
}
|
|
|
|
public expectService(serviceName: string, serviceId = 243768) {
|
|
this.scope.get(/^\/v\d+\/service($|\?)/).reply(200, {
|
|
d: [{ id: serviceId, service_name: serviceName }],
|
|
});
|
|
}
|
|
|
|
// User details are cached in the SDK
|
|
// so often we don't know if we can expect the whoami request
|
|
public expectWhoAmI(persist = false, optional = true) {
|
|
const get = (persist ? this.scope.persist() : this.scope).get(
|
|
'/user/v1/whoami',
|
|
);
|
|
(optional ? get.optionally() : get).reply(200, {
|
|
id: 99999,
|
|
username: 'testuser',
|
|
email: 'testuser@test.com',
|
|
});
|
|
}
|
|
|
|
public expectMixpanel(optional = true) {
|
|
const get = this.scope.get(/^\/mixpanel\/track/);
|
|
(optional ? get.optionally() : get).reply(200, {});
|
|
}
|
|
|
|
protected handleUnexpectedRequest(req: any) {
|
|
console.error(`Unexpected http request!: ${req.path}`);
|
|
// Errors thrown here are not causing the tests to fail for some reason.
|
|
// Possibly due to CLI global error handlers? (error.js)
|
|
// (Also, nock should automatically throw an error, but also not happening)
|
|
// For now, the console.error is sufficient (will fail the test)
|
|
}
|
|
|
|
public debug() {
|
|
const scope = this.scope;
|
|
let mocks = scope.pendingMocks();
|
|
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
|
|
|
this.scope.on('request', function(_req, _interceptor, _body) {
|
|
console.log(`>> REQUEST:` + _req.path);
|
|
mocks = scope.pendingMocks();
|
|
console.error(`pending mocks ${mocks.length}: ${mocks}`);
|
|
});
|
|
|
|
this.scope.on('replied', function(_req) {
|
|
console.log(`<< REPLIED:` + _req.path);
|
|
});
|
|
}
|
|
}
|
|
|
|
const appServiceVarsByService: { [key: string]: any } = {
|
|
service1: {
|
|
id: 120110,
|
|
name: 'svar1',
|
|
value: 'svar1-value',
|
|
service: [
|
|
{
|
|
id: 210110,
|
|
service_name: 'service1',
|
|
},
|
|
],
|
|
},
|
|
service2: {
|
|
id: 120111,
|
|
name: 'svar2',
|
|
value: 'svar2-value',
|
|
service: [
|
|
{
|
|
id: 210111,
|
|
service_name: 'service2',
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
const deviceServiceVarsByService: { [key: string]: any } = {
|
|
service1: {
|
|
id: 120120,
|
|
name: 'svar3',
|
|
value: 'svar3-value',
|
|
service: [
|
|
{
|
|
id: 210110,
|
|
service_name: 'service1',
|
|
},
|
|
],
|
|
},
|
|
service2: {
|
|
id: 120121,
|
|
name: 'svar4',
|
|
value: 'svar4-value',
|
|
service: [
|
|
{
|
|
id: 210111,
|
|
service_name: 'service2',
|
|
},
|
|
],
|
|
},
|
|
};
|