| "use strict"; |
| |
| require("should"); |
| |
| var async = require("async"), |
| fs = require("fs"), |
| path = require("path"), |
| zlib = require("zlib"), |
| streams = require("stream"), |
| RollingFileStream = require("../lib").RollingFileStream; |
| |
| function remove(filename, cb) { |
| fs.unlink(filename, function() { |
| cb(); |
| }); |
| } |
| |
| function create(filename, cb) { |
| fs.writeFile(filename, "test file", cb); |
| } |
| |
| describe("RollingFileStream", function() { |
| describe("arguments", function() { |
| var stream; |
| |
| before(function(done) { |
| remove(__dirname + "/test-rolling-file-stream", function() { |
| stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream", |
| 1024, |
| 5 |
| ); |
| done(); |
| }); |
| }); |
| |
| after(function(done) { |
| remove(__dirname + "/test-rolling-file-stream", done); |
| }); |
| |
| it("should take a filename, file size (bytes), no. backups, return Writable", function() { |
| stream.should.be.an.instanceOf(streams.Writable); |
| stream.filename.should.eql(__dirname + "/test-rolling-file-stream"); |
| stream.size.should.eql(1024); |
| stream.backups.should.eql(5); |
| }); |
| |
| it("should apply default settings to the underlying stream", function() { |
| stream.theStream.mode.should.eql(420); |
| stream.theStream.flags.should.eql("a"); |
| }); |
| }); |
| |
| describe("with stream arguments", function() { |
| it("should pass them to the underlying stream", function() { |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream", |
| 1024, |
| 5, |
| { mode: parseInt("0666", 8) } |
| ); |
| stream.theStream.mode.should.eql(parseInt("0666", 8)); |
| }); |
| |
| after(function(done) { |
| remove(__dirname + "/test-rolling-file-stream", done); |
| }); |
| }); |
| |
| describe("without size", function() { |
| it("should default to max int size", function() { |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream" |
| ); |
| stream.size.should.eql(Number.MAX_SAFE_INTEGER); |
| }); |
| |
| after(function(done) { |
| remove(__dirname + "/test-rolling-file-stream", done); |
| }); |
| }); |
| |
| describe("without number of backups", function() { |
| it("should default to 1 backup", function() { |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream", |
| 1024 |
| ); |
| stream.backups.should.eql(1); |
| }); |
| |
| after(function(done) { |
| remove(__dirname + "/test-rolling-file-stream", done); |
| }); |
| }); |
| |
| describe("writing less than the file size", function() { |
| before(function(done) { |
| remove(__dirname + "/test-rolling-file-stream-write-less", function() { |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream-write-less", |
| 100 |
| ); |
| stream.write("cheese", "utf8", function() { |
| stream.end(done); |
| }); |
| }); |
| }); |
| |
| after(function(done) { |
| remove(__dirname + "/test-rolling-file-stream-write-less", done); |
| }); |
| |
| it("should write to the file", function(done) { |
| fs.readFile( |
| __dirname + "/test-rolling-file-stream-write-less", |
| "utf8", |
| function(err, contents) { |
| contents.should.eql("cheese"); |
| done(err); |
| } |
| ); |
| }); |
| |
| it("should write one file", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| files |
| .filter(function(file) { |
| return file.indexOf("test-rolling-file-stream-write-less") > -1; |
| }) |
| .should.have.length(1); |
| done(err); |
| }); |
| }); |
| }); |
| |
| describe("writing more than the file size", function() { |
| before(function(done) { |
| async.forEach( |
| [ |
| __dirname + "/test-rolling-file-stream-write-more", |
| __dirname + "/test-rolling-file-stream-write-more.1" |
| ], |
| remove, |
| function() { |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-file-stream-write-more", |
| 45 |
| ); |
| async.forEachSeries( |
| [0, 1, 2, 3, 4, 5, 6], |
| function(i, cb) { |
| stream.write(i + ".cheese\n", "utf8", cb); |
| }, |
| function() { |
| stream.end(done); |
| } |
| ); |
| } |
| ); |
| }); |
| |
| after(function(done) { |
| async.forEach( |
| [ |
| __dirname + "/test-rolling-file-stream-write-more", |
| __dirname + "/test-rolling-file-stream-write-more.1" |
| ], |
| remove, |
| done |
| ); |
| }); |
| |
| it("should write two files", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| files |
| .filter(function(file) { |
| return file.indexOf("test-rolling-file-stream-write-more") > -1; |
| }) |
| .should.have.length(2); |
| done(err); |
| }); |
| }); |
| |
| it("should write the last two log messages to the first file", function(done) { |
| fs.readFile( |
| __dirname + "/test-rolling-file-stream-write-more", |
| "utf8", |
| function(err, contents) { |
| contents.should.eql("5.cheese\n6.cheese\n"); |
| done(err); |
| } |
| ); |
| }); |
| |
| it("should write the first five log messages to the second file", function(done) { |
| fs.readFile( |
| __dirname + "/test-rolling-file-stream-write-more.1", |
| "utf8", |
| function(err, contents) { |
| contents.should.eql( |
| "0.cheese\n1.cheese\n2.cheese\n3.cheese\n4.cheese\n" |
| ); |
| done(err); |
| } |
| ); |
| }); |
| }); |
| |
| describe("with options.compress = true", function() { |
| before(function(done) { |
| var stream = new RollingFileStream( |
| path.join(__dirname, "compressed-backups.log"), |
| 30, //30 bytes max size |
| 2, //two backup files to keep |
| { compress: true } |
| ); |
| async.forEachSeries( |
| [ |
| "This is the first log message.", |
| "This is the second log message.", |
| "This is the third log message.", |
| "This is the fourth log message." |
| ], |
| function(i, cb) { |
| stream.write(i + "\n", "utf8", cb); |
| }, |
| function() { |
| stream.end(done); |
| } |
| ); |
| }); |
| |
| it("should produce three files, with the backups compressed", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| var testFiles = files |
| .filter(function(f) { |
| return f.indexOf("compressed-backups.log") > -1; |
| }) |
| .sort(); |
| |
| testFiles.length.should.eql(3); |
| testFiles.should.eql([ |
| "compressed-backups.log", |
| "compressed-backups.log.1.gz", |
| "compressed-backups.log.2.gz" |
| ]); |
| |
| fs.readFile(path.join(__dirname, testFiles[0]), "utf8", function( |
| err, |
| contents |
| ) { |
| contents.should.eql("This is the fourth log message.\n"); |
| |
| zlib.gunzip( |
| fs.readFileSync(path.join(__dirname, testFiles[1])), |
| function(err, contents) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the third log message.\n"); |
| zlib.gunzip( |
| fs.readFileSync(path.join(__dirname, testFiles[2])), |
| function(err, contents) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the second log message.\n"); |
| done(err); |
| } |
| ); |
| } |
| ); |
| }); |
| }); |
| }); |
| |
| after(function(done) { |
| async.forEach( |
| [ |
| path.join(__dirname, "compressed-backups.log"), |
| path.join(__dirname, "compressed-backups.log.1.gz"), |
| path.join(__dirname, "compressed-backups.log.2.gz") |
| ], |
| remove, |
| done |
| ); |
| }); |
| }); |
| |
| describe("with options.keepFileExt = true", function() { |
| before(function(done) { |
| var stream = new RollingFileStream( |
| path.join(__dirname, "extKept-backups.log"), |
| 30, //30 bytes max size |
| 2, //two backup files to keep |
| { keepFileExt: true } |
| ); |
| async.forEachSeries( |
| [ |
| "This is the first log message.", |
| "This is the second log message.", |
| "This is the third log message.", |
| "This is the fourth log message." |
| ], |
| function(i, cb) { |
| stream.write(i + "\n", "utf8", cb); |
| }, |
| function() { |
| stream.end(done); |
| } |
| ); |
| }); |
| |
| it("should produce three files, with the file-extension kept", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| var testFiles = files |
| .filter(function(f) { |
| return f.indexOf("extKept-backups") > -1; |
| }) |
| .sort(); |
| |
| testFiles.length.should.eql(3); |
| testFiles.should.eql([ |
| "extKept-backups.1.log", |
| "extKept-backups.2.log", |
| "extKept-backups.log" |
| ]); |
| |
| fs.readFile(path.join(__dirname, testFiles[0]), "utf8", function( |
| err, |
| contents |
| ) { |
| contents.should.eql("This is the third log message.\n"); |
| |
| fs.readFile(path.join(__dirname, testFiles[1]), "utf8", function( |
| err, |
| contents |
| ) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the second log message.\n"); |
| fs.readFile(path.join(__dirname, testFiles[2]), "utf8", function( |
| err, |
| contents |
| ) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the fourth log message.\n"); |
| done(err); |
| }); |
| }); |
| }); |
| }); |
| }); |
| |
| after(function(done) { |
| async.forEach( |
| [ |
| path.join(__dirname, "extKept-backups.log"), |
| path.join(__dirname, "extKept-backups.1.log"), |
| path.join(__dirname, "extKept-backups.2.log") |
| ], |
| remove, |
| done |
| ); |
| }); |
| }); |
| |
| describe("with options.compress = true and keepFileExt = true", function() { |
| before(function(done) { |
| var stream = new RollingFileStream( |
| path.join(__dirname, "compressed-backups.log"), |
| 30, //30 bytes max size |
| 2, //two backup files to keep |
| { compress: true, keepFileExt: true } |
| ); |
| async.forEachSeries( |
| [ |
| "This is the first log message.", |
| "This is the second log message.", |
| "This is the third log message.", |
| "This is the fourth log message." |
| ], |
| function(i, cb) { |
| stream.write(i + "\n", "utf8", cb); |
| }, |
| function() { |
| stream.end(done); |
| } |
| ); |
| }); |
| |
| it("should produce three files, with the backups compressed", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| var testFiles = files |
| .filter(function(f) { |
| return f.indexOf("compressed-backups") > -1; |
| }) |
| .sort(); |
| |
| testFiles.length.should.eql(3); |
| testFiles.should.eql([ |
| "compressed-backups.1.log.gz", |
| "compressed-backups.2.log.gz", |
| "compressed-backups.log" |
| ]); |
| |
| fs.readFile(path.join(__dirname, testFiles[2]), "utf8", function( |
| err, |
| contents |
| ) { |
| contents.should.eql("This is the fourth log message.\n"); |
| |
| zlib.gunzip( |
| fs.readFileSync(path.join(__dirname, testFiles[1])), |
| function(err, contents) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the second log message.\n"); |
| zlib.gunzip( |
| fs.readFileSync(path.join(__dirname, testFiles[0])), |
| function(err, contents) { |
| contents |
| .toString("utf8") |
| .should.eql("This is the third log message.\n"); |
| done(err); |
| } |
| ); |
| } |
| ); |
| }); |
| }); |
| }); |
| |
| after(function(done) { |
| async.forEach( |
| [ |
| path.join(__dirname, "compressed-backups.log"), |
| path.join(__dirname, "compressed-backups.1.log.gz"), |
| path.join(__dirname, "compressed-backups.2.log.gz") |
| ], |
| remove, |
| done |
| ); |
| }); |
| }); |
| |
| describe("when many files already exist", function() { |
| before(function(done) { |
| async.forEach( |
| [ |
| __dirname + "/test-rolling-stream-with-existing-files.11", |
| __dirname + "/test-rolling-stream-with-existing-files.20", |
| __dirname + "/test-rolling-stream-with-existing-files.-1", |
| __dirname + "/test-rolling-stream-with-existing-files.1.1", |
| __dirname + "/test-rolling-stream-with-existing-files.1" |
| ], |
| remove, |
| function(err) { |
| if (err) done(err); |
| |
| async.forEach( |
| [ |
| __dirname + "/test-rolling-stream-with-existing-files.11", |
| __dirname + "/test-rolling-stream-with-existing-files.20", |
| __dirname + "/test-rolling-stream-with-existing-files.-1", |
| __dirname + "/test-rolling-stream-with-existing-files.1.1", |
| __dirname + "/test-rolling-stream-with-existing-files.1" |
| ], |
| create, |
| function(err) { |
| if (err) done(err); |
| |
| var stream = new RollingFileStream( |
| __dirname + "/test-rolling-stream-with-existing-files", |
| 18, |
| 5 |
| ); |
| |
| async.forEachSeries( |
| [0, 1, 2, 3, 4, 5, 6], |
| function(i, cb) { |
| stream.write(i + ".cheese\n", "utf8", cb); |
| }, |
| function() { |
| stream.end(done); |
| } |
| ); |
| } |
| ); |
| } |
| ); |
| }); |
| |
| after(function(done) { |
| async.forEach( |
| [ |
| __dirname + "/test-rolling-stream-with-existing-files.-1", |
| __dirname + "/test-rolling-stream-with-existing-files", |
| __dirname + "/test-rolling-stream-with-existing-files.1.1", |
| __dirname + "/test-rolling-stream-with-existing-files.0", |
| __dirname + "/test-rolling-stream-with-existing-files.1", |
| __dirname + "/test-rolling-stream-with-existing-files.2", |
| __dirname + "/test-rolling-stream-with-existing-files.3", |
| __dirname + "/test-rolling-stream-with-existing-files.4", |
| __dirname + "/test-rolling-stream-with-existing-files.5", |
| __dirname + "/test-rolling-stream-with-existing-files.6", |
| __dirname + "/test-rolling-stream-with-existing-files.11", |
| __dirname + "/test-rolling-stream-with-existing-files.20" |
| ], |
| remove, |
| done |
| ); |
| }); |
| |
| it("should roll the files, removing the highest indices", function(done) { |
| fs.readdir(__dirname, function(err, files) { |
| files.should.containEql("test-rolling-stream-with-existing-files"); |
| files.should.containEql("test-rolling-stream-with-existing-files.1"); |
| files.should.containEql("test-rolling-stream-with-existing-files.2"); |
| files.should.containEql("test-rolling-stream-with-existing-files.3"); |
| files.should.containEql("test-rolling-stream-with-existing-files.4"); |
| done(err); |
| }); |
| }); |
| }); |
| |
| describe("when the directory gets deleted", function() { |
| var stream; |
| before(function(done) { |
| stream = new RollingFileStream( |
| path.join("subdir", "test-rolling-file-stream"), |
| 5, |
| 5 |
| ); |
| stream.write("initial", "utf8", done); |
| }); |
| |
| after(function() { |
| fs.unlinkSync(path.join("subdir", "test-rolling-file-stream")); |
| fs.rmdirSync("subdir"); |
| }); |
| |
| it("handles directory deletion gracefully", function(done) { |
| stream.theStream.on("error", done); |
| |
| remove(path.join("subdir", "test-rolling-file-stream"), function() { |
| fs.rmdir("subdir", function() { |
| stream.write("rollover", "utf8", function() { |
| fs.readFileSync( |
| path.join("subdir", "test-rolling-file-stream"), |
| "utf8" |
| ).should.eql("rollover"); |
| done(); |
| }); |
| }); |
| }); |
| }); |
| }); |
| }); |