1 # -*- encoding: binary -*-
2 $stderr.sync = $stdout.sync = true
13 # used to test subclasses
14 class FooString < String
17 class TestClogger < Test::Unit::TestCase
18 include Clogger::Format
22 @nginx_fmt = "%d/%b/%Y:%H:%M:%S %z"
24 "REQUEST_METHOD" => "GET",
25 "HTTP_VERSION" => "HTTP/1.0",
26 "HTTP_USER_AGENT" => 'echo and socat \o/',
27 "PATH_INFO" => "/hello",
28 "QUERY_STRING" => "goodbye=true",
29 "rack.errors" => $stderr,
30 "rack.input" => File.open('/dev/null', 'rb'),
31 "rack.url_scheme" => "http",
32 "REMOTE_ADDR" => 'home',
41 Clogger.new(lambda { |env| [ 0, {}, [] ] })
45 assert_raise(ArgumentError) { Clogger.new }
48 def test_clogger_sym_format
49 app = lambda { |env| [ 0, {}, [] ] }
50 tmp = Clogger.new app, :format => :Rack_1_0, :logger => $stderr
54 cl = Clogger.new(lambda { |env| [ 0, {}, [] ] }, :logger => $stderr)
55 assert_kind_of(Integer, cl.fileno)
56 assert_equal $stderr.fileno, cl.fileno
59 def test_init_stringio
60 cl = Clogger.new(lambda { |env| [ 0, {}, [] ] }, :logger => StringIO.new)
64 def test_write_stringio
65 start = DateTime.now - 1
67 cl = Clogger.new(lambda { |env| [ "302 Found", {}, [] ] }, :logger => str)
68 status, headers, body = cl.call(@req)
69 assert_equal("302 Found", status)
70 assert_equal({}, headers)
71 body.each { |part| assert false }
74 r = %r{\Ahome - - \[[^\]]+\] "GET /hello\?goodbye=true HTTP/1.0" 302 -\n\z}
76 %r{\[([^\]]+)\]} =~ str
78 assert_nothing_raised {
79 tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
82 assert tmp <= DateTime.now
85 def test_clen_stringio
86 start = DateTime.now - 1
88 app = lambda { |env| [ 301, {'Content-Length' => '5'}, ['abcde'] ] }
90 assert format.gsub!(/response_length/, 'sent_http_content_length')
91 cl = Clogger.new(app, :logger => str, :format => format)
92 status, headers, body = cl.call(@req)
93 assert_equal(301, status)
94 assert_equal({'Content-Length' => '5'}, headers)
95 body.each { |part| assert_equal('abcde', part) }
97 r = %r{\Ahome - - \[[^\]]+\] "GET /hello\?goodbye=true HTTP/1.0" 301 5\n\z}
99 %r{\[([^\]]+)\]} =~ str
101 assert_nothing_raised {
102 tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
105 assert tmp <= DateTime.now
108 def test_compile_ambiguous
109 cl = Clogger.new(nil, :logger => $stderr)
112 ary = compile_format(
113 '$remote_addr $$$$pid' \
117 [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
118 [ Clogger::OP_LITERAL, " " ],
119 [ Clogger::OP_LITERAL, "$$$" ],
120 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:pid] ],
121 [ Clogger::OP_LITERAL, "\n" ],
123 assert_equal expect, ary
126 def test_compile_auto_newline
127 cl = Clogger.new(nil, :logger => $stderr)
129 cl.instance_eval { ary = compile_format('$remote_addr $request') }
131 [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
132 [ Clogger::OP_LITERAL, " " ],
133 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
134 [ Clogger::OP_LITERAL, "\n" ],
136 assert_equal expect, ary
141 fmt = '$remote_addr $pid $remote_user [$time_local] ' \
142 '"$request" $status $body_bytes_sent "$http_referer" ' \
143 '"$http_user_agent" "$http_cookie" $request_time $http_host'
144 app = lambda { |env| [ 302, {}, [] ] }
145 cl = Clogger.new(app, :logger => str, :format => fmt)
146 cookie = "foo=bar#{'f' * 256}".freeze
148 'HTTP_HOST' => 'example.com:12345',
149 'HTTP_COOKIE' => cookie,
151 req = @req.merge(req)
152 body = cl.call(req).last
153 body.each { |part| part }
156 assert(str.size > 128)
157 assert_match %r["echo and socat \\o/" "#{cookie}" \d+\.\d{3}], str
158 assert_match %r["#{cookie}" \d+\.\d{3} example\.com:12345\n\z], str
162 cl = Clogger.new(nil, :logger => $stderr)
165 ary = compile_format(
166 '$remote_addr - $remote_user [$time_local] ' \
167 '"$request" $status $body_bytes_sent "$http_referer" ' \
168 '"$http_user_agent" "$http_cookie" $request_time ' \
169 '$env{rack.url_scheme}' \
173 [ Clogger::OP_REQUEST, "REMOTE_ADDR" ],
174 [ Clogger::OP_LITERAL, " - " ],
175 [ Clogger::OP_REQUEST, "REMOTE_USER" ],
176 [ Clogger::OP_LITERAL, " [" ],
177 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:time_local] ],
178 [ Clogger::OP_LITERAL, "] \"" ],
179 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:request] ],
180 [ Clogger::OP_LITERAL, "\" "],
181 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:status] ],
182 [ Clogger::OP_LITERAL, " "],
183 [ Clogger::OP_SPECIAL, Clogger::SPECIAL_VARS[:body_bytes_sent] ],
184 [ Clogger::OP_LITERAL, " \"" ],
185 [ Clogger::OP_REQUEST, "HTTP_REFERER" ],
186 [ Clogger::OP_LITERAL, "\" \"" ],
187 [ Clogger::OP_REQUEST, "HTTP_USER_AGENT" ],
188 [ Clogger::OP_LITERAL, "\" \"" ],
189 [ Clogger::OP_REQUEST, "HTTP_COOKIE" ],
190 [ Clogger::OP_LITERAL, "\" " ],
191 [ Clogger::OP_REQUEST_TIME, '%d.%03d', 1000 ],
192 [ Clogger::OP_LITERAL, " " ],
193 [ Clogger::OP_REQUEST, "rack.url_scheme" ],
194 [ Clogger::OP_LITERAL, "\n" ],
196 assert_equal expect, ary
200 current = Thread.current.to_s
202 app = lambda { |env| [ 302, {}, [] ] }
203 cl = Clogger.new(app,
205 :format => "-$e{Thread.current}-\n")
206 status, headers, body = cl.call(@req)
207 assert_equal "-#{current}-\n", str.string
212 app = lambda { |env| [ 302, {}, [] ] }
213 cl = Clogger.new(app, :logger => str, :format => "[$pid]\n")
214 status, headers, body = cl.call(@req)
215 assert_equal "[#$$]\n", str.string
220 app = lambda { |env| [ 302, {}, [] ] }
221 cl = Clogger.new(app, :logger => str, :format => "$ip")
222 req = @req.merge("HTTP_X_FORWARDED_FOR" => '192.168.1.1')
223 status, headers, body = cl.call(req)
224 assert_equal "192.168.1.1\n", str.string
227 status, headers, body = cl.call(@req)
228 assert_equal "home\n", str.string
234 start = DateTime.now - 1
236 app = lambda { |env| [ 200, {'Content-Length'=>'0'}, %w(a b c)] }
237 cl = Clogger.new(app, :logger => str, :format => Rack_1_0)
238 status, headers, body = cl.call(@req)
240 body.each { |s| tmp << s }
242 assert_equal %w(a b c), tmp
244 assert_match %r[" 200 3 \d+\.\d{4}\n\z], str
246 %r{\[(\d+/\w+/\d+ \d+:\d+:\d+)\]} =~ str
248 assert_nothing_raised { tmp = DateTime.strptime($1, "%d/%b/%Y %H:%M:%S") }
250 assert tmp <= DateTime.now
255 app = lambda { |env| [ 200, {}, [] ] }
256 cl = Clogger.new(app, :logger => str, :format => '$msec')
257 a = Time.now.to_f - 0.001
258 status, header, bodies = cl.call(@req)
259 assert_match %r(\A\d+\.\d{3}\n\z), str.string
260 b = Time.now.to_f + 0.001
261 logged = str.string.to_f
262 assert logged >= a, "#{logged} >= #{a}"
263 assert logged <= b, "#{logged} <= #{b}"
268 app = lambda { |env| [ 200, {}, [] ] }
269 cl = Clogger.new(app, :logger => str, :format => '$usec')
270 a = Time.now.to_f - 0.000001
271 status, header, bodies = cl.call(@req)
272 assert_match %r(\A\d+\.\d{6}\n\z), str.string
273 b = Time.now.to_f + 0.000001
274 logged = str.string.to_f
275 assert logged >= a, "#{logged} >= #{a}"
276 assert logged <= b, "#{logged} <= #{b}"
281 app = lambda { |env| [ 200, {}, [] ] }
282 cl = Clogger.new(app, :logger => str, :format => '$time{0}')
283 a = Time.now.to_f - 1
284 status, header, bodies = cl.call(@req)
285 assert_match %r(\A\d+\n\z), str.string
286 b = Time.now.to_f + 1
287 logged = str.string.to_f
288 assert logged >= a, "#{logged} >= #{a}"
289 assert logged <= b, "#{logged} <= #{b}"
294 app = lambda { |env| [ 200, {}, [] ] }
295 cl = Clogger.new(app, :logger => str, :format => '$time{1}')
296 a = Time.now.to_f - 0.5
297 status, header, bodies = cl.call(@req)
298 assert_match %r(\A\d+\.\d\n\z), str.string
299 b = Time.now.to_f + 0.5
300 logged = str.string.to_f
301 assert logged >= a, "#{logged} >= #{a}"
302 assert logged <= b, "#{logged} <= #{b}"
305 def test_request_length
307 input = StringIO.new('.....')
308 app = lambda { |env| [ 200, {}, [] ] }
309 cl = Clogger.new(app, :logger => str, :format => '$request_length')
310 status, header, bodies = cl.call(@req.merge('rack.input' => input))
311 assert_equal "5\n", str.string
314 def test_response_length_0
316 app = lambda { |env| [ 200, {}, [] ] }
317 cl = Clogger.new(app, :logger => str, :format => '$response_length')
318 status, header, bodies = cl.call(@req)
319 bodies.each { |part| part }
321 assert_equal "-\n", str.string
325 start = DateTime.now - 1
327 app = lambda { |env| [ 200, {'Content-Length'=>'3'}, %w(a b c)] }
328 cl = Clogger.new(app, :logger => str, :format => Combined)
329 status, headers, body = cl.call(@req)
331 body.each { |s| tmp << s }
333 assert_equal %w(a b c), tmp
335 assert_match %r[" 200 3 "-" "echo and socat \\o/"\n\z], str
337 %r{\[(\d+/\w+/\d+:\d+:\d+:\d+ .+)\]} =~ str
339 assert_nothing_raised {
340 tmp = DateTime.strptime($1, "%d/%b/%Y:%H:%M:%S %z")
343 assert tmp <= DateTime.now
346 def test_rack_errors_fallback
348 app = lambda { |env| [ 200, {'Content-Length'=>'3'}, %w(a b c)] }
349 cl = Clogger.new(app, :format => '$pid')
350 req = @req.merge('rack.errors' => err)
351 status, headers, body = cl.call(req)
352 assert_equal "#$$\n", err.string
356 s_body = StringIO.new(%w(a b c).join("\n"))
357 app = lambda { |env| [ 200, {'Content-Length'=>'5'}, s_body] }
358 cl = Clogger.new(app, :logger => [], :format => '$pid')
359 status, headers, body = cl.call(@req)
360 assert ! s_body.closed?
361 assert_nothing_raised { body.close }
362 assert s_body.closed?
367 app = lambda { |env| [ 200, {'Content-Length'=>'5'}, [] ] }
368 cl = Clogger.new(app,
370 :format => '$http_user_agent "$request"')
372 'HTTP_USER_AGENT' => '"asdf"',
373 'QUERY_STRING' => 'sdf=bar"',
374 'PATH_INFO' => '/"<>"',
376 status, headers, body = cl.call(@req.merge(bad))
377 expect = '\x22asdf\x22 "GET /\x22<>\x22?sdf=bar\x22 HTTP/1.0"' << "\n"
378 assert_equal expect, str.string
381 # rack allows repeated headers with "\n":
382 # { 'Set-Cookie' => "a\nb" } =>
385 def test_escape_header_newlines
387 app = lambda { |env| [302, { 'Set-Cookie' => "a\nb" }, [] ] }
388 cl = Clogger.new(app, :logger => str, :format => '$sent_http_set_cookie')
390 assert_equal "a\\x0Ab\n", str.string
393 def test_escape_crazy_delete
395 app = lambda { |env| [302, {}, [] ] }
396 cl = Clogger.new(app, :logger => str, :format => "$http_cookie")
397 @req["HTTP_COOKIE"] = "a\x7f\xff"
399 assert_equal "a\\x7F\\xFF\n", str.string
402 def test_request_uri_fallback
404 app = lambda { |env| [ 200, {}, [] ] }
405 cl = Clogger.new(app, :logger => str, :format => '$request_uri')
406 status, headers, body = cl.call(@req)
407 assert_equal "/hello?goodbye=true\n", str.string
410 def test_request_uri_set
412 app = lambda { |env| [ 200, {}, [] ] }
413 cl = Clogger.new(app, :logger => str, :format => '$request_uri')
414 status, headers, body = cl.call(@req.merge("REQUEST_URI" => '/zzz'))
415 assert_equal "/zzz\n", str.string
421 req = Rack::Request.new(env).cookies
424 cl = Clogger.new(app,
425 :format => '$cookie_foo $cookie_quux',
427 req = @req.merge('HTTP_COOKIE' => "foo=bar;quux=h&m")
428 status, headers, body = cl.call(req)
429 assert_equal "bar h&m\n", str.string
432 def test_bogus_app_response
434 app = lambda { |env| 302 }
435 cl = Clogger.new(app, :logger => str)
436 assert_raise(TypeError) { cl.call(@req) }
438 e = Regexp.quote " \"GET /hello?goodbye=true HTTP/1.0\" 500 -"
439 assert_match %r{#{e}$}m, str
442 def test_broken_header_response
444 app = lambda { |env| [302, [ %w(a) ], []] }
445 cl = Clogger.new(app, :logger => str, :format => '$sent_http_set_cookie')
446 assert_nothing_raised { cl.call(@req) }
449 def test_subclass_hash
451 req = Rack::Utils::HeaderHash.new(@req)
452 app = lambda { |env| [302, [ %w(a) ], []] }
453 cl = Clogger.new(app, :logger => str, :format => Rack_1_0)
454 assert_nothing_raised { cl.call(req).last.each {}.close }
458 def test_subclassed_string_req
461 @req.each { |key,value|
462 req[FooString.new(key)] = value.kind_of?(String) ?
463 FooString.new(value) : value
465 app = lambda { |env| [302, [ %w(a) ], []] }
466 cl = Clogger.new(app, :logger => str, :format => Rack_1_0)
467 assert_nothing_raised { cl.call(req).last.each {}.close }
471 def test_subclassed_string_in_body
475 app = lambda { |env| [302, [ %w(a) ], [FooString.new(body)]] }
476 cl = Clogger.new(app, :logger => str, :format => '$body_bytes_sent')
477 assert_nothing_raised { cl.call(@req).last.each { |x| r = x }.close }
479 assert_equal body.size.to_s << "\n", str.string
481 assert r.object_id != body.object_id
484 def test_http_09_request
486 app = lambda { |env| [302, [ %w(a) ], []] }
487 cl = Clogger.new(app, :logger => str, :format => '$request')
489 req.delete 'HTTP_VERSION'
491 assert_equal "GET /hello?goodbye=true\n", str.string
494 def test_request_method_only
496 app = lambda { |env| [302, [ %w(a) ], []] }
497 cl = Clogger.new(app, :logger => str, :format => '$request_method')
499 assert_equal "GET\n", str.string
502 def test_content_length_null
504 app = lambda { |env| [302, [ %w(a) ], []] }
505 cl = Clogger.new(app, :logger => str, :format => '$content_length')
507 assert_equal "-\n", str.string
510 def test_content_length_set
512 app = lambda { |env| [302, [ %w(a) ], []] }
513 cl = Clogger.new(app, :logger => str, :format => '$content_length')
514 cl.call(@req.merge('CONTENT_LENGTH' => '5'))
515 assert_equal "5\n", str.string
518 def test_http_content_type_fallback
520 app = lambda { |env| [302, [ %w(a) ], []] }
521 cl = Clogger.new(app, :logger => str, :format => '$http_content_type')
522 cl.call(@req.merge('CONTENT_TYPE' => 'text/plain'))
523 assert_equal "text/plain\n", str.string
526 def test_clogger_synced
528 logger = Struct.new(:sync, :io).new(false, io)
533 app = lambda { |env| [302, [ %w(a) ], []] }
534 cl = Clogger.new(app, :logger => logger)
538 def test_clogger_unsyncable
540 assert ! logger.respond_to?('sync=')
541 app = lambda { |env| [302, [ %w(a) ], []] }
542 assert_nothing_raised { Clogger.new(app, :logger => logger) }
545 def test_clogger_no_ORS
547 app = lambda { |env| [302, [ %w(a) ], []] }
548 cl = Clogger.new(app, :logger => s, :format => "$request", :ORS => "")
550 assert_equal "GET /hello?goodbye=true HTTP/1.0", s
553 def test_clogger_weird_ORS
555 app = lambda { |env| [302, [ %w(a) ], []] }
556 cl = Clogger.new(app, :logger => s, :format => "<$request", :ORS => ">")
558 assert_equal "<GET /hello?goodbye=true HTTP/1.0>", s
561 def test_clogger_body_not_closeable
563 app = lambda { |env| [302, [ %w(a) ], []] }
564 cl = Clogger.new(app, :logger => s)
565 status, headers, body = cl.call(@req)
566 assert_nil body.close
569 def test_clogger_response_frozen
570 response = [ 200, { "AAAA" => "AAAA"}.freeze, [].freeze ].freeze
572 app = Rack::Builder.new do
573 use Clogger, :logger => s, :format => "$request_time $http_host"
574 run lambda { |env| response }
576 assert_nothing_raised do
578 resp = app.call(@req)
579 assert ! resp.frozen?
580 resp.last.each { |x| }
585 def test_clogger_body_close_return_value
591 app = lambda { |env| [302, [ %w(a) ], body ] }
592 cl = Clogger.new(app, :logger => s)
593 status, headers, body = cl.call(@req)
594 assert_equal :foo, body.close
597 def test_clogger_auto_reentrant_true
600 app = lambda { |env| [302, [ %w(a) ], body ] }
601 cl = Clogger.new(app, :logger => s, :format => "$request_time")
602 @req['rack.multithread'] = true
603 status, headers, body = cl.call(@req)
607 def test_clogger_auto_reentrant_false
610 app = lambda { |env| [302, [ %w(a) ], body ] }
611 cl = Clogger.new(app, :logger => s, :format => "$request_time")
612 @req['rack.multithread'] = false
613 status, headers, body = cl.call(@req)
614 assert ! cl.reentrant?
617 def test_clogger_auto_reentrant_forced_true
620 app = lambda { |env| [302, [ %w(a) ], body ] }
621 o = { :logger => s, :format => "$request_time", :reentrant => true }
622 cl = Clogger.new(app, o)
623 @req['rack.multithread'] = false
624 status, headers, body = cl.call(@req)
628 def test_clogger_auto_reentrant_forced_false
631 app = lambda { |env| [302, [ %w(a) ], body ] }
632 o = { :logger => s, :format => "$request_time", :reentrant => false }
633 cl = Clogger.new(app, o)
634 @req['rack.multithread'] = true
635 status, headers, body = cl.call(@req)
636 assert ! cl.reentrant?
639 def test_invalid_status
642 app = lambda { |env| [ env["force.status"], [ %w(a b) ], body ] }
643 o = { :logger => s, :format => "$status" }
644 cl = Clogger.new(app, o)
645 status, headers, body = cl.call(@req.merge("force.status" => -1))
646 assert_equal -1, status
647 assert_equal "-\n", s.last
648 status, headers, body = cl.call(@req.merge("force.status" => 1000))
649 assert_equal 1000, status
650 assert_equal "-\n", s.last
651 u64_max = 0xffffffffffffffff
652 status, headers, body = cl.call(@req.merge("force.status" => u64_max))
653 assert_equal u64_max, status
654 assert_equal "-\n", s.last
657 # so we don't care about the portability of this test
658 # if it doesn't leak on Linux, it won't leak anywhere else
659 # unless your C compiler or platform is otherwise broken
660 LINUX_PROC_PID_STATUS = "/proc/self/status"
662 app = lambda { |env| [ 0, {}, [] ] }
663 clogger = Clogger.new(app, :logger => $stderr)
664 match_rss = /^VmRSS:\s+(\d+)/
665 if File.read(LINUX_PROC_PID_STATUS) =~ match_rss
667 1000000.times { clogger.dup }
668 File.read(LINUX_PROC_PID_STATUS) =~ match_rss
670 diff = after - before
671 assert(diff < 10000, "memory grew more than 10M: #{diff}")
673 end if RUBY_PLATFORM =~ /linux/ && File.readable?(LINUX_PROC_PID_STATUS)
675 def test_path_open_file
676 tmp = Tempfile.new('test_clogger')
677 app = lambda { |env| [ 200, {}, [] ] }
678 app = Clogger.new(app, :format => '$status', :path => tmp.path)
679 assert_kind_of Integer, app.fileno
680 assert app.fileno != tmp.fileno
681 status, headers, body = app.call(@req)
682 assert_equal "200\n", tmp.read
685 def test_path_logger_conflict
686 tmp = Tempfile.new('test_clogger')
687 app = lambda { |env| [ 200, {}, [] ] }
688 assert_raises(ArgumentError) {
689 Clogger.new(app, :logger=> $stderr, :path => tmp.path)
693 def test_request_time
695 app = lambda { |env| sleep(0.1) ; [302, [], [] ] }
696 cl = Clogger.new(app, :logger => s, :format => "$request_time")
697 status, headers, body = cl.call(@req)
698 assert_nothing_raised { body.each { |x| } ; body.close }
699 assert s[-1].to_f >= 0.100
700 assert s[-1].to_f <= 0.110
703 def test_insanely_long_time_format
705 app = lambda { |env| [200, [], [] ] }
707 expect = Time.now.utc.strftime(fmt) << "\n"
708 assert_equal 100 * 4 + 1, expect.size
709 cl = Clogger.new(app, :logger => s, :format => "$time_utc{#{fmt}}")
710 status, headers, body = cl.call(@req)
711 assert_equal expect, s[0]
716 app = lambda { |env| [200, [], [] ] }
717 cl = Clogger.new(app, :logger => s, :format => "$time_utc")
718 status, headers, body = cl.call(@req)
719 assert %r!\A\d+/\w+/\d{4}:\d\d:\d\d:\d\d \+0000\n\z! =~ s[0], s.inspect
722 def test_time_iso8601
724 app = lambda { |env| [200, [], [] ] }
725 cl = Clogger.new(app, :logger => s, :format => "$time_iso8601")
726 status, headers, body = cl.call(@req)
728 assert_equal t.iso8601, s[0].strip
731 def test_time_iso8601_pst8pdt
732 ENV["TZ"] = "PST8PDT"
734 app = lambda { |env| [200, [], [] ] }
735 cl = Clogger.new(app, :logger => s, :format => "$time_iso8601")
736 status, headers, body = cl.call(@req)
738 assert_equal t.iso8601, s[0].strip
741 def test_time_iso8601_utc
744 app = lambda { |env| [200, [], [] ] }
745 cl = Clogger.new(app, :logger => s, :format => "$time_iso8601")
746 status, headers, body = cl.call(@req)
748 assert_equal t.iso8601, s[0].strip
753 app = lambda { |env| [200, [], [] ] }
754 cl = Clogger.new(app, :logger => s, :format => "$time_local")
755 status, headers, body = cl.call(@req)
756 t = DateTime.strptime(s[0].strip, @nginx_fmt)
757 assert_equal t.strftime(@nginx_fmt), s[0].strip
760 def test_time_local_pst8pdt
762 ENV["TZ"] = "PST8PDT"
764 app = lambda { |env| [200, [], [] ] }
765 cl = Clogger.new(app, :logger => s, :format => "$time_local")
766 status, headers, body = cl.call(@req)
767 t = DateTime.strptime(s[0].strip, @nginx_fmt)
768 assert_equal t.strftime(@nginx_fmt), s[0].strip
771 def test_time_local_utc
774 app = lambda { |env| [200, [], [] ] }
775 cl = Clogger.new(app, :logger => s, :format => "$time_local")
776 status, headers, body = cl.call(@req)
777 t = DateTime.strptime(s[0].strip, @nginx_fmt)
778 assert_equal t.strftime(@nginx_fmt), s[0].strip
781 def test_method_missing
784 def body.foo_bar(foo)
793 app = lambda { |env| [200, [], body ] }
794 cl = Clogger.new(app, :logger => s, :format => '$body_bytes_sent')
795 status, headers, body = cl.call(@req)
796 assert_nothing_raised do
797 body.each { |x| s << x }
800 assert_equal "0\n", s[0], s.inspect
801 assert_kind_of Clogger, body
802 assert_equal %w(1), body.foo_bar(1)
803 assert_equal :hello, body.noargs
804 body.omg { |x| s << x }
805 assert_equal :PONIES, s[1]
806 assert_equal 2, s.size
811 format = '"$request_method ' \
812 '$env{rack.url_scheme}://$http_host$request_uri $http_version"'
813 app = lambda { |env| [200, [], [] ] }
814 cl = Clogger.new(app, :logger => s, :format => format)
815 @req["HTTP_HOST"] = "example.com"
816 status, headers, body = cl.call(@req)
817 expect = "\"GET http://example.com/hello?goodbye=true HTTP/1.0\"\n"
818 assert_equal [ expect ], s