DateRollingFileStream-test.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. require("should");
  2. const fs = require("fs-extra"),
  3. path = require("path"),
  4. zlib = require("zlib"),
  5. proxyquire = require("proxyquire").noPreserveCache(),
  6. util = require("util"),
  7. streams = require("stream");
  8. let fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  9. const mockNow = () => fakeNow;
  10. const RollingFileWriteStream = proxyquire("../lib/RollingFileWriteStream", {
  11. "./now": mockNow
  12. });
  13. const DateRollingFileStream = proxyquire("../lib/DateRollingFileStream", {
  14. "./RollingFileWriteStream": RollingFileWriteStream
  15. });
  16. const gunzip = util.promisify(zlib.gunzip);
  17. const gzip = util.promisify(zlib.gzip);
  18. const remove = filename => fs.unlink(filename).catch(() => {});
  19. const close = async (stream) => new Promise(
  20. (resolve, reject) => stream.end(e => e ? reject(e) : resolve())
  21. );
  22. describe("DateRollingFileStream", function() {
  23. describe("arguments", function() {
  24. let stream;
  25. before(function() {
  26. stream = new DateRollingFileStream(
  27. path.join(__dirname, "test-date-rolling-file-stream-1"),
  28. "yyyy-MM-dd.hh"
  29. );
  30. });
  31. after(async function() {
  32. await close(stream);
  33. await remove(path.join(__dirname, "test-date-rolling-file-stream-1"));
  34. });
  35. it("should take a filename and a pattern and return a WritableStream", function() {
  36. stream.filename.should.eql(
  37. path.join(__dirname, "test-date-rolling-file-stream-1")
  38. );
  39. stream.options.pattern.should.eql("yyyy-MM-dd.hh");
  40. stream.should.be.instanceOf(streams.Writable);
  41. });
  42. it("with default settings for the underlying stream", function() {
  43. stream.currentFileStream.mode.should.eql(420);
  44. stream.currentFileStream.flags.should.eql("a");
  45. });
  46. });
  47. describe("default arguments", function() {
  48. var stream;
  49. before(function() {
  50. stream = new DateRollingFileStream(
  51. path.join(__dirname, "test-date-rolling-file-stream-2")
  52. );
  53. });
  54. after(async function() {
  55. await close(stream);
  56. await remove(path.join(__dirname, "test-date-rolling-file-stream-2"));
  57. });
  58. it("should have pattern of .yyyy-MM-dd", function() {
  59. stream.options.pattern.should.eql("yyyy-MM-dd");
  60. });
  61. });
  62. describe("with stream arguments", function() {
  63. var stream;
  64. before(function() {
  65. stream = new DateRollingFileStream(
  66. path.join(__dirname, "test-date-rolling-file-stream-3"),
  67. "yyyy-MM-dd",
  68. { mode: parseInt("0666", 8) }
  69. );
  70. });
  71. after(async function() {
  72. await close(stream);
  73. await remove(path.join(__dirname, "test-date-rolling-file-stream-3"));
  74. });
  75. it("should pass them to the underlying stream", function() {
  76. stream.theStream.mode.should.eql(parseInt("0666", 8));
  77. });
  78. });
  79. describe("with stream arguments but no pattern", function() {
  80. var stream;
  81. before(function() {
  82. stream = new DateRollingFileStream(
  83. path.join(__dirname, "test-date-rolling-file-stream-4"),
  84. { mode: parseInt("0666", 8) }
  85. );
  86. });
  87. after(async function() {
  88. await close(stream);
  89. await remove(path.join(__dirname, "test-date-rolling-file-stream-4"));
  90. });
  91. it("should pass them to the underlying stream", function() {
  92. stream.theStream.mode.should.eql(parseInt("0666", 8));
  93. });
  94. it("should use default pattern", function() {
  95. stream.options.pattern.should.eql("yyyy-MM-dd");
  96. });
  97. });
  98. describe("with a pattern of .yyyy-MM-dd", function() {
  99. var stream;
  100. before(function(done) {
  101. stream = new DateRollingFileStream(
  102. path.join(__dirname, "test-date-rolling-file-stream-5"),
  103. ".yyyy-MM-dd",
  104. null
  105. );
  106. stream.write("First message\n", "utf8", done);
  107. });
  108. after(async function() {
  109. await close(stream);
  110. await remove(path.join(__dirname, "test-date-rolling-file-stream-5"));
  111. });
  112. it("should create a file with the base name", async function() {
  113. const contents = await fs.readFile(
  114. path.join(__dirname, "test-date-rolling-file-stream-5"),
  115. "utf8"
  116. );
  117. contents.should.eql("First message\n");
  118. });
  119. describe("when the day changes", function() {
  120. before(function(done) {
  121. fakeNow = new Date(2012, 8, 13, 0, 10, 12);
  122. stream.write("Second message\n", "utf8", done);
  123. });
  124. after(async function() {
  125. await remove(
  126. path.join(__dirname, "test-date-rolling-file-stream-5.2012-09-12")
  127. );
  128. });
  129. describe("the number of files", function() {
  130. it("should be two", async function() {
  131. const files = await fs.readdir(__dirname);
  132. files
  133. .filter(
  134. file => file.indexOf("test-date-rolling-file-stream-5") > -1
  135. )
  136. .should.have.length(2);
  137. });
  138. });
  139. describe("the file without a date", function() {
  140. it("should contain the second message", async function() {
  141. const contents = await fs.readFile(
  142. path.join(__dirname, "test-date-rolling-file-stream-5"),
  143. "utf8"
  144. );
  145. contents.should.eql("Second message\n");
  146. });
  147. });
  148. describe("the file with the date", function() {
  149. it("should contain the first message", async function() {
  150. const contents = await fs.readFile(
  151. path.join(__dirname, "test-date-rolling-file-stream-5.2012-09-12"),
  152. "utf8"
  153. );
  154. contents.should.eql("First message\n");
  155. });
  156. });
  157. });
  158. });
  159. describe("with alwaysIncludePattern", function() {
  160. var stream;
  161. before(async function() {
  162. fakeNow = new Date(2012, 8, 12, 11, 10, 12);
  163. await remove(
  164. path.join(
  165. __dirname,
  166. "test-date-rolling-file-stream-pattern.2012-09-12-11.log"
  167. )
  168. );
  169. stream = new DateRollingFileStream(
  170. path.join(__dirname, "test-date-rolling-file-stream-pattern"),
  171. ".yyyy-MM-dd-hh.log",
  172. { alwaysIncludePattern: true }
  173. );
  174. await new Promise(resolve => {
  175. setTimeout(function() {
  176. stream.write("First message\n", "utf8", () => resolve());
  177. }, 50);
  178. });
  179. });
  180. after(async function() {
  181. await close(stream);
  182. await remove(
  183. path.join(
  184. __dirname,
  185. "test-date-rolling-file-stream-pattern.2012-09-12-11.log"
  186. )
  187. );
  188. });
  189. it("should create a file with the pattern set", async function() {
  190. const contents = await fs.readFile(
  191. path.join(
  192. __dirname,
  193. "test-date-rolling-file-stream-pattern.2012-09-12-11.log"
  194. ),
  195. "utf8"
  196. );
  197. contents.should.eql("First message\n");
  198. });
  199. describe("when the day changes", function() {
  200. before(function(done) {
  201. fakeNow = new Date(2012, 8, 12, 12, 10, 12);
  202. stream.write("Second message\n", "utf8", done);
  203. });
  204. after(async function() {
  205. await remove(
  206. path.join(
  207. __dirname,
  208. "test-date-rolling-file-stream-pattern.2012-09-12-12.log"
  209. )
  210. );
  211. });
  212. describe("the number of files", function() {
  213. it("should be two", async function() {
  214. const files = await fs.readdir(__dirname);
  215. files
  216. .filter(
  217. file => file.indexOf("test-date-rolling-file-stream-pattern") > -1
  218. )
  219. .should.have.length(2);
  220. });
  221. });
  222. describe("the file with the later date", function() {
  223. it("should contain the second message", async function() {
  224. const contents = await fs.readFile(
  225. path.join(
  226. __dirname,
  227. "test-date-rolling-file-stream-pattern.2012-09-12-12.log"
  228. ),
  229. "utf8"
  230. );
  231. contents.should.eql("Second message\n");
  232. });
  233. });
  234. describe("the file with the date", function() {
  235. it("should contain the first message", async function() {
  236. const contents = await fs.readFile(
  237. path.join(
  238. __dirname,
  239. "test-date-rolling-file-stream-pattern.2012-09-12-11.log"
  240. ),
  241. "utf8"
  242. );
  243. contents.should.eql("First message\n");
  244. });
  245. });
  246. });
  247. });
  248. describe("with a pattern that evaluates to digits", function() {
  249. let stream;
  250. before(done => {
  251. fakeNow = new Date(2012, 8, 12, 0, 10, 12);
  252. stream = new DateRollingFileStream(
  253. path.join(__dirname, "digits.log"),
  254. ".yyyyMMdd"
  255. );
  256. stream.write("First message\n", "utf8", done);
  257. });
  258. describe("when the day changes", function() {
  259. before(function(done) {
  260. fakeNow = new Date(2012, 8, 13, 0, 10, 12);
  261. stream.write("Second message\n", "utf8", done);
  262. });
  263. it("should be two files (it should not get confused by indexes)", async function() {
  264. const files = await fs.readdir(__dirname);
  265. var logFiles = files.filter(file => file.indexOf("digits.log") > -1);
  266. logFiles.should.have.length(2);
  267. const contents = await fs.readFile(
  268. path.join(__dirname, "digits.log.20120912"),
  269. "utf8"
  270. );
  271. contents.should.eql("First message\n");
  272. const c = await fs.readFile(path.join(__dirname, "digits.log"), "utf8");
  273. c.should.eql("Second message\n");
  274. });
  275. });
  276. after(async function() {
  277. await close(stream);
  278. await remove(path.join(__dirname, "digits.log"));
  279. await remove(path.join(__dirname, "digits.log.20120912"));
  280. });
  281. });
  282. describe("with compress option", function() {
  283. var stream;
  284. before(function(done) {
  285. fakeNow = new Date(2012, 8, 12, 0, 10, 12);
  286. stream = new DateRollingFileStream(
  287. path.join(__dirname, "compressed.log"),
  288. ".yyyy-MM-dd",
  289. { compress: true }
  290. );
  291. stream.write("First message\n", "utf8", done);
  292. });
  293. describe("when the day changes", function() {
  294. before(function(done) {
  295. fakeNow = new Date(2012, 8, 13, 0, 10, 12);
  296. stream.write("Second message\n", "utf8", done);
  297. });
  298. it("should be two files, one compressed", async function() {
  299. const files = await fs.readdir(__dirname);
  300. var logFiles = files.filter(
  301. file => file.indexOf("compressed.log") > -1
  302. );
  303. logFiles.should.have.length(2);
  304. const gzipped = await fs.readFile(
  305. path.join(__dirname, "compressed.log.2012-09-12.gz")
  306. );
  307. const contents = await gunzip(gzipped);
  308. contents.toString("utf8").should.eql("First message\n");
  309. (await fs.readFile(
  310. path.join(__dirname, "compressed.log"),
  311. "utf8"
  312. )).should.eql("Second message\n");
  313. });
  314. });
  315. after(async function() {
  316. await close(stream);
  317. await remove(path.join(__dirname, "compressed.log"));
  318. await remove(path.join(__dirname, "compressed.log.2012-09-12.gz"));
  319. });
  320. });
  321. describe("with keepFileExt option", function() {
  322. var stream;
  323. before(function(done) {
  324. fakeNow = new Date(2012, 8, 12, 0, 10, 12);
  325. stream = new DateRollingFileStream(
  326. path.join(__dirname, "keepFileExt.log"),
  327. ".yyyy-MM-dd",
  328. { keepFileExt: true }
  329. );
  330. stream.write("First message\n", "utf8", done);
  331. });
  332. describe("when the day changes", function() {
  333. before(function(done) {
  334. fakeNow = new Date(2012, 8, 13, 0, 10, 12);
  335. stream.write("Second message\n", "utf8", done);
  336. });
  337. it("should be two files", async function() {
  338. const files = await fs.readdir(__dirname);
  339. var logFiles = files.filter(file => file.indexOf("keepFileExt") > -1);
  340. logFiles.should.have.length(2);
  341. (await fs.readFile(
  342. path.join(__dirname, "keepFileExt.2012-09-12.log"),
  343. "utf8"
  344. )).should.eql("First message\n");
  345. (await fs.readFile(
  346. path.join(__dirname, "keepFileExt.log"),
  347. "utf8"
  348. )).should.eql("Second message\n");
  349. });
  350. });
  351. after(async function() {
  352. await close(stream);
  353. await remove(path.join(__dirname, "keepFileExt.log"));
  354. await remove(path.join(__dirname, "keepFileExt.2012-09-12.log"));
  355. });
  356. });
  357. describe("with compress option and keepFileExt option", function() {
  358. var stream;
  359. before(function(done) {
  360. fakeNow = new Date(2012, 8, 12, 0, 10, 12);
  361. stream = new DateRollingFileStream(
  362. path.join(__dirname, "compressedAndKeepExt.log"),
  363. ".yyyy-MM-dd",
  364. { compress: true, keepFileExt: true }
  365. );
  366. stream.write("First message\n", "utf8", done);
  367. });
  368. describe("when the day changes", function() {
  369. before(function(done) {
  370. fakeNow = new Date(2012, 8, 13, 0, 10, 12);
  371. stream.write("Second message\n", "utf8", done);
  372. });
  373. it("should be two files, one compressed", async function() {
  374. const files = await fs.readdir(__dirname);
  375. var logFiles = files.filter(
  376. file => file.indexOf("compressedAndKeepExt") > -1
  377. );
  378. logFiles.should.have.length(2);
  379. const gzipped = await fs.readFile(
  380. path.join(__dirname, "compressedAndKeepExt.2012-09-12.log.gz")
  381. );
  382. const contents = await gunzip(gzipped);
  383. contents.toString("utf8").should.eql("First message\n");
  384. (await fs.readFile(
  385. path.join(__dirname, "compressedAndKeepExt.log"),
  386. "utf8"
  387. )).should.eql("Second message\n");
  388. });
  389. });
  390. after(async function() {
  391. await close(stream);
  392. await remove(path.join(__dirname, "compressedAndKeepExt.log"));
  393. await remove(
  394. path.join(__dirname, "compressedAndKeepExt.2012-09-12.log.gz")
  395. );
  396. });
  397. });
  398. describe("with daysToKeep option", function() {
  399. let stream;
  400. var daysToKeep = 4;
  401. var numOriginalLogs = 10;
  402. before(async function() {
  403. for (let i = 0; i < numOriginalLogs; i += 1) {
  404. await fs.writeFile(
  405. path.join(__dirname, `daysToKeep.log.2012-09-${20-i}`),
  406. `Message on day ${i}\n`,
  407. { encoding: "utf-8" }
  408. );
  409. }
  410. stream = new DateRollingFileStream(
  411. path.join(__dirname, "daysToKeep.log"),
  412. ".yyyy-MM-dd",
  413. {
  414. alwaysIncludePattern: true,
  415. daysToKeep: daysToKeep
  416. }
  417. );
  418. });
  419. describe("when the day changes", function() {
  420. before(function(done) {
  421. fakeNow = new Date(2012, 8, 21, 0, 10, 12);
  422. stream.write("Second message\n", "utf8", done);
  423. });
  424. it("should be daysToKeep + 1 files left from numOriginalLogs", async function() {
  425. const files = await fs.readdir(__dirname);
  426. var logFiles = files.filter(
  427. file => file.indexOf("daysToKeep.log") > -1
  428. );
  429. logFiles.should.have.length(daysToKeep + 1);
  430. });
  431. });
  432. after(async function() {
  433. await close(stream);
  434. const files = await fs.readdir(__dirname);
  435. const logFiles = files
  436. .filter(file => file.indexOf("daysToKeep.log") > -1)
  437. .map(f => remove(path.join(__dirname, f)));
  438. await Promise.all(logFiles);
  439. });
  440. });
  441. describe("with daysToKeep and compress options", function() {
  442. let stream;
  443. const daysToKeep = 4;
  444. const numOriginalLogs = 10;
  445. before(async function() {
  446. for (let i = numOriginalLogs; i >= 0; i -= 1) {
  447. fakeNow = new Date(2012, 8, 20 - i, 0, 10, 12);
  448. const contents = await gzip(`Message on day ${i}\n`);
  449. await fs.writeFile(
  450. path.join(__dirname, `compressedDaysToKeep.log.2012-09-${20-i}.gz`),
  451. contents
  452. );
  453. }
  454. stream = new DateRollingFileStream(
  455. path.join(__dirname, "compressedDaysToKeep.log"),
  456. ".yyyy-MM-dd",
  457. {
  458. alwaysIncludePattern: true,
  459. compress: true,
  460. daysToKeep: daysToKeep
  461. }
  462. );
  463. });
  464. describe("when the day changes", function() {
  465. before(function(done) {
  466. fakeNow = new Date(2012, 8, 21, 0, 10, 12);
  467. stream.write("New file message\n", "utf8", done);
  468. });
  469. it("should be 4 files left from original 3", async function() {
  470. const files = await fs.readdir(__dirname);
  471. var logFiles = files.filter(
  472. file => file.indexOf("compressedDaysToKeep.log") > -1
  473. );
  474. logFiles.should.have.length(daysToKeep + 1);
  475. });
  476. });
  477. after(async function() {
  478. await close(stream);
  479. const files = await fs.readdir(__dirname);
  480. const logFiles = files
  481. .filter(file => file.indexOf("compressedDaysToKeep.log") > -1)
  482. .map(f => remove(path.join(__dirname, f)));
  483. await Promise.all(logFiles);
  484. });
  485. });
  486. });