@razee/kubernetes-util
Version:
A set of Kubernetes API utilities to facilitate resource discovery and watches
292 lines (279 loc) • 9.62 kB
JavaScript
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
*
* 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.
*/
const assert = require('chai').assert;
const nock = require('nock');
const watchman = require('../lib/Watchman');
const log = require('../lib/bunyan-api').createLogger('Watchman-test');
const KubeApiConfig = require('../lib/KubeApiConfig');
const Stream = require('stream');
KubeApiConfig({ localhost: true });
const dummyOptions = { rewatchOnTimeout: false, requestOptions: { baseUrl: 'https://localhost:32263', uri: '/api/v1/watch/namespaces/default/services/kubernetes' } };
const data1 = { 'type': 'ADDED', 'object': { 'kind': 'Service', 'apiVersion': 'v1', 'metadata': { 'name': 'kubernetes', 'namespace': 'default', 'selfLink': '/api/v1/namespaces/default/services/kubernetes', 'uid': '7c75c135-fca7-11e8-9f10-3a7d3a0f8cf2', 'resourceVersion': '14840391', 'creationTimestamp': '2018-12-10T18:14:51Z', 'labels': { 'component': 'apiserver', 'provider': 'kubernetes', 'razee/watch-resource': 'lite' } }, 'spec': { 'ports': [{ 'name': 'https', 'protocol': 'TCP', 'port': 443, 'targetPort': 2040 }], 'clusterIP': '172.21.0.1', 'type': 'ClusterIP', 'sessionAffinity': 'None' }, 'status': { 'loadBalancer': {} } } };
let mockObjectHandler = (data) => { }; // eslint-disable-line no-unused-vars
describe('watchman', () => {
describe('#constructor', () => {
it('success', () => {
let errorsHappen = false;
try {
var wm = new watchman(dummyOptions, mockObjectHandler); // eslint-disable-line no-unused-vars
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(errorsHappen);
}
});
it('bad objecthandler', () => {
let errorsHappen = false;
try {
var wm = new watchman(dummyOptions, ''); // eslint-disable-line no-unused-vars
} catch (err) {
errorsHappen = true;
assert.equal(err, 'Watchman objectHandler must be a function.');
} finally {
assert.isTrue(errorsHappen);
}
});
it('bad uri', () => {
let errorsHappen = false;
try {
var wm = new watchman('', mockObjectHandler); // eslint-disable-line no-unused-vars
} catch (err) {
assert.include(err, 'not valid watch uri');
errorsHappen = true;
}
assert.isTrue(errorsHappen);
});
it('bad logger', () => {
let errorsHappen = false;
try {
let options = dummyOptions;
options.logger = 'notanobject';
var wm = new watchman(options, mockObjectHandler); // eslint-disable-line no-unused-vars
} catch (err) {
errorsHappen = true;
assert.equal(err, 'options.logger must be an object.');
} finally {
assert.isTrue(errorsHappen);
}
});
});
describe('#selfLink', () => {
it('success', () => {
let errorsHappen = false;
try {
let options = dummyOptions;
options.logger = { fakeLogger: true };
var wm = new watchman(options, mockObjectHandler);
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.equal(wm.selfLink, '/api/v1/watch/namespaces/default/services/kubernetes');
assert.isFalse(errorsHappen);
}
});
});
describe('#logger', () => {
it('success', () => {
let errorsHappen = false;
try {
let options = dummyOptions;
options.logger = { fakeLogger: true };
var wm = new watchman(dummyOptions, mockObjectHandler);
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.deepEqual(wm.logger, { fakeLogger: true });
assert.isFalse(errorsHappen);
}
});
});
describe('#objectHandler', () => {
it('success', () => {
let errorsHappen = false;
try {
var wm = new watchman(dummyOptions, mockObjectHandler);
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.equal(wm.objectHandler, mockObjectHandler);
assert.isFalse(errorsHappen);
}
});
});
describe('#watching', () => {
it('success', () => {
let errorsHappen = false;
try {
var wm = new watchman(dummyOptions, mockObjectHandler);
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(wm.watching);
assert.isFalse(errorsHappen);
}
});
});
describe('#watch', () => {
it('success', (done) => {
let dummyLogger = {
debug: (msg) => {
log.debug('dummyLogger', msg);
},
info: (msg) => {
log.info('dummyLogger', msg);
},
error: (msg) => {
log.error('dummyLogger', msg);
}
};
let xmockObjectHandler = (data) => {
assert.deepEqual(data, data1);
done();
};
let myOptions = dummyOptions;
myOptions.logger = dummyLogger;
nock('https://localhost:32263')
.get('/api/v1/watch/namespaces/default/services/kubernetes')
.reply(200, data1);
let errorsHappen = false;
try {
var wm = new watchman(myOptions, xmockObjectHandler);
wm.watch();
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(wm.watching);
assert.isFalse(errorsHappen);
}
});
it('end', (done) => {
let xmockObjectHandler = (data) => { // eslint-disable-line no-unused-vars
assert.fail('should not get here');
};
nock('https://localhost:32263')
.get('/api/v1/namespaces/default/services/kubernetes')
.reply(200, data1);
let errorsHappen = false;
try {
var wm = new watchman(dummyOptions, xmockObjectHandler);
wm.watch();
wm.end();
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(wm.watching);
assert.isFalse(errorsHappen);
done();
}
});
it('errorResponse', (done) => {
let wm;
let dummyLogger = {
debug: (msg) => {
log.debug('dummyLogger', msg);
},
info: (msg) => {
log.info('dummyLogger', msg);
},
error: (msg) => {
assert.equal(msg, 'GET /api/v1/watch/namespaces/default/services/kubernetes returned 201');
wm.end();
done();
}
};
let myOptions = dummyOptions;
myOptions.logger = dummyLogger;
myOptions.requestOptions.baseUrl = 'https://localhost:666';
myOptions.rewatchOnTimeout = false;
let xmockObjectHandler = (data) => {
log.info('xmockObjectHandler', data);
};
nock('https://localhost:666')
.get('/api/v1/watch/namespaces/default/services/kubernetes')
.reply( 201, {} ); // Needs to return some data since it's a stream -- otherwise will not call `.on('data')`, which is where the logger.error is called
let errorsHappen = false;
try {
wm = new watchman(myOptions, xmockObjectHandler);
wm.watch();
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(wm.watching);
assert.isFalse(errorsHappen);
}
});
it('errorstream', (done) => {
let wm;
let dummyLogger = {
debug: (msg) => {
log.debug('dummyLogger', msg);
},
info: (msg) => {
log.info('dummyLogger', msg);
},
error: (msg) => {
assert.equal(msg, 'GET /api/v1/watch/namespaces/default/services/kubernetes errored');
wm.end();
done();
}
};
let myOptions = dummyOptions;
myOptions.logger = dummyLogger;
myOptions.requestOptions.baseUrl = 'https://localhost:666';
myOptions.rewatchOnTimeout = false;
let xmockObjectHandler = (data) => {
log.info('xmockObjectHandler', data);
};
// Create a dummy stream that will return data 3 times and then an error
let eventCount = 0;
const mockEventStream = new Stream.Readable({
objectMode: true,
read: function() {
eventCount++;
if (eventCount <= 3) {
console.log( `stream returning data (event ${eventCount})` );
return this.push(JSON.stringify({message: `event${eventCount}`}));
}
else {
return this.emit('error', new Error( 'errstring' ));
}
}
});
nock('https://localhost:666')
.get('/api/v1/watch/namespaces/default/services/kubernetes')
.reply(200, mockEventStream);
let errorsHappen = false;
try {
wm = new watchman(myOptions, xmockObjectHandler);
wm.watch();
} catch (err) {
errorsHappen = true;
assert.equal(err, '');
} finally {
assert.isFalse(wm.watching);
assert.isFalse(errorsHappen);
}
});
});
});