require('should'); const _ = require('lodash'); const path = require('path'); const zlib = require('zlib'); const async = require('async'); const stream = require('stream'); const fs = require('fs-extra'); const proxyquire = require('proxyquire').noPreserveCache(); let fakeNow = new Date(2012, 8, 12, 10, 37, 11); const mockNow = () => fakeNow; const RollingFileWriteStream = proxyquire('../lib/RollingFileWriteStream', { './now': mockNow }); let fakedFsDate = fakeNow; const mockFs = require('fs-extra'); const oldStatSync = mockFs.statSync mockFs.statSync = fd => { const result = oldStatSync(fd); result.birthtime = fakedFsDate; return result; } function generateTestFile(fileName) { const dirName = path.join(__dirname, 'tmp_' + Math.floor(Math.random() * new Date())); fileName = fileName || 'ignored.log'; const fileNameObj = path.parse(fileName); return { dir: dirName, base: fileNameObj.base, name: fileNameObj.name, ext: fileNameObj.ext, path: path.join(dirName, fileName) }; } function resetTime() { fakeNow = new Date(2012, 8, 12, 10, 37, 11); fakedFsDate = fakeNow; } describe('RollingFileWriteStream', () => { beforeEach(() => { resetTime(); }); after(() => { fs .readdirSync(__dirname) .filter(f => f.startsWith('tmp_')) .forEach(f => fs.removeSync(path.join(__dirname, f))); }); describe('with no arguments', () => { it('should throw an error', () => { (() => new RollingFileWriteStream()).should.throw( /(the )?"?path"? (argument )?must be (a|of type) string\. received (type )?undefined/i); }); }); describe('with invalid options', () => { after(done => { fs.remove('filename', done); }); it('should complain about a negative maxSize', () => { (() => { new RollingFileWriteStream('filename', { maxSize: -3 }) }).should.throw('options.maxSize (-3) should be > 0'); (() => { new RollingFileWriteStream('filename', { maxSize: 0 }) }).should.throw('options.maxSize (0) should be > 0'); }); it('should complain about a negative numToKeep', () => { (() => { new RollingFileWriteStream('filename', { numToKeep: -3 }) }).should.throw('options.numToKeep (-3) should be > 0'); (() => { new RollingFileWriteStream('filename', { numToKeep: 0 }) }).should.throw('options.numToKeep (0) should be > 0'); }); }); describe('with default arguments', () => { const fileObj = generateTestFile(); let s; before(() => { s = new RollingFileWriteStream(fileObj.path); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should take a filename and options, return Writable', () => { s.should.be.an.instanceOf(stream.Writable); s.currentFileStream.path.should.eql(fileObj.path); s.currentFileStream.mode.should.eql(420); s.currentFileStream.flags.should.eql('a'); }); it('should apply default options', () => { s.options.maxSize.should.eql(Number.MAX_SAFE_INTEGER); s.options.encoding.should.eql('utf8'); s.options.mode.should.eql(420); s.options.flags.should.eql('a'); s.options.compress.should.eql(false); s.options.keepFileExt.should.eql(false); }); }); describe('with 5 maxSize, rotating daily', () => { const fileObj = generateTestFile('noExtension'); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { pattern: 'yyyy-MM-dd', maxSize: 5 }); const flows = Array.from(Array(38).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { fs.removeSync(fileObj.dir); done(); }); it('should rotate using filename with no extension', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, //353637 fileObj.base + '.2012-09-12.1', // 01234 fileObj.base + '.2012-09-13.1', // 56789 fileObj.base + '.2012-09-14.2', // 101112 fileObj.base + '.2012-09-14.1', // 1314 fileObj.base + '.2012-09-15.2', // 151617 fileObj.base + '.2012-09-15.1', // 1819 fileObj.base + '.2012-09-16.2', // 202122 fileObj.base + '.2012-09-16.1', // 2324 fileObj.base + '.2012-09-17.2', // 252627 fileObj.base + '.2012-09-17.1', // 2829 fileObj.base + '.2012-09-18.2', // 303132 fileObj.base + '.2012-09-18.1' // 3334 ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('353637'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-12.1', }))).toString().should.equal('01234'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-13.1', }))).toString().should.equal('56789'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.2', }))).toString().should.equal('101112'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.1', }))).toString().should.equal('1314'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.2', }))).toString().should.equal('151617'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.1', }))).toString().should.equal('1819'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-16.2', }))).toString().should.equal('202122'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-16.1', }))).toString().should.equal('2324'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-17.2', }))).toString().should.equal('252627'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-17.1', }))).toString().should.equal('2829'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-18.2', }))).toString().should.equal('303132'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-18.1', }))).toString().should.equal('3334'); }); }); describe('with default arguments and recreated in the same day', () => { const fileObj = generateTestFile(); let s; before(done => { const flows = Array.from(Array(3).keys()).map(() => cb => { s = new RollingFileWriteStream(fileObj.path); s.write('abc', 'utf8', cb); s.end(); }) async.waterfall(flows, () => done()); }); after(() => { fs.removeSync(fileObj.dir); }); it('should have only 1 file', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base, }))).toString().should.equal('abcabcabc'); }); }); describe('with 5 maxSize, using filename with extension', () => { const fileObj = generateTestFile("withExtension.log"); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { pattern: 'yyyy-MM-dd', maxSize: 5 }); const flows = Array.from(Array(38).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 10, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { fs.removeSync(fileObj.dir); done(); }); it('should rotate files within the day, and when the day changes', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, //3637 fileObj.base + '.2012-09-12.2', //01234 fileObj.base + '.2012-09-12.1', //56789 fileObj.base + '.2012-09-13.4', //101112 fileObj.base + '.2012-09-13.3', //131415 fileObj.base + '.2012-09-13.2', //161718 fileObj.base + '.2012-09-13.1', //19 fileObj.base + '.2012-09-14.4', //202122 fileObj.base + '.2012-09-14.3', //232425 fileObj.base + '.2012-09-14.2', //262728 fileObj.base + '.2012-09-14.1', //29 fileObj.base + '.2012-09-15.2', //303132 fileObj.base + '.2012-09-15.1', //333435 ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('3637'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-12.2', }))).toString().should.equal('01234'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-12.1', }))).toString().should.equal('56789'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-13.4', }))).toString().should.equal('101112'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-13.3', }))).toString().should.equal('131415'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-13.2', }))).toString().should.equal('161718'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-13.1', }))).toString().should.equal('19'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.4', }))).toString().should.equal('202122'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.3', }))).toString().should.equal('232425'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.2', }))).toString().should.equal('262728'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.1', }))).toString().should.equal('29'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.2', }))).toString().should.equal('303132'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.1', }))).toString().should.equal('333435'); }); }); describe('with 5 maxSize and 3 files limit', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, numToKeep: 3 }); const flows = Array.from(Array(38).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should rotate with at most 3 backup files not including the hot one', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, fileObj.base + '.1', fileObj.base + '.2', fileObj.base + '.3' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('37'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.1' }))).toString().should.equal('343536'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2' }))).toString().should.equal('313233'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.3' }))).toString().should.equal('282930'); }); }); describe('with 5 maxSize and 3 files limit, rotating daily', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, pattern: 'yyyy-MM-dd', numToKeep: 3 }); const flows = Array.from(Array(38).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should rotate with at most 3 backup files not including the hot one', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, //3637 fileObj.base + '.2012-09-14.1', //29 fileObj.base + '.2012-09-15.2', //303132 fileObj.base + '.2012-09-15.1', //333435 ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('3637'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.1', }))).toString().should.equal('333435'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-15.2', }))).toString().should.equal('303132'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-14.1', }))).toString().should.equal('29'); }); }); describe('with date pattern dd-MM-yyyy', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, pattern: 'dd-MM-yyyy' }); const flows = Array.from(Array(8).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after((done) => { s.end(() => { fs.remove(fileObj.dir, done); }); }); it('should rotate with date pattern dd-MM-yyyy in the file name', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, fileObj.base + '.12-09-2012.1' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('567'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.12-09-2012.1' }))).toString().should.equal('01234'); }); }); describe('with compress true', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, pattern: 'yyyy-MM-dd', compress: true }); const flows = Array.from(Array(8).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should rotate with gunzip', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, fileObj.base + '.2012-09-12.1.gz' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('567'); const content = fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.base + '.2012-09-12.1.gz' }))); zlib.gunzipSync(content).toString().should.equal('01234'); }); }); describe('with keepFileExt', () => { const fileObj = generateTestFile('keepFileExt.log'); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { pattern: 'yyyy-MM-dd', maxSize: 5, keepFileExt: true }); const flows = Array.from(Array(8).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { s.end(); fs.removeSync(fileObj.dir); done(); }); it('should rotate with the same extension', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, fileObj.name + '.2012-09-12.1.log' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('567'); fs.readFileSync(path.format({ dir: fileObj.dir, base: fileObj.name + '.2012-09-12.1' + fileObj.ext })).toString().should.equal('01234'); }); }); describe('with keepFileExt and compress', () => { const fileObj = generateTestFile('keepFileExt.log'); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, pattern: 'yyyy-MM-dd', keepFileExt: true, compress: true }); const flows = Array.from(Array(8).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { s.end(); fs.removeSync(fileObj.dir); done(); }); it('should rotate with the same extension', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.base, fileObj.name + '.2012-09-12.1.log.gz' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('567'); const content = fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-12.1.log.gz' }))); zlib.gunzipSync(content).toString().should.equal('01234'); }); }); describe('with alwaysIncludePattern and keepFileExt', () => { const fileObj = generateTestFile('keepFileExt.log'); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, pattern: 'yyyy-MM-dd', keepFileExt: true, alwaysIncludePattern: true }); const flows = Array.from(Array(8).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { s.end(); fs.removeSync(fileObj.dir); done(); }); it('should rotate with the same extension and keep date in the filename', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.name + '.2012-09-12.1.log', fileObj.name + '.2012-09-13.log' ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-13.log' }))).toString().should.equal('567'); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-12.1.log' }))).toString().should.equal('01234'); }); }); describe('with 5 maxSize, compress, keepFileExt and alwaysIncludePattern', () => { const fileObj = generateTestFile('keepFileExt.log'); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path, { maxSize: 5, compress: true, keepFileExt: true, alwaysIncludePattern: true, pattern: 'yyyy-MM-dd' }); const flows = Array.from(Array(38).keys()).map(i => cb => { fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11); s.write(i.toString(), 'utf8', cb); }); async.waterfall(flows, () => done()); }); after(done => { s.end(); fs.removeSync(fileObj.dir); done(); }); it('should rotate every day', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [ fileObj.name + '.2012-09-12.1.log.gz', //01234 fileObj.name + '.2012-09-13.1.log.gz', //56789 fileObj.name + '.2012-09-14.2.log.gz', //101112 fileObj.name + '.2012-09-14.1.log.gz', //1314 fileObj.name + '.2012-09-15.2.log.gz', //151617 fileObj.name + '.2012-09-15.1.log.gz', //1819 fileObj.name + '.2012-09-16.2.log.gz', //202122 fileObj.name + '.2012-09-16.1.log.gz', //2324 fileObj.name + '.2012-09-17.2.log.gz', //252627 fileObj.name + '.2012-09-17.1.log.gz', //2829 fileObj.name + '.2012-09-18.2.log.gz', //303132 fileObj.name + '.2012-09-18.1.log.gz', //3334 fileObj.name + '.2012-09-19.log' //353637 ]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-19.log', }))).toString().should.equal('353637'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-18.1.log.gz', })))).toString().should.equal('3334'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-18.2.log.gz', })))).toString().should.equal('303132'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-17.1.log.gz', })))).toString().should.equal('2829'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-17.2.log.gz', })))).toString().should.equal('252627'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-16.1.log.gz', })))).toString().should.equal('2324'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-16.2.log.gz', })))).toString().should.equal('202122'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-15.1.log.gz', })))).toString().should.equal('1819'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-15.2.log.gz', })))).toString().should.equal('151617'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-14.1.log.gz', })))).toString().should.equal('1314'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-14.2.log.gz', })))).toString().should.equal('101112'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-13.1.log.gz', })))).toString().should.equal('56789'); zlib.gunzipSync(fs.readFileSync(path.format(_.assign({}, fileObj, { base: fileObj.name + '.2012-09-12.1.log.gz', })))).toString().should.equal('01234'); }); }); describe('when old files exist', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); fs.ensureFileSync(fileObj.path); fs.writeFileSync(fileObj.path, 'exist'); s = new RollingFileWriteStream(fileObj.path); s.write('now', 'utf8', done); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should use write in the old file if not reach the maxSize limit', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('existnow'); }); }); describe('when old files exist with contents', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); fs.ensureFileSync(fileObj.path); fs.writeFileSync(fileObj.path, 'This is exactly 30 bytes long\n'); s = new RollingFileWriteStream(fileObj.path, { maxSize: 35 }); s.write('one\n', 'utf8'); //34 s.write('two\n', 'utf8'); //38 - file should be rotated next time s.write('three\n', 'utf8', done); // this should be in a new file. }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should respect the existing file size', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base, fileObj.base + '.1']; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('three\n'); fs.readFileSync(path.join(fileObj.dir, fileObj.base + '.1')).toString().should.equal('This is exactly 30 bytes long\none\ntwo\n'); }); }); describe('when old files exist with contents and rolling by date', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); fs.ensureFileSync(fileObj.path); fs.writeFileSync(fileObj.path, 'This was created Sept 12, 2012.\n'); fakeNow = new Date(2012, 8, 13, 10, 53, 12); s = new RollingFileWriteStream(fileObj.path, { pattern: 'yyyy-MM-dd' }); s.write('It is now Sept 13, 2012.\n', 'utf8', done); // this should be in a new file. }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should respect the existing file date', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base, fileObj.base + '.2012-09-12']; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('It is now Sept 13, 2012.\n'); fs.readFileSync(path.join(fileObj.dir, fileObj.base + '.2012-09-12')).toString().should.equal('This was created Sept 12, 2012.\n'); }); }); describe('when old files exist with contents and stream created with overwrite flag', () => { const fileObj = generateTestFile(); let s; before(done => { fakeNow = new Date(2012, 8, 12, 10, 37, 11); fs.ensureFileSync(fileObj.path); fs.writeFileSync(fileObj.path, 'This is exactly 30 bytes long\n'); s = new RollingFileWriteStream(fileObj.path, { maxSize: 35, flags: 'w' }); s.write('there should only be this\n', 'utf8', done); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should ignore the existing file size', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); s.state.currentSize.should.equal(26); fs.readFileSync(path.format(fileObj)).toString().should.equal('there should only be this\n'); }); }); describe('when dir does not exist', () => { const fileObj = generateTestFile(); let s; before(done => { fs.removeSync(fileObj.dir); fakeNow = new Date(2012, 8, 12, 10, 37, 11); s = new RollingFileWriteStream(fileObj.path); s.write('test', 'utf8', done); }); after(() => { s.end(); fs.removeSync(fileObj.dir); }); it('should create the dir', () => { const files = fs.readdirSync(fileObj.dir); const expectedFileList = [fileObj.base]; files.length.should.equal(expectedFileList.length); files.should.containDeep(expectedFileList); fs.readFileSync(path.format(fileObj)).toString().should.equal('test'); }); }); describe('when given just a base filename with no dir', () => { let s; before(done => { s = new RollingFileWriteStream('test.log'); s.write('this should not cause any problems', 'utf8', done); }); after(() => { s.end(); fs.removeSync('test.log'); }); it('should use process.cwd() as the dir', () => { const files = fs.readdirSync(process.cwd()); files.should.containDeep(['test.log']); fs.readFileSync( path.join(process.cwd(), 'test.log') ).toString().should.equal('this should not cause any problems'); }); }); describe('with no callback to write', () => { let s; before(done => { s = new RollingFileWriteStream('no-callback.log'); s.write('this is all very nice', 'utf8', done); }); after(done => { fs.remove('no-callback.log', done); }); it('should not complain', done => { s.write('I am not bothered if this succeeds or not'); s.end(done); }); }); describe('events', () => { let s; before(done => { s = new RollingFileWriteStream('test-events.log'); s.write('this should not cause any problems', 'utf8', done); }); after(() => { s.end(); fs.removeSync('test-events.log'); }); it('should emit the error event of the underlying stream', (done) => { s.on('error', (e) => { e.message.should.equal('oh no'); done(); }); s.currentFileStream.emit('error', new Error('oh no')); }); }); });