UNPKG

12.8 kBtext/coffeescriptView Raw
1#mocha
2e = require 'expect.js'
3fs = require 'fs'
4path = require 'path'
5stream = require 'stream'
6
7class mockStream
8 constructor : () -> @chunks = []
9 write : (chunk) ->
10 @chunks.push chunk
11 clean : -> chunks = []
12 toString : (nocolor = true) ->
13 data = ''
14 for chunk in @chunks
15 data += chunk.toString()
16 data
17 toStringNoColor : (nocolor = true) ->
18 data = ''
19 for chunk in @chunks
20 data += chunk.toString()
21 data.replace /\x1b\[\d+m/g, '' # trim ansi color
22
23
24
25
26mock =
27 send : ''
28 headers : {}
29 req :
30 url : '/'
31 headers :
32 'user-agent' : 'mock server'
33 'referer' : 'mock refer'
34 socket :
35 remoteAddress : '127.0.0.1'
36 remotePort : 1234
37 httpVersionMajor : 1
38 httpVersionMinor : 1
39 method : 'GET'
40 resp :
41 write : (data)-> mock.send += data.toString() if data?
42 end : (data)-> mock.send += data.toString() if data?
43 statusCode : 0
44 setHeader : (name, value) -> mock.headers[name.toLowerCase()] = value
45 getHeader : (name) -> mock.headers[name.toLowerCase()]
46 clean : ->
47 mock.send = ''
48 mock.headers = {}
49 mock.resp.statusCode = 0
50 mock.url = '/'
51mock.resp.headers = mock.headers
52
53describe 'JustLog', ->
54 jl = require '../lib/justlog'
55 jl.config flushTime : 10
56 {pre: predefined} = require '../lib/pattern'
57 options = stdout = stderr = l = null
58 dir = "#{__dirname}/log_file"
59
60 beforeEach ->
61 mock.clean()
62 stdout = new mockStream
63 stderr = new mockStream
64 options =
65 file:
66 path : "[#{dir}/test.txt]"
67 stdio :
68 stdout : stdout
69 stderr : stderr
70
71
72 afterEach (done)->
73 return done() if not l?
74 l.close ()->
75 setTimeout ->
76 try
77 for file in fs.readdirSync dir
78 fs.unlinkSync "#{dir}/#{file}"
79 fs.rmdirSync dir
80 done()
81 , 100
82 l = null
83
84 describe 'options init', ->
85 it 'check default options', (done)->
86 l = new jl
87 e(jl.INFO).to.be l.INFO
88 e(jl.DEBUG).to.be l.DEBUG
89 e(jl.WARN).to.be l.WARN
90 e(jl.ERROR).to.be l.ERROR
91
92 e(l.options.file.level).to.be jl.EXCEPTION
93 e(l.options.file.path).to.be "[#{process.cwd()}/logs/_mocha-]YYYY-MM-DD[.log]"
94 e(l.options.stdio.level).to.be jl.ALL
95 e(l.options.stdio.stdout).to.be process.stdout
96 e(l.options.stdio.stderr).to.be process.stderr
97 e(l.options.file.render.pattern).to.be 'file'
98 e(l.options.stdio.render.pattern).to.be 'color'
99 setTimeout done, 100
100 describe 'stdio', ->
101 it 'stdout with default output pattern', (done)->
102 options.file = false
103 l = new jl options
104 l.info 'simple info'
105 l.debug 'simple debug'
106 l.warn 'simple warn'
107 l.error 'simple error'
108 e(stdout.toStringNoColor()).to.match ///
109 ^
110 \d{2}:\d{2}:\d{2}\s
111 INFO\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\sinfo\n
112 \d{2}:\d{2}:\d{2}\s
113 DEBUG\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\sdebug\n
114 $
115 ///
116 e(stderr.toStringNoColor()).to.match ///
117 ^
118 \d{2}:\d{2}:\d{2}\s
119 WARN\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\swarn\n
120 \d{2}:\d{2}:\d{2}\s
121 ERROR\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\serror\n
122 $
123 ///
124 done()
125
126 it 'stdout with default output pattern and printf info', (done)->
127 options.file.level = 0
128 options.stdio.level = jl.INFO | jl.DEBUG
129 l = new jl options
130 l.info 'simple info', 'data2', 123
131 l.debug 'simple debug %s %d %s %j', 'data3', 456, [1, 2, 3], a:1
132 l.warn 'simple warn %s'
133 l.error 'simple error'
134 e(stdout.toStringNoColor()).to.match ///
135 ^
136 \d{2}:\d{2}:\d{2}\s
137 INFO\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\sinfo\sdata2\s123\n
138 \d{2}:\d{2}:\d{2}\s
139 DEBUG\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\ssimple\sdebug\sdata3\s456\s1,2,3\s\{"a":1\}\n
140 $
141 ///
142 e(stderr.toStringNoColor()).to.be ''
143 done()
144 it 'stdout with default output pattern and change placeholder to "_"', (done)->
145 options.file = false
146 options.placeholder = "_"
147 l = new jl options
148 l.info {}
149 e(stdout.toStringNoColor()).to.match ///
150 ^
151 \d{2}:\d{2}:\d{2}\s
152 INFO\s+(out/test/)?tests/test-justlog\.(js|coffee):\d+\s_\n
153 $
154 ///
155 done()
156 describe 'file', ->
157 it 'write warn & error log with default pattern', (done)->
158 options.stdio = false
159 l = new jl options
160 l.info 'simple info'
161 l.debug 'simple debug'
162 l.warn 'simple warn'
163 l.error 'simple error'
164 l.close ->
165 e(fs.readFileSync(l.file.path).toString()).to.match ///
166 ^
167 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
168 \[WARN\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\swarn\n
169 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
170 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror\n
171 $
172 ///
173 done()
174
175 it 'rename file when current stream is not closed', (done)->
176 options.stdio.level = 0
177 options.file._watcher_timeout = 10
178
179 l = new jl options
180 flag = 0
181 l.on 'rename', (file) ->
182 flag++
183 e(file).to.be l.file.path
184 l.warn 'simple warn' # first log
185 setTimeout -> # remove 30 ms later
186 fs.renameSync l.file.path, l.file.path+'.move'
187 , 300
188 setTimeout -> # second log 60 ms later
189 l.error 'simple error'
190 , 600
191 setTimeout -> # remove 30 ms later
192 fs.renameSync l.file.path, l.file.path+'.move1'
193 , 900
194 setTimeout -> # second log 60 ms later
195 l.error 'simple error2'
196 , 1200
197 setTimeout -> # check two logfile 90 ms later
198 e(flag).to.be 2
199 l.close ()->
200 e(fs.readFileSync(l.file.path+'.move').toString()).to.match ///
201 ^
202 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
203 \[WARN\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\swarn\n
204 $
205 ///
206 e(fs.readFileSync(l.file.path+'.move1').toString()).to.match ///
207 ^
208 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
209 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror\n
210 $
211 ///
212 e(fs.readFileSync(l.file.path).toString()).to.match ///
213 ^
214 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
215 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror2\n
216 $
217 ///
218 done()
219 , 1500
220 it 'file inode changed when current stream is not closed', (done)->
221 # return done()
222 options.stdio = false
223 options.file._watcher_timeout = 10
224 l = new jl options
225 flag = 0
226 l.on 'rename', (file) ->
227 flag++
228 e(file).to.be l.file.path
229 l.warn 'simple warn' # first log
230 setTimeout -> # remove 30 ms later
231 fs.renameSync l.file.path, l.file.path+'.move'
232 fs.writeFileSync l.file.path, 'somedata1\n'
233 , 300
234 setTimeout -> # second log 60 ms later
235 l.error 'simple error'
236 , 600
237 setTimeout -> # remove 30 ms later
238 fs.renameSync l.file.path, l.file.path+'.move1'
239 fs.writeFileSync l.file.path, 'somedata2\n'
240 , 900
241 setTimeout -> # second log 60 ms later
242 l.error 'simple error2'
243 , 1200
244 setTimeout -> # check two logfile 90 ms later
245 e(flag).to.be 2
246 l.close ()->
247 e(fs.readFileSync(l.file.path+'.move').toString()).to.match ///
248 ^
249 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
250 \[WARN\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\swarn\n
251 $
252 ///
253 e(fs.readFileSync(l.file.path+'.move1').toString()).to.match ///
254 ^
255 somedata1\n
256 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
257 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror\n
258 $
259 ///
260 e(fs.readFileSync(l.file.path).toString()).to.match ///
261 ^
262 somedata2\n
263 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
264 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror2\n
265 $
266 ///
267 done()
268 , 1500
269
270 it 'logfile rotate by time', (done)->
271 nowMs = new Date().getMilliseconds()
272 this.timeout 10000
273 setTimeout ->
274 options.stdio = false
275 options.file.watcher_timeout = 10
276 options.file.path = "[#{dir}]/ss.txt"
277 l = new jl options
278 files = [l.file.path]
279 l.on 'rotate', (prev, curr) ->
280 files.push curr
281 tflag = 0
282 l.on 'timer', (ms)->
283 e(ms).to.below 1001
284 e(ms).to.above 99
285 tflag++
286 # console.log prev, curr
287 l.warn 'simple warn' # first log
288 setTimeout ->
289 l.error 'simple error1'
290 , 1000
291 setTimeout ->
292 l.error 'simple error2'
293 , 2000
294 setTimeout ->
295 l.error 'simple error3'
296 l.close ->
297 # console.log files
298 e(tflag).to.above 3
299 # e(tflag).to.below 6
300 flag = 0
301 # console.log files
302 for k in files
303 txt = fs.readFileSync(k).toString().trim()
304 fs.unlinkSync k
305 continue unless txt
306 switch ++flag
307 when 1
308 e(txt).to.match ///
309 ^
310 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
311 \[WARN\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\swarn\n?
312 $
313 ///
314 when 2
315 e(txt).to.match ///
316 ^
317 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
318 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror1\n?
319 $
320 ///
321 when 3
322 e(txt).to.match ///
323 ^
324 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
325 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror2\n?
326 $
327 ///
328 when 4
329 e(txt).to.match ///
330 ^
331 \d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\s
332 \[ERROR\]\s+\((out/test/)?tests/test-justlog\.(js|coffee):\d+\)\ssimple\serror3\n?
333 $
334 ///
335 e(flag).to.be 4
336 done()
337 , 3000
338 , nowMs + 10
339 describe 'middleware', ->
340 it 'simple 200 response', (done)->
341 m = jl.middleware options
342 l = m.justlog
343 mock.resp.statusCode = 200
344 mock.req.url = '/simple_200'
345 m mock.req, mock.resp, -> setTimeout (->mock.resp.end 'some data1'), 20
346 setTimeout ->
347 mock.resp.end 'some data'
348 std = stdout.toString()
349 e(stdout.toString()).to.match ///
350 ^
351 \x1b\[33m127\.0\.0\.1\x1b\[0m\s
352 -\s
353 -\s
354 \[\d{1,2}/\w{3}/\d{4}:\d\d:\d\d:\d\d\s[\+\-]?\d{4}\]\s
355 "\x1b\[32mGET\x1b\[0m\s\x1b\[4m\x1b\[1m\x1b\[34m/simple_200\x1b\[0m\sHTTP/1.1"\s
356 \x1b\[32m200\x1b\[0m\s-\s
357 "\x1b\[34mmock\srefer\x1b\[0m"\s
358 "\x1b\[36mmock\sserver\x1b\[0m"\s
359 [12]\d\n
360 $
361 ///
362
363 fbody = fs.readFileSync(l.file.path).toString()
364 e(fbody).to.match
365 ///
366 ^
367 127\.0\.0\.1\s
368 -\s
369 -\s
370 \[\d{1,2}/\w{3}/\d{4}:\d\d:\d\d:\d\d\s[\+\-]?\d{4}\]\s
371 "GET\s /simple_200\sHTTP/1.1"\s
372 200\s-\s
373 "mock\srefer"\s
374 "mock\sserver"\s
375 [12]\d\n
376 $
377 ///
378 done()
379 , 100
380 it 'with traceid', (done)->
381 options.traceid = true
382 options.file.pattern = 'accesslog-traceid'
383 m = jl.middleware options
384 l = m.justlog
385 mock.resp.statusCode = 200
386 mock.req.url = '/traceid'
387 m mock.req, mock.resp, -> setTimeout (->mock.resp.end 'some data1'), 20
388 setTimeout ->
389 mock.resp.end 'some data'
390 fbody = fs.readFileSync(l.file.path).toString()
391 e(fbody).to.match
392 ///
393 ^
394 127\.0\.0\.1\s
395 -\s
396 -\s
397 \[\d{1,2}/\w{3}/\d{4}:\d\d:\d\d:\d\d\s[\+\-]?\d{4}\]\s
398 "GET\s /traceid\sHTTP/1.1"\s
399 200\s-\s
400 "mock\srefer"\s
401 "mock\sserver"\s
402 [12]\d\s
403 [\w\/\=]{24}\n
404 $
405 ///
406 done()
407 , 100
408
409