mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2024-12-18 21:27:54 +00:00
Convert test/12-logger.spec.coffee to javascript
Change-type: patch
This commit is contained in:
parent
364fabd749
commit
fd4cec31e7
@ -1,116 +0,0 @@
|
|||||||
https = require 'https'
|
|
||||||
stream = require 'stream'
|
|
||||||
zlib = require 'zlib'
|
|
||||||
|
|
||||||
Promise = require 'bluebird'
|
|
||||||
{ expect } = require './lib/chai-config'
|
|
||||||
sinon = require 'sinon'
|
|
||||||
{ stub } = sinon
|
|
||||||
|
|
||||||
{ Logger } = require '../src/logger'
|
|
||||||
{ ContainerLogs } = require '../src/logging/container'
|
|
||||||
describe 'Logger', ->
|
|
||||||
beforeEach ->
|
|
||||||
@_req = new stream.PassThrough()
|
|
||||||
@_req.flushHeaders = sinon.spy()
|
|
||||||
@_req.end = sinon.spy()
|
|
||||||
|
|
||||||
@_req.body = ''
|
|
||||||
@_req
|
|
||||||
.pipe(zlib.createGunzip())
|
|
||||||
.on 'data', (chunk) =>
|
|
||||||
@_req.body += chunk
|
|
||||||
|
|
||||||
stub(https, 'request').returns(@_req)
|
|
||||||
|
|
||||||
@fakeEventTracker = {
|
|
||||||
track: sinon.spy()
|
|
||||||
}
|
|
||||||
|
|
||||||
@logger = new Logger({ eventTracker: @fakeEventTracker })
|
|
||||||
@logger.init({
|
|
||||||
apiEndpoint: 'https://example.com'
|
|
||||||
uuid: 'deadbeef'
|
|
||||||
deviceApiKey: 'secretkey'
|
|
||||||
unmanaged: false
|
|
||||||
enableLogs: true
|
|
||||||
localMode: false
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach ->
|
|
||||||
https.request.restore()
|
|
||||||
|
|
||||||
it 'waits the grace period before sending any logs', ->
|
|
||||||
clock = sinon.useFakeTimers()
|
|
||||||
@logger.log({ message: 'foobar', serviceId: 15 })
|
|
||||||
clock.tick(4999)
|
|
||||||
clock.restore()
|
|
||||||
|
|
||||||
Promise.delay(100)
|
|
||||||
.then =>
|
|
||||||
expect(@_req.body).to.equal('')
|
|
||||||
|
|
||||||
it 'tears down the connection after inactivity', ->
|
|
||||||
clock = sinon.useFakeTimers()
|
|
||||||
@logger.log({ message: 'foobar', serviceId: 15 })
|
|
||||||
clock.tick(61000)
|
|
||||||
clock.restore()
|
|
||||||
|
|
||||||
Promise.delay(100)
|
|
||||||
.then =>
|
|
||||||
expect(@_req.end.calledOnce).to.be.true
|
|
||||||
|
|
||||||
|
|
||||||
it 'sends logs as gzipped ndjson', ->
|
|
||||||
timestamp = Date.now()
|
|
||||||
@logger.log({ message: 'foobar', serviceId: 15 })
|
|
||||||
@logger.log({ timestamp: 1337, message: 'foobar', serviceId: 15 })
|
|
||||||
@logger.log({ message: 'foobar' }) # shold be ignored
|
|
||||||
|
|
||||||
Promise.delay(5500).then =>
|
|
||||||
expect(https.request.calledOnce).to.be.true
|
|
||||||
opts = https.request.firstCall.args[0]
|
|
||||||
|
|
||||||
expect(opts.href).to.equal('https://example.com/device/v2/deadbeef/log-stream')
|
|
||||||
expect(opts.method).to.equal('POST')
|
|
||||||
expect(opts.headers).to.deep.equal({
|
|
||||||
'Authorization': 'Bearer secretkey'
|
|
||||||
'Content-Type': 'application/x-ndjson'
|
|
||||||
'Content-Encoding': 'gzip'
|
|
||||||
})
|
|
||||||
|
|
||||||
lines = @_req.body.split('\n')
|
|
||||||
expect(lines.length).to.equal(3)
|
|
||||||
expect(lines[2]).to.equal('')
|
|
||||||
|
|
||||||
msg = JSON.parse(lines[0])
|
|
||||||
expect(msg).to.have.property('message').that.equals('foobar')
|
|
||||||
expect(msg).to.have.property('serviceId').that.equals(15)
|
|
||||||
expect(msg).to.have.property('timestamp').that.is.at.least(timestamp)
|
|
||||||
msg = JSON.parse(lines[1])
|
|
||||||
expect(msg).to.deep.equal({ timestamp: 1337, message: 'foobar', serviceId: 15 })
|
|
||||||
|
|
||||||
it 'allows logging system messages which are also reported to the eventTracker', ->
|
|
||||||
timestamp = Date.now()
|
|
||||||
@logger.logSystemMessage('Hello there!', { someProp: 'someVal' }, 'Some event name')
|
|
||||||
|
|
||||||
Promise.delay(5500)
|
|
||||||
.then =>
|
|
||||||
expect(@fakeEventTracker.track).to.be.calledWith('Some event name', { someProp: 'someVal' })
|
|
||||||
lines = @_req.body.split('\n')
|
|
||||||
expect(lines.length).to.equal(2)
|
|
||||||
expect(lines[1]).to.equal('')
|
|
||||||
|
|
||||||
msg = JSON.parse(lines[0])
|
|
||||||
expect(msg).to.have.property('message').that.equals('Hello there!')
|
|
||||||
expect(msg).to.have.property('isSystem').that.equals(true)
|
|
||||||
expect(msg).to.have.property('timestamp').that.is.at.least(timestamp)
|
|
||||||
|
|
||||||
it 'should support non-tty log lines', ->
|
|
||||||
message = '\u0001\u0000\u0000\u0000\u0000\u0000\u0000?2018-09-21T12:37:09.819134000Z this is the message'
|
|
||||||
buffer = Buffer.from(message)
|
|
||||||
|
|
||||||
expect(ContainerLogs.extractMessage(buffer)).to.deep.equal({
|
|
||||||
message: 'this is the message',
|
|
||||||
timestamp: 1537533429819
|
|
||||||
})
|
|
148
test/12-logger.spec.js
Normal file
148
test/12-logger.spec.js
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
import * as https from 'https';
|
||||||
|
import * as stream from 'stream';
|
||||||
|
import * as zlib from 'zlib';
|
||||||
|
import * as Promise from 'bluebird';
|
||||||
|
import { expect } from './lib/chai-config';
|
||||||
|
import * as sinon from 'sinon';
|
||||||
|
|
||||||
|
import { Logger } from '../src/logger';
|
||||||
|
import { ContainerLogs } from '../src/logging/container';
|
||||||
|
describe('Logger', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
this._req = new stream.PassThrough();
|
||||||
|
this._req.flushHeaders = sinon.spy();
|
||||||
|
this._req.end = sinon.spy();
|
||||||
|
|
||||||
|
this._req.body = '';
|
||||||
|
this._req.pipe(zlib.createGunzip()).on('data', chunk => {
|
||||||
|
this._req.body += chunk;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.requestStub = sinon.stub(https, 'request').returns(this._req);
|
||||||
|
|
||||||
|
this.fakeEventTracker = {
|
||||||
|
track: sinon.spy(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore missing db property
|
||||||
|
this.logger = new Logger({ eventTracker: this.fakeEventTracker });
|
||||||
|
return this.logger.init({
|
||||||
|
apiEndpoint: 'https://example.com',
|
||||||
|
uuid: 'deadbeef',
|
||||||
|
deviceApiKey: 'secretkey',
|
||||||
|
unmanaged: false,
|
||||||
|
enableLogs: true,
|
||||||
|
localMode: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
this.requestStub.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('waits the grace period before sending any logs', function() {
|
||||||
|
const clock = sinon.useFakeTimers();
|
||||||
|
this.logger.log({ message: 'foobar', serviceId: 15 });
|
||||||
|
clock.tick(4999);
|
||||||
|
clock.restore();
|
||||||
|
|
||||||
|
return Promise.delay(100).then(() => {
|
||||||
|
expect(this._req.body).to.equal('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('tears down the connection after inactivity', function() {
|
||||||
|
const clock = sinon.useFakeTimers();
|
||||||
|
this.logger.log({ message: 'foobar', serviceId: 15 });
|
||||||
|
clock.tick(61000);
|
||||||
|
clock.restore();
|
||||||
|
|
||||||
|
return Promise.delay(100).then(() => {
|
||||||
|
expect(this._req.end.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sends logs as gzipped ndjson', function() {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
this.logger.log({ message: 'foobar', serviceId: 15 });
|
||||||
|
this.logger.log({ timestamp: 1337, message: 'foobar', serviceId: 15 });
|
||||||
|
this.logger.log({ message: 'foobar' }); // shold be ignored
|
||||||
|
|
||||||
|
return Promise.delay(5500).then(() => {
|
||||||
|
expect(this.requestStub.calledOnce).to.be.true;
|
||||||
|
const opts = this.requestStub.firstCall.args[0];
|
||||||
|
|
||||||
|
expect(opts.href).to.equal(
|
||||||
|
'https://example.com/device/v2/deadbeef/log-stream',
|
||||||
|
);
|
||||||
|
expect(opts.method).to.equal('POST');
|
||||||
|
expect(opts.headers).to.deep.equal({
|
||||||
|
Authorization: 'Bearer secretkey',
|
||||||
|
'Content-Type': 'application/x-ndjson',
|
||||||
|
'Content-Encoding': 'gzip',
|
||||||
|
});
|
||||||
|
|
||||||
|
const lines = this._req.body.split('\n');
|
||||||
|
expect(lines.length).to.equal(3);
|
||||||
|
expect(lines[2]).to.equal('');
|
||||||
|
|
||||||
|
let msg = JSON.parse(lines[0]);
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('message')
|
||||||
|
.that.equals('foobar');
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('serviceId')
|
||||||
|
.that.equals(15);
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('timestamp')
|
||||||
|
.that.is.at.least(timestamp);
|
||||||
|
msg = JSON.parse(lines[1]);
|
||||||
|
expect(msg).to.deep.equal({
|
||||||
|
timestamp: 1337,
|
||||||
|
message: 'foobar',
|
||||||
|
serviceId: 15,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('allows logging system messages which are also reported to the eventTracker', function() {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
this.logger.logSystemMessage(
|
||||||
|
'Hello there!',
|
||||||
|
{ someProp: 'someVal' },
|
||||||
|
'Some event name',
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.delay(5500).then(() => {
|
||||||
|
expect(this.fakeEventTracker.track).to.be.calledWith('Some event name', {
|
||||||
|
someProp: 'someVal',
|
||||||
|
});
|
||||||
|
const lines = this._req.body.split('\n');
|
||||||
|
expect(lines.length).to.equal(2);
|
||||||
|
expect(lines[1]).to.equal('');
|
||||||
|
|
||||||
|
const msg = JSON.parse(lines[0]);
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('message')
|
||||||
|
.that.equals('Hello there!');
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('isSystem')
|
||||||
|
.that.equals(true);
|
||||||
|
expect(msg)
|
||||||
|
.to.have.property('timestamp')
|
||||||
|
.that.is.at.least(timestamp);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support non-tty log lines', function() {
|
||||||
|
const message =
|
||||||
|
'\u0001\u0000\u0000\u0000\u0000\u0000\u0000?2018-09-21T12:37:09.819134000Z this is the message';
|
||||||
|
const buffer = Buffer.from(message);
|
||||||
|
|
||||||
|
// @ts-ignore accessing a private function
|
||||||
|
expect(ContainerLogs.extractMessage(buffer)).to.deep.equal({
|
||||||
|
message: 'this is the message',
|
||||||
|
timestamp: 1537533429819,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -4,5 +4,5 @@
|
|||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"checkJs": true
|
"checkJs": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "typings/**/*.d.ts"]
|
"include": ["src/**/*", "test/**/*", "typings/**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
@ -11,5 +11,5 @@
|
|||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "test/**/*.ts", "typings/**/*.d.ts"]
|
"include": ["src/**/*", "test/**/*", "typings/**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"preserveConstEnums": true,
|
"preserveConstEnums": true,
|
||||||
"removeComments": true
|
"removeComments": true
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.js", "typings/**/*.d.ts"]
|
"include": ["src/**/*", "typings/**/*.d.ts"]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user