RollingFileStream-test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. "use strict";
  2. var async = require('async')
  3. , should = require('should')
  4. , fs = require('fs')
  5. , path = require('path')
  6. , zlib = require('zlib')
  7. , streams = require('readable-stream')
  8. , RollingFileStream = require('../lib').RollingFileStream;
  9. function remove(filename, cb) {
  10. fs.unlink(filename, function(err) { cb(); });
  11. }
  12. function create(filename, cb) {
  13. fs.writeFile(filename, "test file", cb);
  14. }
  15. describe('RollingFileStream', function() {
  16. describe('arguments', function() {
  17. var stream;
  18. before(function(done) {
  19. remove(__dirname + "/test-rolling-file-stream", function() {
  20. stream = new RollingFileStream(__dirname + "/test-rolling-file-stream", 1024, 5);
  21. done();
  22. });
  23. });
  24. after(function(done) {
  25. remove(__dirname + "/test-rolling-file-stream", done);
  26. });
  27. it('should take a filename, file size (bytes), no. backups, return Writable', function() {
  28. stream.should.be.an.instanceOf(streams.Writable);
  29. stream.filename.should.eql(__dirname + "/test-rolling-file-stream");
  30. stream.size.should.eql(1024);
  31. stream.backups.should.eql(5);
  32. });
  33. it('should apply default settings to the underlying stream', function() {
  34. stream.theStream.mode.should.eql(420);
  35. stream.theStream.flags.should.eql('a');
  36. //encoding isn't a property on the underlying stream
  37. //assert.equal(stream.theStream.encoding, 'utf8');
  38. });
  39. });
  40. describe('with stream arguments', function() {
  41. it('should pass them to the underlying stream', function() {
  42. var stream = new RollingFileStream(
  43. __dirname + '/test-rolling-file-stream',
  44. 1024,
  45. 5,
  46. { mode: parseInt('0666', 8) }
  47. );
  48. stream.theStream.mode.should.eql(parseInt('0666', 8));
  49. });
  50. after(function(done) {
  51. remove(__dirname + '/test-rolling-file-stream', done);
  52. });
  53. });
  54. describe('without size', function() {
  55. it('should default to max int size', function() {
  56. var stream = new RollingFileStream(__dirname + "/test-rolling-file-stream");
  57. stream.size.should.eql(Number.MAX_SAFE_INTEGER);
  58. });
  59. after(function(done) {
  60. remove(__dirname + "/test-rolling-file-stream", done);
  61. });
  62. });
  63. describe('without number of backups', function() {
  64. it('should default to 1 backup', function() {
  65. var stream = new RollingFileStream(__dirname + "/test-rolling-file-stream", 1024);
  66. stream.backups.should.eql(1);
  67. });
  68. after(function(done) {
  69. remove(__dirname + "/test-rolling-file-stream", done);
  70. });
  71. });
  72. describe('writing less than the file size', function() {
  73. before(function(done) {
  74. remove(__dirname + "/test-rolling-file-stream-write-less", function() {
  75. var stream = new RollingFileStream(
  76. __dirname + "/test-rolling-file-stream-write-less",
  77. 100
  78. );
  79. stream.write("cheese", "utf8", function() {
  80. stream.end(done);
  81. });
  82. });
  83. });
  84. after(function(done) {
  85. remove(__dirname + "/test-rolling-file-stream-write-less", done);
  86. });
  87. it('should write to the file', function(done) {
  88. fs.readFile(
  89. __dirname + "/test-rolling-file-stream-write-less", "utf8",
  90. function(err, contents) {
  91. contents.should.eql("cheese");
  92. done(err);
  93. }
  94. );
  95. });
  96. it('should write one file', function(done) {
  97. fs.readdir(__dirname, function(err, files) {
  98. files.filter(
  99. function(file) { return file.indexOf('test-rolling-file-stream-write-less') > -1; }
  100. ).should.have.length(1);
  101. done(err);
  102. });
  103. });
  104. });
  105. describe('writing more than the file size', function() {
  106. before(function(done) {
  107. async.forEach(
  108. [
  109. __dirname + "/test-rolling-file-stream-write-more",
  110. __dirname + "/test-rolling-file-stream-write-more.1"
  111. ],
  112. remove,
  113. function() {
  114. var stream = new RollingFileStream(
  115. __dirname + "/test-rolling-file-stream-write-more",
  116. 45
  117. );
  118. async.forEachSeries(
  119. [0, 1, 2, 3, 4, 5, 6],
  120. function(i, cb) {
  121. stream.write(i +".cheese\n", "utf8", cb);
  122. },
  123. function() {
  124. stream.end(done);
  125. }
  126. );
  127. }
  128. );
  129. });
  130. after(function(done) {
  131. async.forEach(
  132. [
  133. __dirname + "/test-rolling-file-stream-write-more",
  134. __dirname + "/test-rolling-file-stream-write-more.1"
  135. ],
  136. remove,
  137. done
  138. );
  139. });
  140. it('should write two files' , function(done) {
  141. fs.readdir(__dirname, function(err, files) {
  142. files.filter(
  143. function(file) {
  144. return file.indexOf('test-rolling-file-stream-write-more') > -1;
  145. }
  146. ).should.have.length(2);
  147. done(err);
  148. });
  149. });
  150. it('should write the last two log messages to the first file', function(done) {
  151. fs.readFile(
  152. __dirname + "/test-rolling-file-stream-write-more", "utf8",
  153. function(err, contents) {
  154. contents.should.eql('5.cheese\n6.cheese\n');
  155. done(err);
  156. });
  157. });
  158. it('should write the first five log messages to the second file', function(done) {
  159. fs.readFile(
  160. __dirname + '/test-rolling-file-stream-write-more.1', "utf8",
  161. function(err, contents) {
  162. contents.should.eql('0.cheese\n1.cheese\n2.cheese\n3.cheese\n4.cheese\n');
  163. done(err);
  164. }
  165. );
  166. });
  167. });
  168. describe('with options.compress = true', function() {
  169. before(function(done) {
  170. var stream = new RollingFileStream(
  171. path.join(__dirname, 'compressed-backups.log'),
  172. 30, //30 bytes max size
  173. 2, //two backup files to keep
  174. { compress: true }
  175. );
  176. async.forEachSeries(
  177. [
  178. "This is the first log message.",
  179. "This is the second log message.",
  180. "This is the third log message.",
  181. "This is the fourth log message."
  182. ],
  183. function(i, cb) {
  184. stream.write(i + "\n", "utf8", cb);
  185. },
  186. function() {
  187. stream.end(done);
  188. }
  189. );
  190. });
  191. it('should produce three files, with the backups compressed', function(done) {
  192. fs.readdir(__dirname, function(err, files) {
  193. var testFiles = files.filter(
  194. function(f) { return f.indexOf('compressed-backups.log') > -1; }
  195. ).sort();
  196. testFiles.length.should.eql(3);
  197. testFiles.should.eql([
  198. 'compressed-backups.log',
  199. 'compressed-backups.log.1.gz',
  200. 'compressed-backups.log.2.gz',
  201. ]);
  202. fs.readFile(path.join(__dirname, testFiles[0]), 'utf8', function(err, contents) {
  203. contents.should.eql('This is the fourth log message.\n');
  204. zlib.gunzip(fs.readFileSync(path.join(__dirname, testFiles[1])),
  205. function(err, contents) {
  206. contents.toString('utf8').should.eql('This is the third log message.\n');
  207. zlib.gunzip(fs.readFileSync(path.join(__dirname, testFiles[2])),
  208. function(err, contents) {
  209. contents.toString('utf8').should.eql('This is the second log message.\n');
  210. done(err);
  211. }
  212. );
  213. }
  214. );
  215. });
  216. });
  217. });
  218. after(function(done) {
  219. async.forEach([
  220. path.join(__dirname, 'compressed-backups.log'),
  221. path.join(__dirname, 'compressed-backups.log.1.gz'),
  222. path.join(__dirname, 'compressed-backups.log.2.gz'),
  223. ], remove, done);
  224. });
  225. });
  226. describe('with options.keepFileExt = true', function() {
  227. before(function(done) {
  228. var stream = new RollingFileStream(
  229. path.join(__dirname, 'extKept-backups.log'),
  230. 30, //30 bytes max size
  231. 2, //two backup files to keep
  232. { keepFileExt: true }
  233. );
  234. async.forEachSeries(
  235. [
  236. "This is the first log message.",
  237. "This is the second log message.",
  238. "This is the third log message.",
  239. "This is the fourth log message."
  240. ],
  241. function(i, cb) {
  242. stream.write(i + "\n", "utf8", cb);
  243. },
  244. function() {
  245. stream.end(done);
  246. }
  247. );
  248. });
  249. it('should produce three files, with the file-extension kept', function(done) {
  250. fs.readdir(__dirname, function(err, files) {
  251. var testFiles = files.filter(
  252. function(f) { return f.indexOf('extKept-backups') > -1; }
  253. ).sort();
  254. testFiles.length.should.eql(3);
  255. testFiles.should.eql([
  256. 'extKept-backups.1.log',
  257. 'extKept-backups.2.log',
  258. 'extKept-backups.log',
  259. ]);
  260. fs.readFile(path.join(__dirname, testFiles[0]), 'utf8', function(err, contents) {
  261. contents.should.eql('This is the third log message.\n');
  262. fs.readFile(path.join(__dirname, testFiles[1]), 'utf8',
  263. function(err, contents) {
  264. contents.toString('utf8').should.eql('This is the second log message.\n');
  265. fs.readFile(path.join(__dirname, testFiles[2]), 'utf8',
  266. function(err, contents) {
  267. contents.toString('utf8').should.eql('This is the fourth log message.\n');
  268. done(err);
  269. }
  270. );
  271. }
  272. );
  273. });
  274. });
  275. });
  276. after(function(done) {
  277. async.forEach([
  278. path.join(__dirname, 'extKept-backups.log'),
  279. path.join(__dirname, 'extKept-backups.1.log'),
  280. path.join(__dirname, 'extKept-backups.2.log'),
  281. ], remove, done);
  282. });
  283. });
  284. describe('with options.compress = true and keepFileExt = true', function() {
  285. before(function(done) {
  286. var stream = new RollingFileStream(
  287. path.join(__dirname, 'compressed-backups.log'),
  288. 30, //30 bytes max size
  289. 2, //two backup files to keep
  290. { compress: true, keepFileExt: true }
  291. );
  292. async.forEachSeries(
  293. [
  294. "This is the first log message.",
  295. "This is the second log message.",
  296. "This is the third log message.",
  297. "This is the fourth log message."
  298. ],
  299. function(i, cb) {
  300. stream.write(i + "\n", "utf8", cb);
  301. },
  302. function() {
  303. stream.end(done);
  304. }
  305. );
  306. });
  307. it('should produce three files, with the backups compressed', function(done) {
  308. fs.readdir(__dirname, function(err, files) {
  309. var testFiles = files.filter(
  310. function(f) { return f.indexOf('compressed-backups') > -1; }
  311. ).sort();
  312. testFiles.length.should.eql(3);
  313. testFiles.should.eql([
  314. 'compressed-backups.1.log.gz',
  315. 'compressed-backups.2.log.gz',
  316. 'compressed-backups.log',
  317. ]);
  318. fs.readFile(path.join(__dirname, testFiles[2]), 'utf8', function(err, contents) {
  319. contents.should.eql('This is the fourth log message.\n');
  320. zlib.gunzip(fs.readFileSync(path.join(__dirname, testFiles[1])),
  321. function(err, contents) {
  322. contents.toString('utf8').should.eql('This is the second log message.\n');
  323. zlib.gunzip(fs.readFileSync(path.join(__dirname, testFiles[0])),
  324. function(err, contents) {
  325. contents.toString('utf8').should.eql('This is the third log message.\n');
  326. done(err);
  327. }
  328. );
  329. }
  330. );
  331. });
  332. });
  333. });
  334. after(function(done) {
  335. async.forEach([
  336. path.join(__dirname, 'compressed-backups.log'),
  337. path.join(__dirname, 'compressed-backups.1.log.gz'),
  338. path.join(__dirname, 'compressed-backups.2.log.gz'),
  339. ], remove, done);
  340. });
  341. });
  342. describe('when many files already exist', function() {
  343. before(function(done) {
  344. async.forEach(
  345. [
  346. __dirname + '/test-rolling-stream-with-existing-files.11',
  347. __dirname + '/test-rolling-stream-with-existing-files.20',
  348. __dirname + '/test-rolling-stream-with-existing-files.-1',
  349. __dirname + '/test-rolling-stream-with-existing-files.1.1',
  350. __dirname + '/test-rolling-stream-with-existing-files.1'
  351. ],
  352. remove,
  353. function(err) {
  354. if (err) done(err);
  355. async.forEach(
  356. [
  357. __dirname + '/test-rolling-stream-with-existing-files.11',
  358. __dirname + '/test-rolling-stream-with-existing-files.20',
  359. __dirname + '/test-rolling-stream-with-existing-files.-1',
  360. __dirname + '/test-rolling-stream-with-existing-files.1.1',
  361. __dirname + '/test-rolling-stream-with-existing-files.1'
  362. ],
  363. create,
  364. function(err) {
  365. if (err) done(err);
  366. var stream = new RollingFileStream(
  367. __dirname + "/test-rolling-stream-with-existing-files",
  368. 45,
  369. 5
  370. );
  371. async.forEachSeries(
  372. [0, 1, 2, 3, 4, 5, 6],
  373. function(i, cb) {
  374. stream.write(i +".cheese\n", "utf8", cb);
  375. },
  376. function() {
  377. stream.end(done);
  378. }
  379. );
  380. }
  381. );
  382. }
  383. );
  384. });
  385. after(function(done) {
  386. async.forEach([
  387. __dirname + '/test-rolling-stream-with-existing-files',
  388. __dirname + '/test-rolling-stream-with-existing-files.0',
  389. __dirname + '/test-rolling-stream-with-existing-files.1',
  390. __dirname + '/test-rolling-stream-with-existing-files.2',
  391. __dirname + '/test-rolling-stream-with-existing-files.3',
  392. __dirname + '/test-rolling-stream-with-existing-files.4',
  393. __dirname + '/test-rolling-stream-with-existing-files.5',
  394. __dirname + '/test-rolling-stream-with-existing-files.11',
  395. __dirname + '/test-rolling-stream-with-existing-files.20'
  396. ], remove, done);
  397. });
  398. it('should roll the files', function(done) {
  399. fs.readdir(__dirname, function(err, files) {
  400. files.should.containEql('test-rolling-stream-with-existing-files');
  401. files.should.containEql('test-rolling-stream-with-existing-files.1');
  402. files.should.containEql('test-rolling-stream-with-existing-files.2');
  403. files.should.containEql('test-rolling-stream-with-existing-files.11');
  404. files.should.containEql('test-rolling-stream-with-existing-files.20');
  405. done(err);
  406. });
  407. });
  408. });
  409. describe('when the directory gets deleted', function() {
  410. var stream;
  411. before(function(done) {
  412. stream = new RollingFileStream(path.join('subdir', 'test-rolling-file-stream'), 5, 5);
  413. stream.write('initial', 'utf8', done);
  414. });
  415. after(function() {
  416. fs.unlinkSync(path.join('subdir', 'test-rolling-file-stream'));
  417. fs.rmdirSync('subdir');
  418. });
  419. it('handles directory deletion gracefully', function(done) {
  420. stream.theStream.on('error', done);
  421. remove(path.join('subdir', 'test-rolling-file-stream'), function() {
  422. fs.rmdir('subdir', function() {
  423. stream.write('rollover', 'utf8', function() {
  424. fs.readFileSync(path.join('subdir', 'test-rolling-file-stream'), 'utf8')
  425. .should.eql('rollover');
  426. done();
  427. });
  428. });
  429. });
  430. });
  431. });
  432. });