|  |  |  | // NOTE: Temporarily allow `then` until we convert the entire file to `async` / `await`:
 | 
					
						
							|  |  |  | /* eslint-disable more/no-then */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const fs = require('fs'); | 
					
						
							|  |  |  | const path = require('path'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const tmp = require('tmp'); | 
					
						
							|  |  |  | const { expect } = require('chai'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { | 
					
						
							|  |  |  |   eliminateOutOfDateFiles, | 
					
						
							|  |  |  |   eliminateOldEntries, | 
					
						
							|  |  |  |   isLineAfterDate, | 
					
						
							|  |  |  |   fetchLog, | 
					
						
							|  |  |  |   fetch, | 
					
						
							|  |  |  | } = require('../../app/logging'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | describe('app/logging', () => { | 
					
						
							|  |  |  |   let basePath; | 
					
						
							|  |  |  |   let tmpDir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   beforeEach(() => { | 
					
						
							|  |  |  |     tmpDir = tmp.dirSync({ | 
					
						
							|  |  |  |       unsafeCleanup: true, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     basePath = tmpDir.name; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   afterEach(done => { | 
					
						
							|  |  |  |     // we need the unsafe option to recursively remove the directory
 | 
					
						
							|  |  |  |     tmpDir.removeCallback(done); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('#isLineAfterDate', () => { | 
					
						
							|  |  |  |     it('returns false if falsy', () => { | 
					
						
							|  |  |  |       const actual = isLineAfterDate('', new Date()); | 
					
						
							|  |  |  |       expect(actual).to.equal(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns false if invalid JSON', () => { | 
					
						
							|  |  |  |       const actual = isLineAfterDate('{{}', new Date()); | 
					
						
							|  |  |  |       expect(actual).to.equal(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns false if date is invalid', () => { | 
					
						
							|  |  |  |       const line = JSON.stringify({ time: '2018-01-04T19:17:05.014Z' }); | 
					
						
							|  |  |  |       const actual = isLineAfterDate(line, new Date('try6')); | 
					
						
							|  |  |  |       expect(actual).to.equal(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns false if log time is invalid', () => { | 
					
						
							|  |  |  |       const line = JSON.stringify({ time: 'try7' }); | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:00.000Z'); | 
					
						
							|  |  |  |       const actual = isLineAfterDate(line, date); | 
					
						
							|  |  |  |       expect(actual).to.equal(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns false if date before provided date', () => { | 
					
						
							|  |  |  |       const line = JSON.stringify({ time: '2018-01-04T19:17:00.000Z' }); | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:05.014Z'); | 
					
						
							|  |  |  |       const actual = isLineAfterDate(line, date); | 
					
						
							|  |  |  |       expect(actual).to.equal(false); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns true if date is after provided date', () => { | 
					
						
							|  |  |  |       const line = JSON.stringify({ time: '2018-01-04T19:17:05.014Z' }); | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:00.000Z'); | 
					
						
							|  |  |  |       const actual = isLineAfterDate(line, date); | 
					
						
							|  |  |  |       expect(actual).to.equal(true); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('#eliminateOutOfDateFiles', () => { | 
					
						
							|  |  |  |     it('deletes an empty file', () => { | 
					
						
							|  |  |  |       const date = new Date(); | 
					
						
							|  |  |  |       const log = '\n'; | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       fs.writeFileSync(target, log); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOutOfDateFiles(basePath, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.existsSync(target)).to.equal(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('deletes a file with invalid JSON lines', () => { | 
					
						
							|  |  |  |       const date = new Date(); | 
					
						
							|  |  |  |       const log = '{{}\n'; | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       fs.writeFileSync(target, log); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOutOfDateFiles(basePath, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.existsSync(target)).to.equal(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('deletes a file with all dates before provided date', () => { | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:05.014Z'); | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOutOfDateFiles(basePath, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.existsSync(target)).to.equal(false); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('keeps a file with first line date before provided date', () => { | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:16:00.000Z'); | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOutOfDateFiles(basePath, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.existsSync(target)).to.equal(true); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('keeps a file with last line date before provided date', () => { | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:01.000Z'); | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOutOfDateFiles(basePath, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.existsSync(target)).to.equal(true); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('#eliminateOldEntries', () => { | 
					
						
							|  |  |  |     it('eliminates all non-parsing entries', () => { | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:01.000Z'); | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         'random line', | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const expected = [ | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       const files = [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           path: target, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOldEntries(files, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.readFileSync(target, 'utf8')).to.equal(`${expected}\n`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('preserves all lines if before target date', () => { | 
					
						
							|  |  |  |       const date = new Date('2018-01-04T19:17:03.000Z'); | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         'random line', | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const expected = [ | 
					
						
							|  |  |  |         JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const target = path.join(basePath, 'log.log'); | 
					
						
							|  |  |  |       const files = [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           path: target, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return eliminateOldEntries(files, date).then(() => { | 
					
						
							|  |  |  |         expect(fs.readFileSync(target, 'utf8')).to.equal(`${expected}\n`); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('#fetchLog', () => { | 
					
						
							|  |  |  |     it('returns error if file does not exist', () => { | 
					
						
							|  |  |  |       const target = 'random_file'; | 
					
						
							|  |  |  |       return fetchLog(target).then( | 
					
						
							|  |  |  |         () => { | 
					
						
							|  |  |  |           throw new Error('Expected an error!'); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         error => { | 
					
						
							|  |  |  |           expect(error) | 
					
						
							|  |  |  |             .to.have.property('message') | 
					
						
							|  |  |  |             .that.match(/random_file/); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns empty array if file has no valid JSON lines', () => { | 
					
						
							|  |  |  |       const contents = 'line 1\nline2\n'; | 
					
						
							|  |  |  |       const expected = []; | 
					
						
							|  |  |  |       const target = path.join(basePath, 'test.log'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return fetchLog(target).then(result => { | 
					
						
							|  |  |  |         expect(result).to.deep.equal(expected); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns just three fields in each returned line', () => { | 
					
						
							|  |  |  |       const contents = [ | 
					
						
							|  |  |  |         JSON.stringify({ | 
					
						
							|  |  |  |           one: 1, | 
					
						
							|  |  |  |           two: 2, | 
					
						
							|  |  |  |           level: 1, | 
					
						
							|  |  |  |           time: 2, | 
					
						
							|  |  |  |           msg: 3, | 
					
						
							|  |  |  |         }), | 
					
						
							|  |  |  |         JSON.stringify({ | 
					
						
							|  |  |  |           one: 1, | 
					
						
							|  |  |  |           two: 2, | 
					
						
							|  |  |  |           level: 2, | 
					
						
							|  |  |  |           time: 3, | 
					
						
							|  |  |  |           msg: 4, | 
					
						
							|  |  |  |         }), | 
					
						
							|  |  |  |         '', | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const expected = [ | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           level: 1, | 
					
						
							|  |  |  |           time: 2, | 
					
						
							|  |  |  |           msg: 3, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           level: 2, | 
					
						
							|  |  |  |           time: 3, | 
					
						
							|  |  |  |           msg: 4, | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       const target = path.join(basePath, 'test.log'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fs.writeFileSync(target, contents); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return fetchLog(target).then(result => { | 
					
						
							|  |  |  |         expect(result).to.deep.equal(expected); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   describe('#fetch', () => { | 
					
						
							|  |  |  |     it('returns single entry if no files', () => { | 
					
						
							|  |  |  |       return fetch(basePath).then(results => { | 
					
						
							|  |  |  |         expect(results).to.have.length(1); | 
					
						
							|  |  |  |         expect(results[0].msg).to.match(/Loaded this list/); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     it('returns sorted entries from all files', () => { | 
					
						
							|  |  |  |       const first = [ | 
					
						
							|  |  |  |         JSON.stringify({ msg: 2, time: '2018-01-04T19:17:05.014Z' }), | 
					
						
							|  |  |  |         '', | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  |       const second = [ | 
					
						
							|  |  |  |         JSON.stringify({ msg: 1, time: '2018-01-04T19:17:00.014Z' }), | 
					
						
							|  |  |  |         JSON.stringify({ msg: 3, time: '2018-01-04T19:18:00.014Z' }), | 
					
						
							|  |  |  |         '', | 
					
						
							|  |  |  |       ].join('\n'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       fs.writeFileSync(path.join(basePath, 'first.log'), first); | 
					
						
							|  |  |  |       fs.writeFileSync(path.join(basePath, 'second.log'), second); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return fetch(basePath).then(results => { | 
					
						
							|  |  |  |         expect(results).to.have.length(4); | 
					
						
							|  |  |  |         expect(results[0].msg).to.equal(1); | 
					
						
							|  |  |  |         expect(results[1].msg).to.equal(2); | 
					
						
							|  |  |  |         expect(results[2].msg).to.equal(3); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }); |