RollingFileWriteStream-test.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  1. require("should");
  2. const _ = require("lodash");
  3. const path = require("path");
  4. const zlib = require("zlib");
  5. const async = require("async");
  6. const stream = require("stream");
  7. const fs = require("fs-extra");
  8. const proxyquire = require("proxyquire").noPreserveCache();
  9. let fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  10. const mockNow = () => fakeNow;
  11. const RollingFileWriteStream = proxyquire("../lib/RollingFileWriteStream", {
  12. "./now": mockNow
  13. });
  14. let fakedFsDate = fakeNow;
  15. const mockFs = require("fs-extra");
  16. const oldStatSync = mockFs.statSync;
  17. mockFs.statSync = fd => {
  18. const result = oldStatSync(fd);
  19. result.birthtime = fakedFsDate;
  20. return result;
  21. };
  22. function generateTestFile(fileName) {
  23. const dirName = path.join(
  24. __dirname,
  25. "tmp_" + Math.floor(Math.random() * new Date())
  26. );
  27. fileName = fileName || "ignored.log";
  28. const fileNameObj = path.parse(fileName);
  29. return {
  30. dir: dirName,
  31. base: fileNameObj.base,
  32. name: fileNameObj.name,
  33. ext: fileNameObj.ext,
  34. path: path.join(dirName, fileName)
  35. };
  36. }
  37. function resetTime() {
  38. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  39. fakedFsDate = fakeNow;
  40. }
  41. describe("RollingFileWriteStream", () => {
  42. beforeEach(() => {
  43. resetTime();
  44. });
  45. after(() => {
  46. fs.readdirSync(__dirname)
  47. .filter(f => f.startsWith("tmp_"))
  48. .forEach(f => fs.removeSync(path.join(__dirname, f)));
  49. });
  50. describe("with no arguments", () => {
  51. it("should throw an error", () => {
  52. (() => new RollingFileWriteStream()).should.throw(
  53. /(the )?"?path"? (argument )?must be (a|of type) string\. received (type )?undefined/i
  54. );
  55. });
  56. });
  57. describe("with invalid options", () => {
  58. after(done => {
  59. fs.remove("filename", done);
  60. });
  61. it("should complain about a negative maxSize", () => {
  62. (() => {
  63. new RollingFileWriteStream("filename", { maxSize: -3 });
  64. }).should.throw("options.maxSize (-3) should be > 0");
  65. (() => {
  66. new RollingFileWriteStream("filename", { maxSize: 0 });
  67. }).should.throw("options.maxSize (0) should be > 0");
  68. });
  69. it("should complain about a negative numToKeep", () => {
  70. (() => {
  71. new RollingFileWriteStream("filename", { numToKeep: -3 });
  72. }).should.throw("options.numToKeep (-3) should be > 0");
  73. (() => {
  74. new RollingFileWriteStream("filename", { numToKeep: 0 });
  75. }).should.throw("options.numToKeep (0) should be > 0");
  76. });
  77. });
  78. describe("with default arguments", () => {
  79. const fileObj = generateTestFile();
  80. let s;
  81. before(() => {
  82. s = new RollingFileWriteStream(fileObj.path);
  83. });
  84. after(() => {
  85. s.end();
  86. fs.removeSync(fileObj.dir);
  87. });
  88. it("should take a filename and options, return Writable", () => {
  89. s.should.be.an.instanceOf(stream.Writable);
  90. s.currentFileStream.path.should.eql(fileObj.path);
  91. s.currentFileStream.mode.should.eql(420);
  92. s.currentFileStream.flags.should.eql("a");
  93. });
  94. it("should apply default options", () => {
  95. s.options.maxSize.should.eql(Number.MAX_SAFE_INTEGER);
  96. s.options.encoding.should.eql("utf8");
  97. s.options.mode.should.eql(420);
  98. s.options.flags.should.eql("a");
  99. s.options.compress.should.eql(false);
  100. s.options.keepFileExt.should.eql(false);
  101. });
  102. });
  103. describe("with 5 maxSize, rotating daily", () => {
  104. const fileObj = generateTestFile("noExtension");
  105. let s;
  106. before(done => {
  107. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  108. s = new RollingFileWriteStream(fileObj.path, {
  109. pattern: "yyyy-MM-dd",
  110. maxSize: 5
  111. });
  112. const flows = Array.from(Array(38).keys()).map(i => cb => {
  113. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  114. s.write(i.toString(), "utf8", cb);
  115. });
  116. async.waterfall(flows, () => done());
  117. });
  118. after(done => {
  119. fs.removeSync(fileObj.dir);
  120. done();
  121. });
  122. it("should rotate using filename with no extension", () => {
  123. const files = fs.readdirSync(fileObj.dir);
  124. const expectedFileList = [
  125. fileObj.base, //353637
  126. fileObj.base + ".2012-09-12.1", // 01234
  127. fileObj.base + ".2012-09-13.1", // 56789
  128. fileObj.base + ".2012-09-14.2", // 101112
  129. fileObj.base + ".2012-09-14.1", // 1314
  130. fileObj.base + ".2012-09-15.2", // 151617
  131. fileObj.base + ".2012-09-15.1", // 1819
  132. fileObj.base + ".2012-09-16.2", // 202122
  133. fileObj.base + ".2012-09-16.1", // 2324
  134. fileObj.base + ".2012-09-17.2", // 252627
  135. fileObj.base + ".2012-09-17.1", // 2829
  136. fileObj.base + ".2012-09-18.2", // 303132
  137. fileObj.base + ".2012-09-18.1" // 3334
  138. ];
  139. files.should.containDeep(expectedFileList);
  140. files.length.should.equal(expectedFileList.length);
  141. fs.readFileSync(path.format(fileObj))
  142. .toString()
  143. .should.equal("353637");
  144. fs.readFileSync(
  145. path.format(
  146. _.assign({}, fileObj, {
  147. base: fileObj.base + ".2012-09-12.1"
  148. })
  149. )
  150. )
  151. .toString()
  152. .should.equal("01234");
  153. fs.readFileSync(
  154. path.format(
  155. _.assign({}, fileObj, {
  156. base: fileObj.base + ".2012-09-13.1"
  157. })
  158. )
  159. )
  160. .toString()
  161. .should.equal("56789");
  162. fs.readFileSync(
  163. path.format(
  164. _.assign({}, fileObj, {
  165. base: fileObj.base + ".2012-09-14.2"
  166. })
  167. )
  168. )
  169. .toString()
  170. .should.equal("101112");
  171. fs.readFileSync(
  172. path.format(
  173. _.assign({}, fileObj, {
  174. base: fileObj.base + ".2012-09-14.1"
  175. })
  176. )
  177. )
  178. .toString()
  179. .should.equal("1314");
  180. fs.readFileSync(
  181. path.format(
  182. _.assign({}, fileObj, {
  183. base: fileObj.base + ".2012-09-15.2"
  184. })
  185. )
  186. )
  187. .toString()
  188. .should.equal("151617");
  189. fs.readFileSync(
  190. path.format(
  191. _.assign({}, fileObj, {
  192. base: fileObj.base + ".2012-09-15.1"
  193. })
  194. )
  195. )
  196. .toString()
  197. .should.equal("1819");
  198. fs.readFileSync(
  199. path.format(
  200. _.assign({}, fileObj, {
  201. base: fileObj.base + ".2012-09-16.2"
  202. })
  203. )
  204. )
  205. .toString()
  206. .should.equal("202122");
  207. fs.readFileSync(
  208. path.format(
  209. _.assign({}, fileObj, {
  210. base: fileObj.base + ".2012-09-16.1"
  211. })
  212. )
  213. )
  214. .toString()
  215. .should.equal("2324");
  216. fs.readFileSync(
  217. path.format(
  218. _.assign({}, fileObj, {
  219. base: fileObj.base + ".2012-09-17.2"
  220. })
  221. )
  222. )
  223. .toString()
  224. .should.equal("252627");
  225. fs.readFileSync(
  226. path.format(
  227. _.assign({}, fileObj, {
  228. base: fileObj.base + ".2012-09-17.1"
  229. })
  230. )
  231. )
  232. .toString()
  233. .should.equal("2829");
  234. fs.readFileSync(
  235. path.format(
  236. _.assign({}, fileObj, {
  237. base: fileObj.base + ".2012-09-18.2"
  238. })
  239. )
  240. )
  241. .toString()
  242. .should.equal("303132");
  243. fs.readFileSync(
  244. path.format(
  245. _.assign({}, fileObj, {
  246. base: fileObj.base + ".2012-09-18.1"
  247. })
  248. )
  249. )
  250. .toString()
  251. .should.equal("3334");
  252. });
  253. });
  254. describe("with default arguments and recreated in the same day", () => {
  255. const fileObj = generateTestFile();
  256. let s;
  257. before(done => {
  258. const flows = Array.from(Array(3).keys()).map(() => cb => {
  259. s = new RollingFileWriteStream(fileObj.path);
  260. s.write("abc", "utf8", cb);
  261. s.end();
  262. });
  263. async.waterfall(flows, () => done());
  264. });
  265. after(() => {
  266. fs.removeSync(fileObj.dir);
  267. });
  268. it("should have only 1 file", () => {
  269. const files = fs.readdirSync(fileObj.dir);
  270. const expectedFileList = [fileObj.base];
  271. files.should.containDeep(expectedFileList);
  272. files.length.should.equal(expectedFileList.length);
  273. fs.readFileSync(
  274. path.format(
  275. _.assign({}, fileObj, {
  276. base: fileObj.base
  277. })
  278. )
  279. )
  280. .toString()
  281. .should.equal("abcabcabc");
  282. });
  283. });
  284. describe("with 5 maxSize, using filename with extension", () => {
  285. const fileObj = generateTestFile("withExtension.log");
  286. let s;
  287. before(done => {
  288. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  289. s = new RollingFileWriteStream(fileObj.path, {
  290. pattern: "yyyy-MM-dd",
  291. maxSize: 5
  292. });
  293. const flows = Array.from(Array(38).keys()).map(i => cb => {
  294. fakeNow = new Date(2012, 8, 12 + parseInt(i / 10, 10), 10, 37, 11);
  295. s.write(i.toString(), "utf8", cb);
  296. });
  297. async.waterfall(flows, () => done());
  298. });
  299. after(done => {
  300. fs.removeSync(fileObj.dir);
  301. done();
  302. });
  303. it("should rotate files within the day, and when the day changes", () => {
  304. const files = fs.readdirSync(fileObj.dir);
  305. const expectedFileList = [
  306. fileObj.base, //3637
  307. fileObj.base + ".2012-09-12.2", //01234
  308. fileObj.base + ".2012-09-12.1", //56789
  309. fileObj.base + ".2012-09-13.4", //101112
  310. fileObj.base + ".2012-09-13.3", //131415
  311. fileObj.base + ".2012-09-13.2", //161718
  312. fileObj.base + ".2012-09-13.1", //19
  313. fileObj.base + ".2012-09-14.4", //202122
  314. fileObj.base + ".2012-09-14.3", //232425
  315. fileObj.base + ".2012-09-14.2", //262728
  316. fileObj.base + ".2012-09-14.1", //29
  317. fileObj.base + ".2012-09-15.2", //303132
  318. fileObj.base + ".2012-09-15.1" //333435
  319. ];
  320. files.should.containDeep(expectedFileList);
  321. files.length.should.equal(expectedFileList.length);
  322. fs.readFileSync(path.format(fileObj))
  323. .toString()
  324. .should.equal("3637");
  325. fs.readFileSync(
  326. path.format(
  327. _.assign({}, fileObj, {
  328. base: fileObj.base + ".2012-09-12.2"
  329. })
  330. )
  331. )
  332. .toString()
  333. .should.equal("01234");
  334. fs.readFileSync(
  335. path.format(
  336. _.assign({}, fileObj, {
  337. base: fileObj.base + ".2012-09-12.1"
  338. })
  339. )
  340. )
  341. .toString()
  342. .should.equal("56789");
  343. fs.readFileSync(
  344. path.format(
  345. _.assign({}, fileObj, {
  346. base: fileObj.base + ".2012-09-13.4"
  347. })
  348. )
  349. )
  350. .toString()
  351. .should.equal("101112");
  352. fs.readFileSync(
  353. path.format(
  354. _.assign({}, fileObj, {
  355. base: fileObj.base + ".2012-09-13.3"
  356. })
  357. )
  358. )
  359. .toString()
  360. .should.equal("131415");
  361. fs.readFileSync(
  362. path.format(
  363. _.assign({}, fileObj, {
  364. base: fileObj.base + ".2012-09-13.2"
  365. })
  366. )
  367. )
  368. .toString()
  369. .should.equal("161718");
  370. fs.readFileSync(
  371. path.format(
  372. _.assign({}, fileObj, {
  373. base: fileObj.base + ".2012-09-13.1"
  374. })
  375. )
  376. )
  377. .toString()
  378. .should.equal("19");
  379. fs.readFileSync(
  380. path.format(
  381. _.assign({}, fileObj, {
  382. base: fileObj.base + ".2012-09-14.4"
  383. })
  384. )
  385. )
  386. .toString()
  387. .should.equal("202122");
  388. fs.readFileSync(
  389. path.format(
  390. _.assign({}, fileObj, {
  391. base: fileObj.base + ".2012-09-14.3"
  392. })
  393. )
  394. )
  395. .toString()
  396. .should.equal("232425");
  397. fs.readFileSync(
  398. path.format(
  399. _.assign({}, fileObj, {
  400. base: fileObj.base + ".2012-09-14.2"
  401. })
  402. )
  403. )
  404. .toString()
  405. .should.equal("262728");
  406. fs.readFileSync(
  407. path.format(
  408. _.assign({}, fileObj, {
  409. base: fileObj.base + ".2012-09-14.1"
  410. })
  411. )
  412. )
  413. .toString()
  414. .should.equal("29");
  415. fs.readFileSync(
  416. path.format(
  417. _.assign({}, fileObj, {
  418. base: fileObj.base + ".2012-09-15.2"
  419. })
  420. )
  421. )
  422. .toString()
  423. .should.equal("303132");
  424. fs.readFileSync(
  425. path.format(
  426. _.assign({}, fileObj, {
  427. base: fileObj.base + ".2012-09-15.1"
  428. })
  429. )
  430. )
  431. .toString()
  432. .should.equal("333435");
  433. });
  434. });
  435. describe("with 5 maxSize and 3 files limit", () => {
  436. const fileObj = generateTestFile();
  437. let s;
  438. before(done => {
  439. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  440. s = new RollingFileWriteStream(fileObj.path, {
  441. maxSize: 5,
  442. numToKeep: 3
  443. });
  444. const flows = Array.from(Array(38).keys()).map(i => cb => {
  445. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5), 10, 37, 11);
  446. s.write(i.toString(), "utf8", cb);
  447. });
  448. async.waterfall(flows, () => done());
  449. });
  450. after(() => {
  451. s.end();
  452. fs.removeSync(fileObj.dir);
  453. });
  454. it("should rotate with at most 3 backup files not including the hot one", () => {
  455. const files = fs.readdirSync(fileObj.dir);
  456. const expectedFileList = [
  457. fileObj.base,
  458. fileObj.base + ".1",
  459. fileObj.base + ".2",
  460. fileObj.base + ".3"
  461. ];
  462. files.should.containDeep(expectedFileList);
  463. files.length.should.equal(expectedFileList.length);
  464. fs.readFileSync(path.format(fileObj))
  465. .toString()
  466. .should.equal("37");
  467. fs.readFileSync(
  468. path.format(
  469. _.assign({}, fileObj, {
  470. base: fileObj.base + ".1"
  471. })
  472. )
  473. )
  474. .toString()
  475. .should.equal("343536");
  476. fs.readFileSync(
  477. path.format(
  478. _.assign({}, fileObj, {
  479. base: fileObj.base + ".2"
  480. })
  481. )
  482. )
  483. .toString()
  484. .should.equal("313233");
  485. fs.readFileSync(
  486. path.format(
  487. _.assign({}, fileObj, {
  488. base: fileObj.base + ".3"
  489. })
  490. )
  491. )
  492. .toString()
  493. .should.equal("282930");
  494. });
  495. });
  496. describe("with 5 maxSize and 3 files limit, rotating daily", () => {
  497. const fileObj = generateTestFile();
  498. let s;
  499. before(done => {
  500. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  501. s = new RollingFileWriteStream(fileObj.path, {
  502. maxSize: 5,
  503. pattern: "yyyy-MM-dd",
  504. numToKeep: 3
  505. });
  506. const flows = Array.from(Array(38).keys()).map(i => cb => {
  507. fakeNow = new Date(2012, 8, 12 + parseInt(i / 10), 10, 37, 11);
  508. s.write(i.toString(), "utf8", cb);
  509. });
  510. async.waterfall(flows, () => done());
  511. });
  512. after(() => {
  513. s.end();
  514. fs.removeSync(fileObj.dir);
  515. });
  516. it("should rotate with at most 3 backup files not including the hot one", () => {
  517. const files = fs.readdirSync(fileObj.dir);
  518. const expectedFileList = [
  519. fileObj.base, //3637
  520. fileObj.base + ".2012-09-14.1", //29
  521. fileObj.base + ".2012-09-15.2", //303132
  522. fileObj.base + ".2012-09-15.1" //333435
  523. ];
  524. files.should.containDeep(expectedFileList);
  525. files.length.should.equal(expectedFileList.length);
  526. fs.readFileSync(path.format(fileObj))
  527. .toString()
  528. .should.equal("3637");
  529. fs.readFileSync(
  530. path.format(
  531. _.assign({}, fileObj, {
  532. base: fileObj.base + ".2012-09-15.1"
  533. })
  534. )
  535. )
  536. .toString()
  537. .should.equal("333435");
  538. fs.readFileSync(
  539. path.format(
  540. _.assign({}, fileObj, {
  541. base: fileObj.base + ".2012-09-15.2"
  542. })
  543. )
  544. )
  545. .toString()
  546. .should.equal("303132");
  547. fs.readFileSync(
  548. path.format(
  549. _.assign({}, fileObj, {
  550. base: fileObj.base + ".2012-09-14.1"
  551. })
  552. )
  553. )
  554. .toString()
  555. .should.equal("29");
  556. });
  557. });
  558. describe("with date pattern dd-MM-yyyy", () => {
  559. const fileObj = generateTestFile();
  560. let s;
  561. before(done => {
  562. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  563. s = new RollingFileWriteStream(fileObj.path, {
  564. maxSize: 5,
  565. pattern: "dd-MM-yyyy"
  566. });
  567. const flows = Array.from(Array(8).keys()).map(i => cb => {
  568. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  569. s.write(i.toString(), "utf8", cb);
  570. });
  571. async.waterfall(flows, () => done());
  572. });
  573. after(done => {
  574. s.end(() => {
  575. fs.remove(fileObj.dir, done);
  576. });
  577. });
  578. it("should rotate with date pattern dd-MM-yyyy in the file name", () => {
  579. const files = fs.readdirSync(fileObj.dir);
  580. const expectedFileList = [fileObj.base, fileObj.base + ".12-09-2012.1"];
  581. files.should.containDeep(expectedFileList);
  582. files.length.should.equal(expectedFileList.length);
  583. fs.readFileSync(path.format(fileObj))
  584. .toString()
  585. .should.equal("567");
  586. fs.readFileSync(
  587. path.format(
  588. _.assign({}, fileObj, {
  589. base: fileObj.base + ".12-09-2012.1"
  590. })
  591. )
  592. )
  593. .toString()
  594. .should.equal("01234");
  595. });
  596. });
  597. describe("with compress true", () => {
  598. const fileObj = generateTestFile();
  599. let s;
  600. before(done => {
  601. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  602. s = new RollingFileWriteStream(fileObj.path, {
  603. maxSize: 5,
  604. pattern: "yyyy-MM-dd",
  605. compress: true
  606. });
  607. const flows = Array.from(Array(8).keys()).map(i => cb => {
  608. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  609. s.write(i.toString(), "utf8", cb);
  610. });
  611. async.waterfall(flows, () => done());
  612. });
  613. after(() => {
  614. s.end();
  615. fs.removeSync(fileObj.dir);
  616. });
  617. it("should rotate with gunzip", () => {
  618. const files = fs.readdirSync(fileObj.dir);
  619. const expectedFileList = [
  620. fileObj.base,
  621. fileObj.base + ".2012-09-12.1.gz"
  622. ];
  623. files.should.containDeep(expectedFileList);
  624. files.length.should.equal(expectedFileList.length);
  625. fs.readFileSync(path.format(fileObj))
  626. .toString()
  627. .should.equal("567");
  628. const content = fs.readFileSync(
  629. path.format(
  630. _.assign({}, fileObj, {
  631. base: fileObj.base + ".2012-09-12.1.gz"
  632. })
  633. )
  634. );
  635. zlib
  636. .gunzipSync(content)
  637. .toString()
  638. .should.equal("01234");
  639. });
  640. });
  641. describe("with keepFileExt", () => {
  642. const fileObj = generateTestFile("keepFileExt.log");
  643. let s;
  644. before(done => {
  645. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  646. s = new RollingFileWriteStream(fileObj.path, {
  647. pattern: "yyyy-MM-dd",
  648. maxSize: 5,
  649. keepFileExt: true
  650. });
  651. const flows = Array.from(Array(8).keys()).map(i => cb => {
  652. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  653. s.write(i.toString(), "utf8", cb);
  654. });
  655. async.waterfall(flows, () => done());
  656. });
  657. after(done => {
  658. s.end();
  659. fs.removeSync(fileObj.dir);
  660. done();
  661. });
  662. it("should rotate with the same extension", () => {
  663. const files = fs.readdirSync(fileObj.dir);
  664. const expectedFileList = [
  665. fileObj.base,
  666. fileObj.name + ".2012-09-12.1.log"
  667. ];
  668. files.should.containDeep(expectedFileList);
  669. files.length.should.equal(expectedFileList.length);
  670. fs.readFileSync(path.format(fileObj))
  671. .toString()
  672. .should.equal("567");
  673. fs.readFileSync(
  674. path.format({
  675. dir: fileObj.dir,
  676. base: fileObj.name + ".2012-09-12.1" + fileObj.ext
  677. })
  678. )
  679. .toString()
  680. .should.equal("01234");
  681. });
  682. });
  683. describe("with keepFileExt and compress", () => {
  684. const fileObj = generateTestFile("keepFileExt.log");
  685. let s;
  686. before(done => {
  687. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  688. s = new RollingFileWriteStream(fileObj.path, {
  689. maxSize: 5,
  690. pattern: "yyyy-MM-dd",
  691. keepFileExt: true,
  692. compress: true
  693. });
  694. const flows = Array.from(Array(8).keys()).map(i => cb => {
  695. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  696. s.write(i.toString(), "utf8", cb);
  697. });
  698. async.waterfall(flows, () => done());
  699. });
  700. after(done => {
  701. s.end();
  702. fs.removeSync(fileObj.dir);
  703. done();
  704. });
  705. it("should rotate with the same extension", () => {
  706. const files = fs.readdirSync(fileObj.dir);
  707. const expectedFileList = [
  708. fileObj.base,
  709. fileObj.name + ".2012-09-12.1.log.gz"
  710. ];
  711. files.should.containDeep(expectedFileList);
  712. files.length.should.equal(expectedFileList.length);
  713. fs.readFileSync(path.format(fileObj))
  714. .toString()
  715. .should.equal("567");
  716. const content = fs.readFileSync(
  717. path.format(
  718. _.assign({}, fileObj, {
  719. base: fileObj.name + ".2012-09-12.1.log.gz"
  720. })
  721. )
  722. );
  723. zlib
  724. .gunzipSync(content)
  725. .toString()
  726. .should.equal("01234");
  727. });
  728. });
  729. describe("with alwaysIncludePattern and keepFileExt", () => {
  730. const fileObj = generateTestFile("keepFileExt.log");
  731. let s;
  732. before(done => {
  733. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  734. s = new RollingFileWriteStream(fileObj.path, {
  735. maxSize: 5,
  736. pattern: "yyyy-MM-dd",
  737. keepFileExt: true,
  738. alwaysIncludePattern: true
  739. });
  740. const flows = Array.from(Array(8).keys()).map(i => cb => {
  741. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  742. s.write(i.toString(), "utf8", cb);
  743. });
  744. async.waterfall(flows, () => done());
  745. });
  746. after(done => {
  747. s.end();
  748. fs.removeSync(fileObj.dir);
  749. done();
  750. });
  751. it("should rotate with the same extension and keep date in the filename", () => {
  752. const files = fs.readdirSync(fileObj.dir);
  753. const expectedFileList = [
  754. fileObj.name + ".2012-09-12.1.log",
  755. fileObj.name + ".2012-09-13.log"
  756. ];
  757. files.should.containDeep(expectedFileList);
  758. files.length.should.equal(expectedFileList.length);
  759. fs.readFileSync(
  760. path.format(
  761. _.assign({}, fileObj, {
  762. base: fileObj.name + ".2012-09-13.log"
  763. })
  764. )
  765. )
  766. .toString()
  767. .should.equal("567");
  768. fs.readFileSync(
  769. path.format(
  770. _.assign({}, fileObj, {
  771. base: fileObj.name + ".2012-09-12.1.log"
  772. })
  773. )
  774. )
  775. .toString()
  776. .should.equal("01234");
  777. });
  778. });
  779. describe("with 5 maxSize, compress, keepFileExt and alwaysIncludePattern", () => {
  780. const fileObj = generateTestFile("keepFileExt.log");
  781. let s;
  782. before(done => {
  783. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  784. s = new RollingFileWriteStream(fileObj.path, {
  785. maxSize: 5,
  786. compress: true,
  787. keepFileExt: true,
  788. alwaysIncludePattern: true,
  789. pattern: "yyyy-MM-dd"
  790. });
  791. const flows = Array.from(Array(38).keys()).map(i => cb => {
  792. fakeNow = new Date(2012, 8, 12 + parseInt(i / 5, 10), 10, 37, 11);
  793. s.write(i.toString(), "utf8", cb);
  794. });
  795. async.waterfall(flows, () => done());
  796. });
  797. after(done => {
  798. s.end();
  799. fs.removeSync(fileObj.dir);
  800. done();
  801. });
  802. it("should rotate every day", () => {
  803. const files = fs.readdirSync(fileObj.dir);
  804. const expectedFileList = [
  805. fileObj.name + ".2012-09-12.1.log.gz", //01234
  806. fileObj.name + ".2012-09-13.1.log.gz", //56789
  807. fileObj.name + ".2012-09-14.2.log.gz", //101112
  808. fileObj.name + ".2012-09-14.1.log.gz", //1314
  809. fileObj.name + ".2012-09-15.2.log.gz", //151617
  810. fileObj.name + ".2012-09-15.1.log.gz", //1819
  811. fileObj.name + ".2012-09-16.2.log.gz", //202122
  812. fileObj.name + ".2012-09-16.1.log.gz", //2324
  813. fileObj.name + ".2012-09-17.2.log.gz", //252627
  814. fileObj.name + ".2012-09-17.1.log.gz", //2829
  815. fileObj.name + ".2012-09-18.2.log.gz", //303132
  816. fileObj.name + ".2012-09-18.1.log.gz", //3334
  817. fileObj.name + ".2012-09-19.log" //353637
  818. ];
  819. files.should.containDeep(expectedFileList);
  820. files.length.should.equal(expectedFileList.length);
  821. fs.readFileSync(
  822. path.format(
  823. _.assign({}, fileObj, {
  824. base: fileObj.name + ".2012-09-19.log"
  825. })
  826. )
  827. )
  828. .toString()
  829. .should.equal("353637");
  830. zlib
  831. .gunzipSync(
  832. fs.readFileSync(
  833. path.format(
  834. _.assign({}, fileObj, {
  835. base: fileObj.name + ".2012-09-18.1.log.gz"
  836. })
  837. )
  838. )
  839. )
  840. .toString()
  841. .should.equal("3334");
  842. zlib
  843. .gunzipSync(
  844. fs.readFileSync(
  845. path.format(
  846. _.assign({}, fileObj, {
  847. base: fileObj.name + ".2012-09-18.2.log.gz"
  848. })
  849. )
  850. )
  851. )
  852. .toString()
  853. .should.equal("303132");
  854. zlib
  855. .gunzipSync(
  856. fs.readFileSync(
  857. path.format(
  858. _.assign({}, fileObj, {
  859. base: fileObj.name + ".2012-09-17.1.log.gz"
  860. })
  861. )
  862. )
  863. )
  864. .toString()
  865. .should.equal("2829");
  866. zlib
  867. .gunzipSync(
  868. fs.readFileSync(
  869. path.format(
  870. _.assign({}, fileObj, {
  871. base: fileObj.name + ".2012-09-17.2.log.gz"
  872. })
  873. )
  874. )
  875. )
  876. .toString()
  877. .should.equal("252627");
  878. zlib
  879. .gunzipSync(
  880. fs.readFileSync(
  881. path.format(
  882. _.assign({}, fileObj, {
  883. base: fileObj.name + ".2012-09-16.1.log.gz"
  884. })
  885. )
  886. )
  887. )
  888. .toString()
  889. .should.equal("2324");
  890. zlib
  891. .gunzipSync(
  892. fs.readFileSync(
  893. path.format(
  894. _.assign({}, fileObj, {
  895. base: fileObj.name + ".2012-09-16.2.log.gz"
  896. })
  897. )
  898. )
  899. )
  900. .toString()
  901. .should.equal("202122");
  902. zlib
  903. .gunzipSync(
  904. fs.readFileSync(
  905. path.format(
  906. _.assign({}, fileObj, {
  907. base: fileObj.name + ".2012-09-15.1.log.gz"
  908. })
  909. )
  910. )
  911. )
  912. .toString()
  913. .should.equal("1819");
  914. zlib
  915. .gunzipSync(
  916. fs.readFileSync(
  917. path.format(
  918. _.assign({}, fileObj, {
  919. base: fileObj.name + ".2012-09-15.2.log.gz"
  920. })
  921. )
  922. )
  923. )
  924. .toString()
  925. .should.equal("151617");
  926. zlib
  927. .gunzipSync(
  928. fs.readFileSync(
  929. path.format(
  930. _.assign({}, fileObj, {
  931. base: fileObj.name + ".2012-09-14.1.log.gz"
  932. })
  933. )
  934. )
  935. )
  936. .toString()
  937. .should.equal("1314");
  938. zlib
  939. .gunzipSync(
  940. fs.readFileSync(
  941. path.format(
  942. _.assign({}, fileObj, {
  943. base: fileObj.name + ".2012-09-14.2.log.gz"
  944. })
  945. )
  946. )
  947. )
  948. .toString()
  949. .should.equal("101112");
  950. zlib
  951. .gunzipSync(
  952. fs.readFileSync(
  953. path.format(
  954. _.assign({}, fileObj, {
  955. base: fileObj.name + ".2012-09-13.1.log.gz"
  956. })
  957. )
  958. )
  959. )
  960. .toString()
  961. .should.equal("56789");
  962. zlib
  963. .gunzipSync(
  964. fs.readFileSync(
  965. path.format(
  966. _.assign({}, fileObj, {
  967. base: fileObj.name + ".2012-09-12.1.log.gz"
  968. })
  969. )
  970. )
  971. )
  972. .toString()
  973. .should.equal("01234");
  974. });
  975. });
  976. describe("when old files exist", () => {
  977. const fileObj = generateTestFile();
  978. let s;
  979. before(done => {
  980. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  981. fs.ensureFileSync(fileObj.path);
  982. fs.writeFileSync(fileObj.path, "exist");
  983. s = new RollingFileWriteStream(fileObj.path);
  984. s.write("now", "utf8", done);
  985. });
  986. after(() => {
  987. s.end();
  988. fs.removeSync(fileObj.dir);
  989. });
  990. it("should use write in the old file if not reach the maxSize limit", () => {
  991. const files = fs.readdirSync(fileObj.dir);
  992. const expectedFileList = [fileObj.base];
  993. files.should.containDeep(expectedFileList);
  994. files.length.should.equal(expectedFileList.length);
  995. fs.readFileSync(path.format(fileObj))
  996. .toString()
  997. .should.equal("existnow");
  998. });
  999. });
  1000. describe("when old files exist with contents", () => {
  1001. const fileObj = generateTestFile();
  1002. let s;
  1003. before(done => {
  1004. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  1005. fs.ensureFileSync(fileObj.path);
  1006. fs.writeFileSync(fileObj.path, "This is exactly 30 bytes long\n");
  1007. s = new RollingFileWriteStream(fileObj.path, { maxSize: 35 });
  1008. s.write("one\n", "utf8"); //34
  1009. s.write("two\n", "utf8"); //38 - file should be rotated next time
  1010. s.write("three\n", "utf8", done); // this should be in a new file.
  1011. });
  1012. after(() => {
  1013. s.end();
  1014. fs.removeSync(fileObj.dir);
  1015. });
  1016. it("should respect the existing file size", () => {
  1017. const files = fs.readdirSync(fileObj.dir);
  1018. const expectedFileList = [fileObj.base, fileObj.base + ".1"];
  1019. files.should.containDeep(expectedFileList);
  1020. files.length.should.equal(expectedFileList.length);
  1021. fs.readFileSync(path.format(fileObj))
  1022. .toString()
  1023. .should.equal("three\n");
  1024. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".1"))
  1025. .toString()
  1026. .should.equal("This is exactly 30 bytes long\none\ntwo\n");
  1027. });
  1028. });
  1029. describe("when old files exist with indices", () => {
  1030. const fileObj = generateTestFile();
  1031. let s;
  1032. before(done => {
  1033. fs.ensureFileSync(fileObj.path);
  1034. fs.writeFileSync(
  1035. fileObj.path,
  1036. "This was the base file and it should be more than 30 bytes\n"
  1037. ); // base
  1038. fs.writeFileSync(fileObj.path + ".1", "This was the first old file\n"); // base.1
  1039. s = new RollingFileWriteStream(fileObj.path, {
  1040. maxSize: 30,
  1041. numToKeep: 5
  1042. });
  1043. s.write("This is exactly 30 bytes long\n", "utf8"); // base.1 -> base.2, base -> base.1
  1044. s.write("This is exactly 30 bytes long\n", "utf8"); // base.2 -> base.3, base.1 -> base.2, base -> base.1
  1045. s.write("three\n", "utf8", done); // base.3 -> base.4, base.2 -> base.3, base.1 -> base.2, base -> base.1
  1046. });
  1047. after(() => {
  1048. s.end();
  1049. fs.removeSync(fileObj.dir);
  1050. });
  1051. it("should rotate the old file indices", () => {
  1052. const files = fs.readdirSync(fileObj.dir);
  1053. const expectedFileList = [
  1054. fileObj.base,
  1055. fileObj.base + ".1",
  1056. fileObj.base + ".2",
  1057. fileObj.base + ".3",
  1058. fileObj.base + ".4"
  1059. ];
  1060. files.should.containDeep(expectedFileList);
  1061. files.length.should.equal(expectedFileList.length);
  1062. fs.readFileSync(path.format(fileObj))
  1063. .toString()
  1064. .should.equal("three\n");
  1065. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".1"))
  1066. .toString()
  1067. .should.equal("This is exactly 30 bytes long\n");
  1068. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".2"))
  1069. .toString()
  1070. .should.equal("This is exactly 30 bytes long\n");
  1071. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".3"))
  1072. .toString()
  1073. .should.equal(
  1074. "This was the base file and it should be more than 30 bytes\n"
  1075. );
  1076. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".4"))
  1077. .toString()
  1078. .should.equal("This was the first old file\n");
  1079. });
  1080. });
  1081. describe("when old files exist with contents and rolling by date", () => {
  1082. const fileObj = generateTestFile();
  1083. let s;
  1084. before(done => {
  1085. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  1086. fs.ensureFileSync(fileObj.path);
  1087. fs.writeFileSync(fileObj.path, "This was created Sept 12, 2012.\n");
  1088. fakeNow = new Date(2012, 8, 13, 10, 53, 12);
  1089. s = new RollingFileWriteStream(fileObj.path, { pattern: "yyyy-MM-dd" });
  1090. s.write("It is now Sept 13, 2012.\n", "utf8", done); // this should be in a new file.
  1091. });
  1092. after(() => {
  1093. s.end();
  1094. fs.removeSync(fileObj.dir);
  1095. });
  1096. it("should respect the existing file date", () => {
  1097. const files = fs.readdirSync(fileObj.dir);
  1098. const expectedFileList = [fileObj.base, fileObj.base + ".2012-09-12"];
  1099. files.should.containDeep(expectedFileList);
  1100. files.length.should.equal(expectedFileList.length);
  1101. fs.readFileSync(path.format(fileObj))
  1102. .toString()
  1103. .should.equal("It is now Sept 13, 2012.\n");
  1104. fs.readFileSync(path.join(fileObj.dir, fileObj.base + ".2012-09-12"))
  1105. .toString()
  1106. .should.equal("This was created Sept 12, 2012.\n");
  1107. });
  1108. });
  1109. describe("when old files exist with contents and stream created with overwrite flag", () => {
  1110. const fileObj = generateTestFile();
  1111. let s;
  1112. before(done => {
  1113. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  1114. fs.ensureFileSync(fileObj.path);
  1115. fs.writeFileSync(fileObj.path, "This is exactly 30 bytes long\n");
  1116. s = new RollingFileWriteStream(fileObj.path, { maxSize: 35, flags: "w" });
  1117. s.write("there should only be this\n", "utf8", done);
  1118. });
  1119. after(() => {
  1120. s.end();
  1121. fs.removeSync(fileObj.dir);
  1122. });
  1123. it("should ignore the existing file size", () => {
  1124. const files = fs.readdirSync(fileObj.dir);
  1125. const expectedFileList = [fileObj.base];
  1126. files.should.containDeep(expectedFileList);
  1127. files.length.should.equal(expectedFileList.length);
  1128. s.state.currentSize.should.equal(26);
  1129. fs.readFileSync(path.format(fileObj))
  1130. .toString()
  1131. .should.equal("there should only be this\n");
  1132. });
  1133. });
  1134. describe("when dir does not exist", () => {
  1135. const fileObj = generateTestFile();
  1136. let s;
  1137. before(done => {
  1138. fs.removeSync(fileObj.dir);
  1139. fakeNow = new Date(2012, 8, 12, 10, 37, 11);
  1140. s = new RollingFileWriteStream(fileObj.path);
  1141. s.write("test", "utf8", done);
  1142. });
  1143. after(() => {
  1144. s.end();
  1145. fs.removeSync(fileObj.dir);
  1146. });
  1147. it("should create the dir", () => {
  1148. const files = fs.readdirSync(fileObj.dir);
  1149. const expectedFileList = [fileObj.base];
  1150. files.should.containDeep(expectedFileList);
  1151. files.length.should.equal(expectedFileList.length);
  1152. fs.readFileSync(path.format(fileObj))
  1153. .toString()
  1154. .should.equal("test");
  1155. });
  1156. });
  1157. describe("when given just a base filename with no dir", () => {
  1158. let s;
  1159. before(done => {
  1160. s = new RollingFileWriteStream("test.log");
  1161. s.write("this should not cause any problems", "utf8", done);
  1162. });
  1163. after(() => {
  1164. s.end();
  1165. fs.removeSync("test.log");
  1166. });
  1167. it("should use process.cwd() as the dir", () => {
  1168. const files = fs.readdirSync(process.cwd());
  1169. files.should.containDeep(["test.log"]);
  1170. fs.readFileSync(path.join(process.cwd(), "test.log"))
  1171. .toString()
  1172. .should.equal("this should not cause any problems");
  1173. });
  1174. });
  1175. describe("with no callback to write", () => {
  1176. let s;
  1177. before(done => {
  1178. s = new RollingFileWriteStream("no-callback.log");
  1179. s.write("this is all very nice", "utf8", done);
  1180. });
  1181. after(done => {
  1182. fs.remove("no-callback.log", done);
  1183. });
  1184. it("should not complain", done => {
  1185. s.write("I am not bothered if this succeeds or not");
  1186. s.end(done);
  1187. });
  1188. });
  1189. describe("events", () => {
  1190. let s;
  1191. before(done => {
  1192. s = new RollingFileWriteStream("test-events.log");
  1193. s.write("this should not cause any problems", "utf8", done);
  1194. });
  1195. after(() => {
  1196. s.end();
  1197. fs.removeSync("test-events.log");
  1198. });
  1199. it("should emit the error event of the underlying stream", done => {
  1200. s.on("error", e => {
  1201. e.message.should.equal("oh no");
  1202. done();
  1203. });
  1204. s.currentFileStream.emit("error", new Error("oh no"));
  1205. });
  1206. });
  1207. });