blob: dec6aaf05c620967c6b076b3c69388b1355d2954 [file] [log] [blame]
"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();
});
});
});
});
});
});