ww 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +3 -3
- data/example/spy_eye.ru +14 -0
- data/example/spy_eye_output.html +336 -0
- data/lib/ww/application.rb +26 -0
- data/lib/ww/server.rb +80 -0
- data/lib/ww/spy_eye.rb +16 -0
- data/lib/ww.rb +10 -16
- data/spec/spec_helper.rb +4 -0
- data/spec/ww/application_spec.rb +35 -0
- data/spec/ww/double_spec.rb +144 -0
- data/spec/ww/double_spy_request_spec.rb +74 -0
- data/spec/ww/server_integration_spec.rb +73 -0
- data/spec/ww/server_spec.rb +39 -0
- data/spec/ww/servlet_spec.rb +24 -0
- metadata +13 -2
data/Rakefile
CHANGED
@@ -62,9 +62,9 @@ spec = Gem::Specification.new do |s|
|
|
62
62
|
#s.required_ruby_version = '>= 1.8.2'
|
63
63
|
|
64
64
|
s.files = %w(Rakefile) +
|
65
|
-
Dir.glob("{bin,doc,
|
65
|
+
Dir.glob("{bin,doc,spec,lib,templates,generator,extras,website,script}/**/*") +
|
66
66
|
Dir.glob("ext/**/*.{h,c,rb}") +
|
67
|
-
Dir.glob("
|
67
|
+
Dir.glob("example/**/*") +
|
68
68
|
Dir.glob("tools/*.rb") +
|
69
69
|
Dir.glob("rails/*.rb")
|
70
70
|
|
@@ -79,7 +79,7 @@ end
|
|
79
79
|
task :install do
|
80
80
|
name = "#{NAME}-#{VERS}.gem"
|
81
81
|
sh %{rake package}
|
82
|
-
sh %{gem install pkg/#{name}}
|
82
|
+
sh %{gem install --no-rdoc --no-ri pkg/#{name}}
|
83
83
|
end
|
84
84
|
|
85
85
|
task :uninstall => [:clean] do
|
data/example/spy_eye.ru
ADDED
@@ -0,0 +1,336 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>3 requests - Double Web</title>
|
5
|
+
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js'></script>
|
6
|
+
<style type='text/css'>
|
7
|
+
body {
|
8
|
+
width: 80%;
|
9
|
+
margin: auto; }
|
10
|
+
|
11
|
+
h1 {
|
12
|
+
font-size: 10px; }
|
13
|
+
|
14
|
+
div.stump {
|
15
|
+
font-size: 10px;
|
16
|
+
border: 1px solid silver;
|
17
|
+
padding: 0 1em; }
|
18
|
+
div.stump h2 {
|
19
|
+
font-size: 10px;
|
20
|
+
color: gray; }
|
21
|
+
div.stump h2 span.method, div.stump h2 span.path {
|
22
|
+
font-size: 16px;
|
23
|
+
font-weight: normal;
|
24
|
+
font-family: 'Courier', monospace; }
|
25
|
+
div.stump h2 span.method {
|
26
|
+
color: #090; }
|
27
|
+
div.stump h2 span.path {
|
28
|
+
color: black; }
|
29
|
+
div.stump h2 span.time, div.stump h2 span.source {
|
30
|
+
color: blue; }
|
31
|
+
div.stump h3 {
|
32
|
+
font-size: small;
|
33
|
+
border-bottom: 1px solid green;
|
34
|
+
background: #cfb;
|
35
|
+
padding: 2px 0 0 2px; }
|
36
|
+
div.stump h3 span.media_type {
|
37
|
+
color: blue;
|
38
|
+
font-size: small;
|
39
|
+
font-weight: normal;
|
40
|
+
font-family: 'Courier', monospace; }
|
41
|
+
div.stump .headers table, div.stump div.body pre {
|
42
|
+
border: 1px dashed green;
|
43
|
+
margin: 1em;
|
44
|
+
padding: 1em; }
|
45
|
+
div.stump div.body pre {
|
46
|
+
overflow: auto;
|
47
|
+
font-size: 12px; }
|
48
|
+
</style>
|
49
|
+
</head>
|
50
|
+
<body>
|
51
|
+
<h1>3 requests - Double Web</h1>
|
52
|
+
<div class='stump' id='13699160'>
|
53
|
+
<h2>
|
54
|
+
<span class='method'>POST</span>
|
55
|
+
<span class='path'>/hello</span>
|
56
|
+
on
|
57
|
+
<span class='time'>2010-01-16T23:57:01+09:00</span>
|
58
|
+
from
|
59
|
+
<span class='source'>127.0.0.1</span>
|
60
|
+
</h2>
|
61
|
+
<div>
|
62
|
+
<div class='headers'>
|
63
|
+
<h3>Headers</h3>
|
64
|
+
<table>
|
65
|
+
<tr>
|
66
|
+
<th>HTTP_ACCEPT</th>
|
67
|
+
<td>*/*</td>
|
68
|
+
</tr>
|
69
|
+
<tr>
|
70
|
+
<th>HTTP_HOST</th>
|
71
|
+
<td>localhost:8888</td>
|
72
|
+
</tr>
|
73
|
+
<tr>
|
74
|
+
<th>SERVER_NAME</th>
|
75
|
+
<td>localhost</td>
|
76
|
+
</tr>
|
77
|
+
<tr>
|
78
|
+
<th>CONTENT_LENGTH</th>
|
79
|
+
<td>28</td>
|
80
|
+
</tr>
|
81
|
+
<tr>
|
82
|
+
<th>HTTP_USER_AGENT</th>
|
83
|
+
<td>curl/7.19.5 (i386-apple-darwin9.7.0) libcurl/7.19.5 OpenSSL/0.9.8k zlib/1.2.3</td>
|
84
|
+
</tr>
|
85
|
+
<tr>
|
86
|
+
<th>REQUEST_PATH</th>
|
87
|
+
<td>/hello</td>
|
88
|
+
</tr>
|
89
|
+
<tr>
|
90
|
+
<th>SERVER_PROTOCOL</th>
|
91
|
+
<td>HTTP/1.1</td>
|
92
|
+
</tr>
|
93
|
+
<tr>
|
94
|
+
<th>CONTENT_TYPE</th>
|
95
|
+
<td>application/x-www-form-urlencoded</td>
|
96
|
+
</tr>
|
97
|
+
<tr>
|
98
|
+
<th>REMOTE_ADDR</th>
|
99
|
+
<td>127.0.0.1</td>
|
100
|
+
</tr>
|
101
|
+
<tr>
|
102
|
+
<th>PATH_INFO</th>
|
103
|
+
<td>/hello</td>
|
104
|
+
</tr>
|
105
|
+
<tr>
|
106
|
+
<th>SERVER_SOFTWARE</th>
|
107
|
+
<td>thin 1.2.5 codename This Is Not A Web Server</td>
|
108
|
+
</tr>
|
109
|
+
<tr>
|
110
|
+
<th>SCRIPT_NAME</th>
|
111
|
+
<td></td>
|
112
|
+
</tr>
|
113
|
+
<tr>
|
114
|
+
<th>HTTP_VERSION</th>
|
115
|
+
<td>HTTP/1.1</td>
|
116
|
+
</tr>
|
117
|
+
<tr>
|
118
|
+
<th>REQUEST_URI</th>
|
119
|
+
<td>/hello</td>
|
120
|
+
</tr>
|
121
|
+
<tr>
|
122
|
+
<th>SERVER_PORT</th>
|
123
|
+
<td>8888</td>
|
124
|
+
</tr>
|
125
|
+
<tr>
|
126
|
+
<th>REQUEST_METHOD</th>
|
127
|
+
<td>POST</td>
|
128
|
+
</tr>
|
129
|
+
<tr>
|
130
|
+
<th>QUERY_STRING</th>
|
131
|
+
<td></td>
|
132
|
+
</tr>
|
133
|
+
<tr>
|
134
|
+
<th>GATEWAY_INTERFACE</th>
|
135
|
+
<td>CGI/1.2</td>
|
136
|
+
</tr>
|
137
|
+
</table>
|
138
|
+
</div>
|
139
|
+
<div class='body'>
|
140
|
+
<h3>
|
141
|
+
Body
|
142
|
+
<span class='media_type'>application/x-www-form-urlencoded</span>
|
143
|
+
</h3>
|
144
|
+
<pre>{"message"=>"How are you?", "key"=>"2nd"}</pre>
|
145
|
+
</div>
|
146
|
+
</div>
|
147
|
+
</div>
|
148
|
+
<div class='stump' id='13730530'>
|
149
|
+
<h2>
|
150
|
+
<span class='method'>POST</span>
|
151
|
+
<span class='path'>/hello</span>
|
152
|
+
on
|
153
|
+
<span class='time'>2010-01-16T23:57:01+09:00</span>
|
154
|
+
from
|
155
|
+
<span class='source'>127.0.0.1</span>
|
156
|
+
</h2>
|
157
|
+
<div>
|
158
|
+
<div class='headers'>
|
159
|
+
<h3>Headers</h3>
|
160
|
+
<table>
|
161
|
+
<tr>
|
162
|
+
<th>HTTP_ACCEPT</th>
|
163
|
+
<td>*/*</td>
|
164
|
+
</tr>
|
165
|
+
<tr>
|
166
|
+
<th>HTTP_HOST</th>
|
167
|
+
<td>localhost:8888</td>
|
168
|
+
</tr>
|
169
|
+
<tr>
|
170
|
+
<th>SERVER_NAME</th>
|
171
|
+
<td>localhost</td>
|
172
|
+
</tr>
|
173
|
+
<tr>
|
174
|
+
<th>CONTENT_LENGTH</th>
|
175
|
+
<td>27</td>
|
176
|
+
</tr>
|
177
|
+
<tr>
|
178
|
+
<th>HTTP_USER_AGENT</th>
|
179
|
+
<td>curl/7.19.5 (i386-apple-darwin9.7.0) libcurl/7.19.5 OpenSSL/0.9.8k zlib/1.2.3</td>
|
180
|
+
</tr>
|
181
|
+
<tr>
|
182
|
+
<th>REQUEST_PATH</th>
|
183
|
+
<td>/hello</td>
|
184
|
+
</tr>
|
185
|
+
<tr>
|
186
|
+
<th>SERVER_PROTOCOL</th>
|
187
|
+
<td>HTTP/1.1</td>
|
188
|
+
</tr>
|
189
|
+
<tr>
|
190
|
+
<th>CONTENT_TYPE</th>
|
191
|
+
<td>application/x-www-form-urlencoded</td>
|
192
|
+
</tr>
|
193
|
+
<tr>
|
194
|
+
<th>REMOTE_ADDR</th>
|
195
|
+
<td>127.0.0.1</td>
|
196
|
+
</tr>
|
197
|
+
<tr>
|
198
|
+
<th>PATH_INFO</th>
|
199
|
+
<td>/hello</td>
|
200
|
+
</tr>
|
201
|
+
<tr>
|
202
|
+
<th>SERVER_SOFTWARE</th>
|
203
|
+
<td>thin 1.2.5 codename This Is Not A Web Server</td>
|
204
|
+
</tr>
|
205
|
+
<tr>
|
206
|
+
<th>SCRIPT_NAME</th>
|
207
|
+
<td></td>
|
208
|
+
</tr>
|
209
|
+
<tr>
|
210
|
+
<th>HTTP_VERSION</th>
|
211
|
+
<td>HTTP/1.1</td>
|
212
|
+
</tr>
|
213
|
+
<tr>
|
214
|
+
<th>REQUEST_URI</th>
|
215
|
+
<td>/hello</td>
|
216
|
+
</tr>
|
217
|
+
<tr>
|
218
|
+
<th>SERVER_PORT</th>
|
219
|
+
<td>8888</td>
|
220
|
+
</tr>
|
221
|
+
<tr>
|
222
|
+
<th>REQUEST_METHOD</th>
|
223
|
+
<td>POST</td>
|
224
|
+
</tr>
|
225
|
+
<tr>
|
226
|
+
<th>QUERY_STRING</th>
|
227
|
+
<td></td>
|
228
|
+
</tr>
|
229
|
+
<tr>
|
230
|
+
<th>GATEWAY_INTERFACE</th>
|
231
|
+
<td>CGI/1.2</td>
|
232
|
+
</tr>
|
233
|
+
</table>
|
234
|
+
</div>
|
235
|
+
<div class='body'>
|
236
|
+
<h3>
|
237
|
+
Body
|
238
|
+
<span class='media_type'>application/x-www-form-urlencoded</span>
|
239
|
+
</h3>
|
240
|
+
<pre>{"message"=>"KON-NICHIWA", "key"=>"1st"}</pre>
|
241
|
+
</div>
|
242
|
+
</div>
|
243
|
+
</div>
|
244
|
+
<div class='stump' id='13760510'>
|
245
|
+
<h2>
|
246
|
+
<span class='method'>GET</span>
|
247
|
+
<span class='path'>/hello</span>
|
248
|
+
on
|
249
|
+
<span class='time'>2010-01-16T23:57:01+09:00</span>
|
250
|
+
from
|
251
|
+
<span class='source'>127.0.0.1</span>
|
252
|
+
</h2>
|
253
|
+
<div>
|
254
|
+
<div class='headers'>
|
255
|
+
<h3>Headers</h3>
|
256
|
+
<table>
|
257
|
+
<tr>
|
258
|
+
<th>HTTP_ACCEPT</th>
|
259
|
+
<td>*/*</td>
|
260
|
+
</tr>
|
261
|
+
<tr>
|
262
|
+
<th>HTTP_HOST</th>
|
263
|
+
<td>localhost:8888</td>
|
264
|
+
</tr>
|
265
|
+
<tr>
|
266
|
+
<th>SERVER_NAME</th>
|
267
|
+
<td>localhost</td>
|
268
|
+
</tr>
|
269
|
+
<tr>
|
270
|
+
<th>HTTP_USER_AGENT</th>
|
271
|
+
<td>curl/7.19.5 (i386-apple-darwin9.7.0) libcurl/7.19.5 OpenSSL/0.9.8k zlib/1.2.3</td>
|
272
|
+
</tr>
|
273
|
+
<tr>
|
274
|
+
<th>REQUEST_PATH</th>
|
275
|
+
<td>/hello</td>
|
276
|
+
</tr>
|
277
|
+
<tr>
|
278
|
+
<th>SERVER_PROTOCOL</th>
|
279
|
+
<td>HTTP/1.1</td>
|
280
|
+
</tr>
|
281
|
+
<tr>
|
282
|
+
<th>REMOTE_ADDR</th>
|
283
|
+
<td>127.0.0.1</td>
|
284
|
+
</tr>
|
285
|
+
<tr>
|
286
|
+
<th>PATH_INFO</th>
|
287
|
+
<td>/hello</td>
|
288
|
+
</tr>
|
289
|
+
<tr>
|
290
|
+
<th>SERVER_SOFTWARE</th>
|
291
|
+
<td>thin 1.2.5 codename This Is Not A Web Server</td>
|
292
|
+
</tr>
|
293
|
+
<tr>
|
294
|
+
<th>SCRIPT_NAME</th>
|
295
|
+
<td></td>
|
296
|
+
</tr>
|
297
|
+
<tr>
|
298
|
+
<th>HTTP_VERSION</th>
|
299
|
+
<td>HTTP/1.1</td>
|
300
|
+
</tr>
|
301
|
+
<tr>
|
302
|
+
<th>REQUEST_URI</th>
|
303
|
+
<td>/hello</td>
|
304
|
+
</tr>
|
305
|
+
<tr>
|
306
|
+
<th>SERVER_PORT</th>
|
307
|
+
<td>8888</td>
|
308
|
+
</tr>
|
309
|
+
<tr>
|
310
|
+
<th>REQUEST_METHOD</th>
|
311
|
+
<td>GET</td>
|
312
|
+
</tr>
|
313
|
+
<tr>
|
314
|
+
<th>QUERY_STRING</th>
|
315
|
+
<td></td>
|
316
|
+
</tr>
|
317
|
+
<tr>
|
318
|
+
<th>GATEWAY_INTERFACE</th>
|
319
|
+
<td>CGI/1.2</td>
|
320
|
+
</tr>
|
321
|
+
</table>
|
322
|
+
</div>
|
323
|
+
</div>
|
324
|
+
</div>
|
325
|
+
</body>
|
326
|
+
</html>
|
327
|
+
<script type='text/javascript'>
|
328
|
+
//<![CDATA[
|
329
|
+
jQuery(function(){
|
330
|
+
$("div.stump .headers h3").click(function(){ $(this).next("table").toggle() });
|
331
|
+
$("div.stump .body h3").click(function(){ $(this).next("pre").toggle() });
|
332
|
+
$("div.stump .headers table").hide();
|
333
|
+
$("div.stump .body pre").hide();
|
334
|
+
});
|
335
|
+
//]]>
|
336
|
+
</script>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ww/servlet'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Ww
|
5
|
+
class Application
|
6
|
+
attr_reader :current
|
7
|
+
|
8
|
+
def initialize(&servlet_initializer)
|
9
|
+
@servlet_initializer = servlet_initializer
|
10
|
+
reset!
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
current.call(env)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset!
|
18
|
+
@current = build_servlet
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def build_servlet
|
23
|
+
Servlet.base(&@servlet_initializer)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/ww/server.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'ww/double'
|
4
|
+
|
5
|
+
module Ww
|
6
|
+
autoload :Application, 'ww/application'
|
7
|
+
class Server
|
8
|
+
extend Forwardable
|
9
|
+
@@servers = {}
|
10
|
+
@@handler = :webrick
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def servers; @@servers; end
|
14
|
+
|
15
|
+
def handler; @@handler; end
|
16
|
+
def handler=(v); @@handler = v; end
|
17
|
+
|
18
|
+
def [](name); @@servers[name] ; end
|
19
|
+
def []=(name, server); @@servers[name] = server ; end
|
20
|
+
|
21
|
+
def build_double(port, &block)
|
22
|
+
new(Application.new(&block), port)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def_delegators :current_app, *double_methods = %w[
|
27
|
+
spy requests mock verify stub
|
28
|
+
]
|
29
|
+
|
30
|
+
attr_reader :app, :port
|
31
|
+
|
32
|
+
def initialize(app, port)
|
33
|
+
@app = app
|
34
|
+
@port = port
|
35
|
+
@handler = ::Rack::Handler.get(self.class.handler)
|
36
|
+
end
|
37
|
+
|
38
|
+
def start_once
|
39
|
+
@app.reset!
|
40
|
+
start! unless running?
|
41
|
+
end
|
42
|
+
|
43
|
+
def running?; !!@running ; end
|
44
|
+
|
45
|
+
def start!
|
46
|
+
run_with_picking_server_instance!
|
47
|
+
@running = true
|
48
|
+
at_exit { shutdown! }
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def shutdown!
|
53
|
+
return unless @running
|
54
|
+
shutdown_http_server
|
55
|
+
@thread.kill if @thread.alive?
|
56
|
+
@running = false
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def run_with_picking_server_instance!
|
62
|
+
q = Queue.new
|
63
|
+
@thread = Thread.new { @handler.run(@app, :Port => @port) {|server| q << server } }
|
64
|
+
@server = q.pop
|
65
|
+
end
|
66
|
+
|
67
|
+
def shutdown_http_server
|
68
|
+
case @server.class.name
|
69
|
+
when "WEBrick::HTTPServer" then @server.shutdown
|
70
|
+
when "Thin::Server", "Mongrel::HttpServer" then @server.stop
|
71
|
+
else
|
72
|
+
@server.stop if @server.respond_to? :stop
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def current_app
|
77
|
+
app.current
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/ww/spy_eye.rb
CHANGED
@@ -1,9 +1,25 @@
|
|
1
|
+
require 'rack'
|
1
2
|
require 'forwardable'
|
2
3
|
require 'time'
|
3
4
|
require 'haml'
|
4
5
|
|
5
6
|
module Ww
|
7
|
+
autoload :Servlet, 'ww/servlet'
|
6
8
|
class SpyEye
|
9
|
+
class << self
|
10
|
+
def to_app(spy_eye_path = "/spy", &block)
|
11
|
+
Rack::Builder.new {
|
12
|
+
use Rack::ShowExceptions
|
13
|
+
|
14
|
+
servlet = Servlet.base(&block)
|
15
|
+
spy = SpyEye.new(servlet)
|
16
|
+
|
17
|
+
map(spy_eye_path) { run spy }
|
18
|
+
map("/") { run servlet }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
7
23
|
extend Forwardable
|
8
24
|
def_delegator :@servlet, :requests
|
9
25
|
|
data/lib/ww.rb
CHANGED
@@ -1,22 +1,16 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rack'
|
3
|
-
|
4
1
|
module Ww
|
5
|
-
|
6
|
-
autoload :SpyEye, 'ww/spy_eye'
|
7
|
-
|
8
|
-
Version = '0.2.1'
|
9
|
-
|
10
|
-
def to_app(spy_eye_path = "/spy", &block)
|
11
|
-
Rack::Builder.new {
|
12
|
-
use Rack::ShowExceptions
|
2
|
+
Version = '0.3.0'
|
13
3
|
|
14
|
-
|
15
|
-
|
4
|
+
def to_app(*args, &block)
|
5
|
+
$stderr.puts <<-WORNING
|
6
|
+
*** DUPLICATION WORNING ***
|
7
|
+
Ww.to_app moves to Ww::SpyEye.to_app
|
16
8
|
|
17
|
-
|
18
|
-
|
19
|
-
|
9
|
+
This comatibility will be lost on 0.4.0.
|
10
|
+
***************************
|
11
|
+
WORNING
|
12
|
+
require 'ww/spy_eye'
|
13
|
+
Ww::SpyEye.to_app(*args, &block)
|
20
14
|
end
|
21
15
|
module_function :to_app
|
22
16
|
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require 'ww/application'
|
3
|
+
|
4
|
+
describe Ww::Application do
|
5
|
+
before do
|
6
|
+
@container = Ww::Application.new do
|
7
|
+
get("/hello") do
|
8
|
+
"Hello World"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
@client = Rack::MockRequest.new(@container)
|
13
|
+
end
|
14
|
+
subject { @client.get("/hello") }
|
15
|
+
|
16
|
+
describe "GET /hello" do
|
17
|
+
its(:status) { should == 200 }
|
18
|
+
its(:body) { should == "Hello World" }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "GET /hello (stubbed)" do
|
22
|
+
before do
|
23
|
+
@container.current.stub(:get, "/hello") { response = "Good night" }
|
24
|
+
end
|
25
|
+
its(:body) { should == "Good night" }
|
26
|
+
|
27
|
+
describe "refleshed" do
|
28
|
+
before do
|
29
|
+
@container.reset!
|
30
|
+
end
|
31
|
+
|
32
|
+
its(:body) { should == "Hello World" }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require 'ww/servlet'
|
3
|
+
|
4
|
+
describe Ww::Double, "with Servlet" do
|
5
|
+
before do
|
6
|
+
@server = Ww::Servlet.base do
|
7
|
+
get("/") do
|
8
|
+
response.status = 200
|
9
|
+
response["Content-Type"] = "text/plain"
|
10
|
+
response.body = "Hello World"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "stub(:get, '/dynamic_add')" do
|
16
|
+
before do
|
17
|
+
@server.stub(:get, '/dynamic_add') do
|
18
|
+
response.status = 200
|
19
|
+
response["Content-Type"] = "text/plain"
|
20
|
+
response.body = "Hi World"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
subject{
|
25
|
+
@server.new.call( Rack::MockRequest.env_for("/dynamic_add", :method => "GET"))
|
26
|
+
}
|
27
|
+
|
28
|
+
it { should == [200, {"Content-Type"=>"text/plain", "Content-Length"=>"8"}, ["Hi World"]] }
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "stub(:get, '/') # override" do
|
32
|
+
before do
|
33
|
+
@server.stub(:get, '/') do
|
34
|
+
response.status = 200
|
35
|
+
response["Content-Type"] = "text/plain"
|
36
|
+
response.body = "Hi World"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
subject{
|
41
|
+
@server.new.call( Rack::MockRequest.env_for("/", :method => "GET"))
|
42
|
+
}
|
43
|
+
|
44
|
+
it { should == [200, {"Content-Type"=>"text/plain", "Content-Length"=>"8"}, ["Hi World"]] }
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "stub(:get, '/') # re-define after app initialized" do
|
48
|
+
before do
|
49
|
+
@app = @server.new
|
50
|
+
|
51
|
+
@server.stub(:get, '/') do
|
52
|
+
response.status = 200
|
53
|
+
response["Content-Type"] = "text/plain"
|
54
|
+
response.body = "Hi! World"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
subject{
|
59
|
+
@app.call( Rack::MockRequest.env_for("/", :method => "GET"))
|
60
|
+
}
|
61
|
+
|
62
|
+
it { should == [200, {"Content-Type"=>"text/plain", "Content-Length"=>"9"}, ["Hi! World"]] }
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "mock(:get, '/')" do
|
66
|
+
before do
|
67
|
+
@server.mock(:get, '/') do
|
68
|
+
response.status = 200
|
69
|
+
response["Content-Type"] = "text/plain"
|
70
|
+
response.body = "Hi World"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "call" do
|
75
|
+
before do
|
76
|
+
app = @server.new
|
77
|
+
@response = app.call( Rack::MockRequest.env_for("/", :method => "GET"))
|
78
|
+
end
|
79
|
+
|
80
|
+
subject{ @response }
|
81
|
+
|
82
|
+
it { should == [200, {"Content-Type"=>"text/plain", "Content-Length"=>"8"}, ["Hi World"]] }
|
83
|
+
it {
|
84
|
+
expect{ @server.verify }.should_not raise_error Ww::Double::MockError
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "don't call" do
|
89
|
+
it { expect{ @server.verify }.should raise_error Ww::Double::MockError }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "spy(:get, '/')" do
|
94
|
+
before do
|
95
|
+
@server.spy(:get, '/') do
|
96
|
+
response.status = 200
|
97
|
+
response["Content-Type"] = "text/plain"
|
98
|
+
response.body = "Hi World"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe "GET / リクエストの" do
|
103
|
+
before do
|
104
|
+
app = @server.new
|
105
|
+
@response = app.call( Rack::MockRequest.env_for("/", :method => "GET"))
|
106
|
+
end
|
107
|
+
|
108
|
+
subject{ @server.requests.first }
|
109
|
+
|
110
|
+
it { should be_a Rack::Request }
|
111
|
+
its(:request_method) { should == 'GET' }
|
112
|
+
its(:fullpath) { should == "/" }
|
113
|
+
|
114
|
+
it "bodyは空のIOであること" do
|
115
|
+
subject.body.rewind
|
116
|
+
subject.body.read.should == ""
|
117
|
+
end
|
118
|
+
|
119
|
+
it "レスポンスは想定どおりのものであること" do
|
120
|
+
@response.should ==
|
121
|
+
[200, {"Content-Type"=>"text/plain", "Content-Length"=>"8"}, ["Hi World"]]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "spy(:get, '/') backword compat" do
|
127
|
+
before do
|
128
|
+
@server.get('/backword') do
|
129
|
+
stump!
|
130
|
+
response.status = 200
|
131
|
+
response["Content-Type"] = "text/plain"
|
132
|
+
response.body = "Hi World"
|
133
|
+
end
|
134
|
+
|
135
|
+
app = @server.new
|
136
|
+
@response = app.call( Rack::MockRequest.env_for("/backword", :method => "GET"))
|
137
|
+
end
|
138
|
+
|
139
|
+
subject{ @server.requests }
|
140
|
+
it { should_not be_empty }
|
141
|
+
it { @server.requests.first.should be_a Ww::Double::Spy::Request }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'ww/double'
|
5
|
+
require 'ww/double/spy/request'
|
6
|
+
|
7
|
+
describe Ww::Double::Spy::Request do
|
8
|
+
describe "GET /" do
|
9
|
+
before do
|
10
|
+
base = Rack::Request.new(Rack::MockRequest.env_for("/", :method => "GET"))
|
11
|
+
@request = Ww::Double::Spy::Request.new(base)
|
12
|
+
end
|
13
|
+
|
14
|
+
subject { @request }
|
15
|
+
its(:request_method) { should == "GET" }
|
16
|
+
its(:parsed_body) { should == "" }
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_env(path, content_type, body)
|
20
|
+
Rack::MockRequest.env_for(
|
21
|
+
path, :method => "POST", :input => body
|
22
|
+
).merge("CONTENT_TYPE" => content_type)
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "POST /json_api" do
|
26
|
+
before do
|
27
|
+
@request = Ww::Double::Spy::Request.new(
|
28
|
+
post_env("/json_api", "application/json", JSON.dump({"json" => true}))
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
subject { @request }
|
33
|
+
its(:request_method) { should == "POST" }
|
34
|
+
its(:parsed_body) { should == {"json" => true} }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "POST /yaml_api" do
|
38
|
+
before do
|
39
|
+
@request = Ww::Double::Spy::Request.new(
|
40
|
+
post_env("/yaml_api", "application/yaml", {"yaml" => true}.to_yaml)
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
subject { @request }
|
45
|
+
its(:parsed_body) { should == {"yaml" => true} }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "POST /www_url_encoded" do
|
49
|
+
before do
|
50
|
+
body = {"www_url_encoded" => true, "multipart_formdata" => false}.map { |k,v|
|
51
|
+
"#{Rack::Utils.escape(k)}=#{Rack::Utils.escape(v)}"
|
52
|
+
}.join("&")
|
53
|
+
|
54
|
+
@request = Ww::Double::Spy::Request.new(
|
55
|
+
post_env("/post", "application/x-www-form-urlencoded", body)
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
subject { @request }
|
60
|
+
its(:parsed_body) { should == {"multipart_formdata"=>"false", "www_url_encoded"=>"true"} }
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "POST /unkown_type" do
|
64
|
+
before do
|
65
|
+
@request = Ww::Double::Spy::Request.new(
|
66
|
+
post_env("/post", "application/zip", "--not-changed-dummy-string--")
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
subject { @request }
|
71
|
+
its(:parsed_body) { should == "--not-changed-dummy-string--" }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require 'ww/server'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
describe Ww::Server do
|
7
|
+
before do
|
8
|
+
Ww::Server.handler = :mongrel # Mongrel is most silent.
|
9
|
+
Ww::Server[:spec] ||= Ww::Server.build_double(3080) do
|
10
|
+
get("/goodnight") { "Good night" }
|
11
|
+
spy(:get, "/hello") { "Hello world" }
|
12
|
+
end
|
13
|
+
Ww::Server[:spec].start_once
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "store only spy-ed action" do
|
17
|
+
before do
|
18
|
+
ignore = URI("http://localhost:3080/goodnight").read
|
19
|
+
ignore = URI("http://localhost:3080/hello").read
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { Ww::Server[:spec].requests }
|
23
|
+
it { should have(1).items }
|
24
|
+
it { subject.first.path.should == "/hello" }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "spying POST action" do
|
28
|
+
before do
|
29
|
+
Ww::Server[:spec].spy(:post, "/message") { status(200) }
|
30
|
+
|
31
|
+
Net::HTTP.start("localhost", 3080) do |http|
|
32
|
+
post = Net::HTTP::Post.new("/message")
|
33
|
+
post["Content-Type"] = "application/json"
|
34
|
+
post.body = {:message => "I'm double Ruby.", :madeby => "moro"}.to_json
|
35
|
+
http.request post
|
36
|
+
end
|
37
|
+
end
|
38
|
+
subject { Ww::Server[:spec].requests.first }
|
39
|
+
|
40
|
+
its(:parsed_body) do
|
41
|
+
should == {"message" => "I'm double Ruby.", "madeby" => "moro"}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with stubing" do
|
46
|
+
before do
|
47
|
+
# validates it's not stubbed.
|
48
|
+
URI("http://localhost:3080/goodnight").read.should == "Good night"
|
49
|
+
Ww::Server[:spec].stub(:get, "/goodnight") { "I'm sleepy, too" }
|
50
|
+
end
|
51
|
+
|
52
|
+
subject { URI("http://localhost:3080/goodnight").read }
|
53
|
+
it { should == "I'm sleepy, too" }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "mocking" do
|
57
|
+
before do
|
58
|
+
Ww::Server[:spec].mock(:get, "/goodnight") do
|
59
|
+
"OYASUMI-NASAI"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "pass if access there" do
|
64
|
+
ignore = URI("http://localhost:3080/goodnight").read
|
65
|
+
expect{ Ww::Server[:spec].verify }.should_not raise_error
|
66
|
+
end
|
67
|
+
|
68
|
+
it "fail unless access there" do
|
69
|
+
expect{ Ww::Server[:spec].verify }.should raise_error Ww::Double::MockError
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require 'ww/server'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
describe Ww::Server do
|
7
|
+
before do
|
8
|
+
Ww::Server.handler = :mongrel # Mongrel is most silent.
|
9
|
+
Ww::Server[:spec] ||= Ww::Server.build_double(3080) do
|
10
|
+
get("/goodnight") { "Good night" }
|
11
|
+
spy(:get, "/hello") { "Hello world" }
|
12
|
+
end
|
13
|
+
Ww::Server[:spec].start_once
|
14
|
+
end
|
15
|
+
subject { Ww::Server[:spec] }
|
16
|
+
it { should be_running }
|
17
|
+
it "should works fine" do
|
18
|
+
URI("http://localhost:3080/hello").read.should == "Hello world"
|
19
|
+
URI("http://localhost:3080/goodnight").read.should == "Good night"
|
20
|
+
end
|
21
|
+
its(:port){ should == 3080 }
|
22
|
+
|
23
|
+
describe "shutdown!" do
|
24
|
+
before do
|
25
|
+
# mongrel fails to shutdon before accepting any req.
|
26
|
+
URI("http://localhost:3080/hello").read
|
27
|
+
Ww::Server[:spec].shutdown!
|
28
|
+
end
|
29
|
+
|
30
|
+
it { should_not be_running }
|
31
|
+
|
32
|
+
it "the server should be down" do
|
33
|
+
expect { URI("http://localhost:3080/hello").read }.should \
|
34
|
+
raise_error Errno::ECONNREFUSED
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.expand_path("../spec_helper", File.dirname(__FILE__))
|
2
|
+
require 'ww/servlet'
|
3
|
+
|
4
|
+
describe Ww::Servlet do
|
5
|
+
before do
|
6
|
+
@server = Ww::Servlet.base do
|
7
|
+
get("/") do
|
8
|
+
response.status = 200
|
9
|
+
response["Content-Type"] = "text/plain"
|
10
|
+
response.body = "Hello World"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
subject{ @server }
|
15
|
+
it { should be_instance_of Class }
|
16
|
+
|
17
|
+
describe "GET /" do
|
18
|
+
subject do
|
19
|
+
@server.new.call( Rack::MockRequest.env_for("/", :method => "GET"))
|
20
|
+
end
|
21
|
+
|
22
|
+
it { should == [200, {"Content-Type"=>"text/plain", "Content-Length"=>"11"}, ["Hello World"]] }
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ww
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- moro
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-17 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -62,16 +62,27 @@ extra_rdoc_files: []
|
|
62
62
|
|
63
63
|
files:
|
64
64
|
- Rakefile
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
- spec/ww/application_spec.rb
|
67
|
+
- spec/ww/double_spec.rb
|
68
|
+
- spec/ww/double_spy_request_spec.rb
|
69
|
+
- spec/ww/server_integration_spec.rb
|
70
|
+
- spec/ww/server_spec.rb
|
71
|
+
- spec/ww/servlet_spec.rb
|
72
|
+
- lib/ww/application.rb
|
65
73
|
- lib/ww/double/mock.rb
|
66
74
|
- lib/ww/double/spy/request.rb
|
67
75
|
- lib/ww/double/spy.rb
|
68
76
|
- lib/ww/double/stub.rb
|
69
77
|
- lib/ww/double.rb
|
78
|
+
- lib/ww/server.rb
|
70
79
|
- lib/ww/servlet.rb
|
71
80
|
- lib/ww/spy_eye.html.haml
|
72
81
|
- lib/ww/spy_eye.rb
|
73
82
|
- lib/ww/store.rb
|
74
83
|
- lib/ww.rb
|
84
|
+
- example/spy_eye.ru
|
85
|
+
- example/spy_eye_output.html
|
75
86
|
has_rdoc: true
|
76
87
|
homepage: http://github.com/moro/ww/
|
77
88
|
licenses: []
|