Use spies for CloudCode logger tests (#5042)
This commit is contained in:
@@ -9,27 +9,35 @@ const loremFile = __dirname + '/support/lorem.txt';
|
|||||||
|
|
||||||
describe('Cloud Code Logger', () => {
|
describe('Cloud Code Logger', () => {
|
||||||
let user;
|
let user;
|
||||||
|
let spy;
|
||||||
beforeEach(done => {
|
beforeEach(async () => {
|
||||||
Parse.User.enableUnsafeCurrentUser();
|
Parse.User.enableUnsafeCurrentUser();
|
||||||
return reconfigureServer({
|
return reconfigureServer({
|
||||||
// useful to flip to false for fine tuning :).
|
// useful to flip to false for fine tuning :).
|
||||||
silent: true,
|
silent: true,
|
||||||
}).then(() => {
|
})
|
||||||
return Parse.User.signUp('tester', 'abc')
|
.then(() => {
|
||||||
.then(loggedInUser => (user = loggedInUser))
|
return Parse.User.signUp('tester', 'abc')
|
||||||
.then(() => Parse.User.logIn(user.get('username'), 'abc'))
|
.catch(() => {})
|
||||||
.then(() => done());
|
.then(loggedInUser => (user = loggedInUser))
|
||||||
});
|
.then(() => Parse.User.logIn(user.get('username'), 'abc'));
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
spy = spyOn(
|
||||||
|
Config.get('test').loggerController.adapter,
|
||||||
|
'log'
|
||||||
|
).and.callThrough();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note that helpers takes care of logout.
|
// Note that helpers takes care of logout.
|
||||||
// see helpers.js:afterEach
|
// see helpers.js:afterEach
|
||||||
|
|
||||||
it('should expose log to functions', () => {
|
it('should expose log to functions', () => {
|
||||||
const config = Config.get('test');
|
const spy = spyOn(
|
||||||
const spy = spyOn(config.loggerController, 'log').and.callThrough();
|
Config.get('test').loggerController,
|
||||||
|
'log'
|
||||||
|
).and.callThrough();
|
||||||
Parse.Cloud.define('loggerTest', req => {
|
Parse.Cloud.define('loggerTest', req => {
|
||||||
req.log.info('logTest', 'info log', { info: 'some log' });
|
req.log.info('logTest', 'info log', { info: 'some log' });
|
||||||
req.log.error('logTest', 'error log', { error: 'there was an error' });
|
req.log.error('logTest', 'error log', { error: 'there was an error' });
|
||||||
@@ -61,26 +69,21 @@ describe('Cloud Code Logger', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('trigger should obfuscate password', done => {
|
it('trigger should obfuscate password', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
|
|
||||||
Parse.Cloud.beforeSave(Parse.User, req => {
|
Parse.Cloud.beforeSave(Parse.User, req => {
|
||||||
return req.object;
|
return req.object;
|
||||||
});
|
});
|
||||||
|
|
||||||
Parse.User.signUp('tester123', 'abc')
|
Parse.User.signUp('tester123', 'abc')
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
.then(() => {
|
||||||
.then(res => {
|
const entry = spy.calls.mostRecent().args;
|
||||||
const entry = res[0];
|
expect(entry[1]).not.toMatch(/password":"abc/);
|
||||||
expect(entry.message).not.toMatch(/password":"abc/);
|
expect(entry[1]).toMatch(/\*\*\*\*\*\*\*\*/);
|
||||||
expect(entry.message).toMatch(/\*\*\*\*\*\*\*\*/);
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.then(null, e => done.fail(e));
|
.then(null, e => done.fail(e));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should expose log to trigger', done => {
|
it('should expose log to trigger', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
|
|
||||||
Parse.Cloud.beforeSave('MyObject', req => {
|
Parse.Cloud.beforeSave('MyObject', req => {
|
||||||
req.log.info('beforeSave MyObject', 'info log', { info: 'some log' });
|
req.log.info('beforeSave MyObject', 'info log', { info: 'some log' });
|
||||||
req.log.error('beforeSave MyObject', 'error log', {
|
req.log.error('beforeSave MyObject', 'error log', {
|
||||||
@@ -90,31 +93,29 @@ describe('Cloud Code Logger', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const obj = new Parse.Object('MyObject');
|
const obj = new Parse.Object('MyObject');
|
||||||
obj
|
obj.save().then(() => {
|
||||||
.save()
|
const lastCalls = spy.calls.all().reverse();
|
||||||
.then(() => {
|
const cloudTriggerMessage = lastCalls[0].args;
|
||||||
return logController.getLogs({ from: Date.now() - 500, size: 1000 });
|
const errorMessage = lastCalls[1].args;
|
||||||
})
|
const infoMessage = lastCalls[2].args;
|
||||||
.then(res => {
|
expect(cloudTriggerMessage[0]).toBe('info');
|
||||||
expect(res.length).not.toBe(0);
|
expect(cloudTriggerMessage[2].triggerType).toEqual('beforeSave');
|
||||||
const lastLogs = res.slice(0, 3);
|
expect(cloudTriggerMessage[1]).toMatch(
|
||||||
const cloudTriggerMessage = lastLogs[0];
|
/beforeSave triggered for MyObject for user [^ ]*\n {2}Input: {}\n {2}Result: {}/
|
||||||
const errorMessage = lastLogs[1];
|
);
|
||||||
const infoMessage = lastLogs[2];
|
expect(cloudTriggerMessage[2].user).toBe(user.id);
|
||||||
expect(cloudTriggerMessage.level).toBe('info');
|
expect(errorMessage[0]).toBe('error');
|
||||||
expect(cloudTriggerMessage.triggerType).toEqual('beforeSave');
|
expect(errorMessage[3].error).toBe('there was an error');
|
||||||
expect(cloudTriggerMessage.message).toMatch(
|
expect(errorMessage[1] + ' ' + errorMessage[2]).toBe(
|
||||||
/beforeSave triggered for MyObject for user [^ ]*\n {2}Input: {}\n {2}Result: {}/
|
'beforeSave MyObject error log'
|
||||||
);
|
);
|
||||||
expect(cloudTriggerMessage.user).toBe(user.id);
|
expect(infoMessage[0]).toBe('info');
|
||||||
expect(errorMessage.level).toBe('error');
|
expect(infoMessage[3].info).toBe('some log');
|
||||||
expect(errorMessage.error).toBe('there was an error');
|
expect(infoMessage[1] + ' ' + infoMessage[2]).toBe(
|
||||||
expect(errorMessage.message).toBe('beforeSave MyObject error log');
|
'beforeSave MyObject info log'
|
||||||
expect(infoMessage.level).toBe('info');
|
);
|
||||||
expect(infoMessage.info).toBe('some log');
|
done();
|
||||||
expect(infoMessage.message).toBe('beforeSave MyObject info log');
|
});
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should truncate really long lines when asked to', () => {
|
it('should truncate really long lines when asked to', () => {
|
||||||
@@ -125,18 +126,16 @@ describe('Cloud Code Logger', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should truncate input and result of long lines', done => {
|
it('should truncate input and result of long lines', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
const longString = fs.readFileSync(loremFile, 'utf8');
|
const longString = fs.readFileSync(loremFile, 'utf8');
|
||||||
Parse.Cloud.define('aFunction', req => {
|
Parse.Cloud.define('aFunction', req => {
|
||||||
return req.params;
|
return req.params;
|
||||||
});
|
});
|
||||||
|
|
||||||
Parse.Cloud.run('aFunction', { longString })
|
Parse.Cloud.run('aFunction', { longString })
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
.then(() => {
|
||||||
.then(logs => {
|
const log = spy.calls.mostRecent().args;
|
||||||
const log = logs[0];
|
expect(log[0]).toEqual('info');
|
||||||
expect(log.level).toEqual('info');
|
expect(log[1]).toMatch(
|
||||||
expect(log.message).toMatch(
|
|
||||||
/Ran cloud function aFunction for user [^ ]* with:\n {2}Input: {.*?\(truncated\)$/m
|
/Ran cloud function aFunction for user [^ ]* with:\n {2}Input: {.*?\(truncated\)$/m
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
@@ -145,14 +144,12 @@ describe('Cloud Code Logger', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should log an afterSave', done => {
|
it('should log an afterSave', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
Parse.Cloud.afterSave('MyObject', () => {});
|
Parse.Cloud.afterSave('MyObject', () => {});
|
||||||
new Parse.Object('MyObject')
|
new Parse.Object('MyObject')
|
||||||
.save()
|
.save()
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
.then(() => {
|
||||||
.then(logs => {
|
const log = spy.calls.mostRecent().args;
|
||||||
const log = logs[0];
|
expect(log[2].triggerType).toEqual('afterSave');
|
||||||
expect(log.triggerType).toEqual('afterSave');
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
// catch errors - not that the error is actually useful :(
|
// catch errors - not that the error is actually useful :(
|
||||||
@@ -160,7 +157,6 @@ describe('Cloud Code Logger', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should log a denied beforeSave', done => {
|
it('should log a denied beforeSave', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
Parse.Cloud.beforeSave('MyObject', () => {
|
Parse.Cloud.beforeSave('MyObject', () => {
|
||||||
throw 'uh oh!';
|
throw 'uh oh!';
|
||||||
});
|
});
|
||||||
@@ -171,54 +167,51 @@ describe('Cloud Code Logger', () => {
|
|||||||
() => done.fail('this is not supposed to succeed'),
|
() => done.fail('this is not supposed to succeed'),
|
||||||
() => new Promise(resolve => setTimeout(resolve, 100))
|
() => new Promise(resolve => setTimeout(resolve, 100))
|
||||||
)
|
)
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
.then(() => {
|
||||||
.then(logs => {
|
const logs = spy.calls.all().reverse();
|
||||||
const log = logs[1]; // 0 is the 'uh oh!' from rejection...
|
const log = logs[1].args; // 0 is the 'uh oh!' from rejection...
|
||||||
expect(log.level).toEqual('error');
|
expect(log[0]).toEqual('error');
|
||||||
expect(log.error).toEqual({ code: 141, message: 'uh oh!' });
|
const error = log[2].error;
|
||||||
|
expect(error instanceof Parse.Error).toBeTruthy();
|
||||||
|
expect(error.code).toBe(141);
|
||||||
|
expect(error.message).toBe('uh oh!');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log cloud function success', done => {
|
it('should log cloud function success', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
|
|
||||||
Parse.Cloud.define('aFunction', () => {
|
Parse.Cloud.define('aFunction', () => {
|
||||||
return 'it worked!';
|
return 'it worked!';
|
||||||
});
|
});
|
||||||
|
|
||||||
Parse.Cloud.run('aFunction', { foo: 'bar' })
|
Parse.Cloud.run('aFunction', { foo: 'bar' }).then(() => {
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
const log = spy.calls.mostRecent().args;
|
||||||
.then(logs => {
|
expect(log[0]).toEqual('info');
|
||||||
const log = logs[0];
|
expect(log[1]).toMatch(
|
||||||
expect(log.level).toEqual('info');
|
/Ran cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Result: "it worked!/
|
||||||
expect(log.message).toMatch(
|
);
|
||||||
/Ran cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Result: "it worked!/
|
done();
|
||||||
);
|
});
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should log cloud function failure', done => {
|
it('should log cloud function failure', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
|
|
||||||
Parse.Cloud.define('aFunction', () => {
|
Parse.Cloud.define('aFunction', () => {
|
||||||
throw 'it failed!';
|
throw 'it failed!';
|
||||||
});
|
});
|
||||||
|
|
||||||
Parse.Cloud.run('aFunction', { foo: 'bar' })
|
Parse.Cloud.run('aFunction', { foo: 'bar' })
|
||||||
.then(null, () =>
|
.catch(() => {})
|
||||||
logController.getLogs({ from: Date.now() - 500, size: 1000 })
|
.then(() => {
|
||||||
)
|
const logs = spy.calls.all().reverse();
|
||||||
.then(logs => {
|
expect(logs[0].args[1]).toBe('it failed!');
|
||||||
expect(logs[0].message).toBe('it failed!');
|
const log = logs[1].args;
|
||||||
const log = logs[1];
|
expect(log[0]).toEqual('error');
|
||||||
expect(log.level).toEqual('error');
|
expect(log[1]).toMatch(
|
||||||
expect(log.message).toMatch(
|
/Failed running cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Error:/
|
||||||
/Failed running cloud function aFunction for user [^ ]* with:\n {2}Input: {"foo":"bar"}\n {2}Error: {"code":141,"message":"it failed!"}/
|
|
||||||
);
|
);
|
||||||
done();
|
done();
|
||||||
});
|
})
|
||||||
|
.catch(done.fail);
|
||||||
});
|
});
|
||||||
|
|
||||||
xit('should log a changed beforeSave indicating a change', done => {
|
xit('should log a changed beforeSave indicating a change', done => {
|
||||||
@@ -247,17 +240,14 @@ describe('Cloud Code Logger', () => {
|
|||||||
}).pend('needs more work.....');
|
}).pend('needs more work.....');
|
||||||
|
|
||||||
it('cloud function should obfuscate password', done => {
|
it('cloud function should obfuscate password', done => {
|
||||||
const logController = new LoggerController(new WinstonLoggerAdapter());
|
|
||||||
|
|
||||||
Parse.Cloud.define('testFunction', () => {
|
Parse.Cloud.define('testFunction', () => {
|
||||||
return 'verify code success';
|
return 'verify code success';
|
||||||
});
|
});
|
||||||
|
|
||||||
Parse.Cloud.run('testFunction', { username: 'hawk', password: '123456' })
|
Parse.Cloud.run('testFunction', { username: 'hawk', password: '123456' })
|
||||||
.then(() => logController.getLogs({ from: Date.now() - 500, size: 1000 }))
|
.then(() => {
|
||||||
.then(res => {
|
const entry = spy.calls.mostRecent().args;
|
||||||
const entry = res[0];
|
expect(entry[2].params.password).toMatch(/\*\*\*\*\*\*\*\*/);
|
||||||
expect(entry.params.password).toMatch(/\*\*\*\*\*\*\*\*/);
|
|
||||||
done();
|
done();
|
||||||
})
|
})
|
||||||
.then(null, e => done.fail(e));
|
.then(null, e => done.fail(e));
|
||||||
|
|||||||
Reference in New Issue
Block a user