mongrel 1.1.2-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mongrel might be problematic. Click here for more details.

Files changed (73) hide show
  1. data.tar.gz.sig +1 -0
  2. data/CHANGELOG +12 -0
  3. data/COPYING +55 -0
  4. data/LICENSE +55 -0
  5. data/Manifest +69 -0
  6. data/README +74 -0
  7. data/TODO +5 -0
  8. data/bin/mongrel_rails +283 -0
  9. data/examples/builder.rb +29 -0
  10. data/examples/camping/README +3 -0
  11. data/examples/camping/blog.rb +294 -0
  12. data/examples/camping/tepee.rb +149 -0
  13. data/examples/httpd.conf +474 -0
  14. data/examples/mime.yaml +3 -0
  15. data/examples/mongrel.conf +9 -0
  16. data/examples/mongrel_simple_ctrl.rb +92 -0
  17. data/examples/mongrel_simple_service.rb +116 -0
  18. data/examples/monitrc +57 -0
  19. data/examples/random_thrash.rb +19 -0
  20. data/examples/simpletest.rb +52 -0
  21. data/examples/webrick_compare.rb +20 -0
  22. data/ext/http11/ext_help.h +14 -0
  23. data/ext/http11/extconf.rb +6 -0
  24. data/ext/http11/http11.c +402 -0
  25. data/ext/http11/http11_parser.c +1221 -0
  26. data/ext/http11/http11_parser.h +49 -0
  27. data/ext/http11/http11_parser.java.rl +170 -0
  28. data/ext/http11/http11_parser.rl +152 -0
  29. data/ext/http11/http11_parser_common.rl +54 -0
  30. data/ext/http11_java/Http11Service.java +13 -0
  31. data/ext/http11_java/org/jruby/mongrel/Http11.java +266 -0
  32. data/ext/http11_java/org/jruby/mongrel/Http11Parser.java +572 -0
  33. data/lib/http11.jar +0 -0
  34. data/lib/mongrel.rb +355 -0
  35. data/lib/mongrel/camping.rb +107 -0
  36. data/lib/mongrel/cgi.rb +181 -0
  37. data/lib/mongrel/command.rb +222 -0
  38. data/lib/mongrel/configurator.rb +388 -0
  39. data/lib/mongrel/const.rb +110 -0
  40. data/lib/mongrel/debug.rb +203 -0
  41. data/lib/mongrel/gems.rb +22 -0
  42. data/lib/mongrel/handlers.rb +468 -0
  43. data/lib/mongrel/header_out.rb +28 -0
  44. data/lib/mongrel/http_request.rb +155 -0
  45. data/lib/mongrel/http_response.rb +163 -0
  46. data/lib/mongrel/init.rb +10 -0
  47. data/lib/mongrel/mime_types.yml +616 -0
  48. data/lib/mongrel/rails.rb +185 -0
  49. data/lib/mongrel/stats.rb +89 -0
  50. data/lib/mongrel/tcphack.rb +18 -0
  51. data/lib/mongrel/uri_classifier.rb +76 -0
  52. data/mongrel-public_cert.pem +20 -0
  53. data/mongrel.gemspec +263 -0
  54. data/setup.rb +1585 -0
  55. data/test/mime.yaml +3 -0
  56. data/test/mongrel.conf +1 -0
  57. data/test/test_cgi_wrapper.rb +26 -0
  58. data/test/test_command.rb +86 -0
  59. data/test/test_conditional.rb +107 -0
  60. data/test/test_configurator.rb +87 -0
  61. data/test/test_debug.rb +25 -0
  62. data/test/test_handlers.rb +103 -0
  63. data/test/test_http11.rb +156 -0
  64. data/test/test_redirect_handler.rb +44 -0
  65. data/test/test_request_progress.rb +99 -0
  66. data/test/test_response.rb +127 -0
  67. data/test/test_stats.rb +35 -0
  68. data/test/test_uriclassifier.rb +261 -0
  69. data/test/test_ws.rb +115 -0
  70. data/test/testhelp.rb +66 -0
  71. data/tools/trickletest.rb +45 -0
  72. metadata +186 -0
  73. metadata.gz.sig +4 -0
@@ -0,0 +1,156 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ include Mongrel
10
+
11
+ class HttpParserTest < Test::Unit::TestCase
12
+
13
+ def test_parse_simple
14
+ parser = HttpParser.new
15
+ req = {}
16
+ http = "GET / HTTP/1.1\r\n\r\n"
17
+ nread = parser.execute(req, http, 0)
18
+
19
+ assert nread == http.length, "Failed to parse the full HTTP request"
20
+ assert parser.finished?, "Parser didn't finish"
21
+ assert !parser.error?, "Parser had error"
22
+ assert nread == parser.nread, "Number read returned from execute does not match"
23
+
24
+ assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL']
25
+ assert_equal '/', req['REQUEST_PATH']
26
+ assert_equal 'HTTP/1.1', req['HTTP_VERSION']
27
+ assert_equal '/', req['REQUEST_URI']
28
+ assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE']
29
+ assert_equal 'GET', req['REQUEST_METHOD']
30
+ assert_nil req['FRAGMENT']
31
+ assert_nil req['QUERY_STRING']
32
+
33
+ parser.reset
34
+ assert parser.nread == 0, "Number read after reset should be 0"
35
+ end
36
+
37
+ def test_parse_dumbfuck_headers
38
+ parser = HttpParser.new
39
+ req = {}
40
+ should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
41
+ nread = parser.execute(req, should_be_good, 0)
42
+ assert_equal should_be_good.length, nread
43
+ assert parser.finished?
44
+ assert !parser.error?
45
+
46
+ nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n"
47
+ parser = HttpParser.new
48
+ req = {}
49
+ #nread = parser.execute(req, nasty_pound_header, 0)
50
+ #assert_equal nasty_pound_header.length, nread
51
+ #assert parser.finished?
52
+ #assert !parser.error?
53
+ end
54
+
55
+ def test_parse_error
56
+ parser = HttpParser.new
57
+ req = {}
58
+ bad_http = "GET / SsUTF/1.1"
59
+
60
+ error = false
61
+ begin
62
+ nread = parser.execute(req, bad_http, 0)
63
+ rescue => details
64
+ error = true
65
+ end
66
+
67
+ assert error, "failed to throw exception"
68
+ assert !parser.finished?, "Parser shouldn't be finished"
69
+ assert parser.error?, "Parser SHOULD have error"
70
+ end
71
+
72
+ def test_fragment_in_uri
73
+ parser = HttpParser.new
74
+ req = {}
75
+ get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
76
+ assert_nothing_raised do
77
+ parser.execute(req, get, 0)
78
+ end
79
+ assert parser.finished?
80
+ assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
81
+ assert_equal 'posts-17408', req['FRAGMENT']
82
+ end
83
+
84
+ # lame random garbage maker
85
+ def rand_data(min, max, readable=true)
86
+ count = min + ((rand(max)+1) *10).to_i
87
+ res = count.to_s + "/"
88
+
89
+ if readable
90
+ res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
91
+ else
92
+ res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
93
+ end
94
+
95
+ return res
96
+ end
97
+
98
+
99
+ def test_horrible_queries
100
+ parser = HttpParser.new
101
+
102
+ # then that large header names are caught
103
+ 10.times do |c|
104
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
105
+ assert_raises Mongrel::HttpParserError do
106
+ parser.execute({}, get, 0)
107
+ parser.reset
108
+ end
109
+ end
110
+
111
+ # then that large mangled field values are caught
112
+ 10.times do |c|
113
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
114
+ assert_raises Mongrel::HttpParserError do
115
+ parser.execute({}, get, 0)
116
+ parser.reset
117
+ end
118
+ end
119
+
120
+ # then large headers are rejected too
121
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
122
+ get << "X-Test: test\r\n" * (80 * 1024)
123
+ assert_raises Mongrel::HttpParserError do
124
+ parser.execute({}, get, 0)
125
+ parser.reset
126
+ end
127
+
128
+ # finally just that random garbage gets blocked all the time
129
+ 10.times do |c|
130
+ get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
131
+ assert_raises Mongrel::HttpParserError do
132
+ parser.execute({}, get, 0)
133
+ parser.reset
134
+ end
135
+ end
136
+
137
+ end
138
+
139
+
140
+
141
+ def test_query_parse
142
+ res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}")
143
+ assert res["zed"], "didn't get the request right"
144
+ assert res["frank"], "no frank"
145
+ assert_equal "1", res["zed"], "wrong result"
146
+ assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result"
147
+
148
+ res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45")
149
+ assert res["zed"], "didn't get the request right"
150
+ assert res["frank"], "no frank"
151
+ assert_equal 4,res["zed"].length, "wrong number for zed"
152
+ assert_equal "11",res["frank"], "wrong number for frank"
153
+ end
154
+
155
+ end
156
+
@@ -0,0 +1,44 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ class RedirectHandlerTest < Test::Unit::TestCase
10
+
11
+ def setup
12
+ redirect_test_io do
13
+ @server = Mongrel::HttpServer.new('127.0.0.1', 9998)
14
+ end
15
+ @server.run
16
+ @client = Net::HTTP.new('127.0.0.1', 9998)
17
+ end
18
+
19
+ def teardown
20
+ @server.stop(true)
21
+ end
22
+
23
+ def test_simple_redirect
24
+ tester = Mongrel::RedirectHandler.new('/yo')
25
+ @server.register("/test", tester)
26
+
27
+ sleep(1)
28
+ res = @client.request_get('/test')
29
+ assert res != nil, "Didn't get a response"
30
+ assert_equal ['/yo'], res.get_fields('Location')
31
+ end
32
+
33
+ def test_rewrite
34
+ tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+')
35
+ @server.register("/test", tester)
36
+
37
+ sleep(1)
38
+ res = @client.request_get('/test/something')
39
+ assert_equal ['/+test+/+something+'], res.get_fields('Location')
40
+ end
41
+
42
+ end
43
+
44
+
@@ -0,0 +1,99 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ class UploadBeginHandler < Mongrel::HttpHandler
10
+ attr_reader :request_began, :request_progressed, :request_processed
11
+
12
+ def initialize
13
+ @request_notify = true
14
+ end
15
+
16
+ def reset
17
+ @request_began = false
18
+ @request_progressed = false
19
+ @request_processed = false
20
+ end
21
+
22
+ def request_begins(params)
23
+ @request_began = true
24
+ end
25
+
26
+ def request_progress(params,len,total)
27
+ @request_progressed = true
28
+ end
29
+
30
+ def process(request, response)
31
+ @request_processed = true
32
+ response.start do |head,body|
33
+ body.write("test")
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ class RequestProgressTest < Test::Unit::TestCase
40
+ def setup
41
+ redirect_test_io do
42
+ @server = Mongrel::HttpServer.new("127.0.0.1", 9998)
43
+ end
44
+ @handler = UploadBeginHandler.new
45
+ @server.register("/upload", @handler)
46
+ @server.run
47
+ end
48
+
49
+ def teardown
50
+ @server.stop(true)
51
+ end
52
+
53
+ def test_begin_end_progress
54
+ Net::HTTP.get("localhost", "/upload", 9998)
55
+ assert @handler.request_began
56
+ assert @handler.request_progressed
57
+ assert @handler.request_processed
58
+ end
59
+
60
+ def call_and_assert_handlers_in_turn(handlers)
61
+ # reset all handlers
62
+ handlers.each { |h| h.reset }
63
+
64
+ # make the call
65
+ Net::HTTP.get("localhost", "/upload", 9998)
66
+
67
+ # assert that each one was fired
68
+ handlers.each { |h|
69
+ assert h.request_began && h.request_progressed && h.request_processed,
70
+ "Callbacks NOT fired for #{h}"
71
+ }
72
+ end
73
+
74
+ def test_more_than_one_begin_end_progress
75
+ handlers = [@handler]
76
+
77
+ second = UploadBeginHandler.new
78
+ @server.register("/upload", second)
79
+ handlers << second
80
+ call_and_assert_handlers_in_turn(handlers)
81
+
82
+ # check three handlers
83
+ third = UploadBeginHandler.new
84
+ @server.register("/upload", third)
85
+ handlers << third
86
+ call_and_assert_handlers_in_turn(handlers)
87
+
88
+ # remove handlers to make sure they've all gone away
89
+ @server.unregister("/upload")
90
+ handlers.each { |h| h.reset }
91
+ Net::HTTP.get("localhost", "/upload", 9998)
92
+ handlers.each { |h|
93
+ assert !h.request_began && !h.request_progressed && !h.request_processed
94
+ }
95
+
96
+ # re-register upload to the state before this test
97
+ @server.register("/upload", @handler)
98
+ end
99
+ end
@@ -0,0 +1,127 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ include Mongrel
10
+
11
+ class ResponseTest < Test::Unit::TestCase
12
+
13
+ def test_response_headers
14
+ out = StringIO.new
15
+ resp = HttpResponse.new(out)
16
+ resp.status = 200
17
+ resp.header["Accept"] = "text/plain"
18
+ resp.header["X-Whatever"] = "stuff"
19
+ resp.body.write("test")
20
+ resp.finished
21
+
22
+ assert out.length > 0, "output didn't have data"
23
+ end
24
+
25
+ def test_response_200
26
+ io = StringIO.new
27
+ resp = HttpResponse.new(io)
28
+ resp.start do |head,out|
29
+ head["Accept"] = "text/plain"
30
+ out.write("tested")
31
+ out.write("hello!")
32
+ end
33
+
34
+ resp.finished
35
+ assert io.length > 0, "output didn't have data"
36
+ end
37
+
38
+ def test_response_duplicate_header_squash
39
+ io = StringIO.new
40
+ resp = HttpResponse.new(io)
41
+ resp.start do |head,out|
42
+ head["Content-Length"] = 30
43
+ head["Content-Length"] = 0
44
+ end
45
+
46
+ resp.finished
47
+
48
+ assert_equal io.length, 95, "too much output"
49
+ end
50
+
51
+
52
+ def test_response_some_duplicates_allowed
53
+ allowed_duplicates = ["Set-Cookie", "Set-Cookie2", "Warning", "WWW-Authenticate"]
54
+ io = StringIO.new
55
+ resp = HttpResponse.new(io)
56
+ resp.start do |head,out|
57
+ allowed_duplicates.each do |dup|
58
+ 10.times do |i|
59
+ head[dup] = i
60
+ end
61
+ end
62
+ end
63
+
64
+ resp.finished
65
+
66
+ assert_equal io.length, 734, "wrong amount of output"
67
+ end
68
+
69
+ def test_response_404
70
+ io = StringIO.new
71
+
72
+ resp = HttpResponse.new(io)
73
+ resp.start(404) do |head,out|
74
+ head['Accept'] = "text/plain"
75
+ out.write("NOT FOUND")
76
+ end
77
+
78
+ resp.finished
79
+ assert io.length > 0, "output didn't have data"
80
+ end
81
+
82
+ def test_response_file
83
+ contents = "PLAIN TEXT\r\nCONTENTS\r\n"
84
+ require 'tempfile'
85
+ tmpf = Tempfile.new("test_response_file")
86
+ tmpf.binmode
87
+ tmpf.write(contents)
88
+ tmpf.rewind
89
+
90
+ io = StringIO.new
91
+ resp = HttpResponse.new(io)
92
+ resp.start(200) do |head,out|
93
+ head['Content-Type'] = 'text/plain'
94
+ resp.send_header
95
+ resp.send_file(tmpf.path)
96
+ end
97
+ io.rewind
98
+ tmpf.close
99
+
100
+ assert io.length > 0, "output didn't have data"
101
+ assert io.read[-contents.length..-1] == contents, "output doesn't end with file payload"
102
+ end
103
+
104
+ def test_response_with_custom_reason
105
+ reason = "You made a bad request"
106
+ io = StringIO.new
107
+ resp = HttpResponse.new(io)
108
+ resp.start(400, false, reason) { |head,out| }
109
+ resp.finished
110
+
111
+ io.rewind
112
+ assert_match(/.* #{reason}$/, io.readline.chomp, "wrong custom reason phrase")
113
+ end
114
+
115
+ def test_response_with_default_reason
116
+ code = 400
117
+ io = StringIO.new
118
+ resp = HttpResponse.new(io)
119
+ resp.start(code) { |head,out| }
120
+ resp.finished
121
+
122
+ io.rewind
123
+ assert_match(/.* #{HTTP_STATUS_CODES[code]}$/, io.readline.chomp, "wrong default reason phrase")
124
+ end
125
+
126
+ end
127
+
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'test/testhelp'
8
+
9
+ class StatsTest < Test::Unit::TestCase
10
+
11
+ def test_sampling_speed
12
+ out = StringIO.new
13
+
14
+ s = Mongrel::Stats.new("test")
15
+ t = Mongrel::Stats.new("time")
16
+
17
+ 100.times { s.sample(rand(20)); t.tick }
18
+
19
+ s.dump("FIRST", out)
20
+ t.dump("FIRST", out)
21
+
22
+ old_mean = s.mean
23
+ old_sd = s.sd
24
+
25
+ s.reset
26
+ t.reset
27
+ 100.times { s.sample(rand(30)); t.tick }
28
+
29
+ s.dump("SECOND", out)
30
+ t.dump("SECOND", out)
31
+ assert_not_equal old_mean, s.mean
32
+ assert_not_equal old_mean, s.sd
33
+ end
34
+
35
+ end