Skip to content

Commit d6e8e02

Browse files
committed
Add Ruby code for final chapter
1 parent e65bb35 commit d6e8e02

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
require_relative "web-server"
2+
require "test/unit"
3+
require 'webrick'
4+
require 'net/http'
5+
6+
class TestWebServer < Test::Unit::TestCase
7+
def initialize(test_method_name)
8+
super(test_method_name)
9+
mock_web_service = MockWebService.new([200, 'text/html', 'mock example.org'])
10+
@handlers = Handlers.new(mock_web_service)
11+
end
12+
13+
def test_unit_hello
14+
status_code, content_type, body = @handlers.handle("/")
15+
assert_equal(200, status_code)
16+
assert_equal('text/plain', content_type)
17+
assert_equal('Hello, World', body)
18+
end
19+
20+
def test_unit_api
21+
status_code, content_type, body = @handlers.handle("/api")
22+
assert_equal(201, status_code)
23+
assert_equal('application/json', content_type)
24+
assert_equal('{"foo":"bar"}', body)
25+
end
26+
27+
def test_unit_404
28+
status_code, content_type, body = @handlers.handle("/invalid-path")
29+
assert_equal(404, status_code)
30+
assert_equal('text/plain', content_type)
31+
assert_equal('Not Found', body)
32+
end
33+
34+
def test_unit_web_service
35+
expected_status = 200
36+
expected_content_type = 'text/html'
37+
expected_body = 'mock example.org'
38+
mock_response = [expected_status, expected_content_type, expected_body]
39+
40+
mock_web_service = MockWebService.new(mock_response)
41+
handlers = Handlers.new(mock_web_service)
42+
43+
status_code, content_type, body = handlers.handle("/web-service")
44+
assert_equal(expected_status, status_code)
45+
assert_equal(expected_content_type, content_type)
46+
assert_equal(expected_body, body)
47+
end
48+
49+
def test_integration_hello
50+
do_integration_test('/', lambda { |response|
51+
assert_equal(200, response.code.to_i)
52+
assert_equal('text/plain', response['Content-Type'])
53+
assert_equal('Hello, World', response.body)
54+
})
55+
end
56+
57+
def test_integration_api
58+
do_integration_test('/api', lambda { |response|
59+
assert_equal(201, response.code.to_i)
60+
assert_equal('application/json', response['Content-Type'])
61+
assert_equal('{"foo":"bar"}', response.body)
62+
})
63+
end
64+
65+
def test_integration_404
66+
do_integration_test('/invalid-path', lambda { |response|
67+
assert_equal(404, response.code.to_i)
68+
assert_equal('text/plain', response['Content-Type'])
69+
assert_equal('Not Found', response.body)
70+
})
71+
end
72+
73+
def test_integration_web_service
74+
do_integration_test('/web-service', lambda { |response|
75+
assert_equal(200, response.code.to_i)
76+
assert_include(response['Content-Type'], 'text/html')
77+
assert_include(response.body, 'Example Domain')
78+
})
79+
end
80+
81+
def do_integration_test(path, check_response)
82+
port = 8000
83+
server = WEBrick::HTTPServer.new :Port => port
84+
server.mount '/', WebServer
85+
86+
begin
87+
# Start the web server in a separate thread so it
88+
# doesn't block the test
89+
thread = Thread.new do
90+
server.start
91+
end
92+
93+
# Make an HTTP request to the web server at the
94+
# specified path
95+
uri = URI("http://localhost:#{port}#{path}")
96+
response = Net::HTTP.get_response(uri)
97+
98+
# Use the specified check_response lambda to validate
99+
# the response
100+
check_response.call(response)
101+
ensure
102+
# Shut the server and thread down at the end of the
103+
# test
104+
server.shutdown
105+
thread.join
106+
end
107+
end
108+
end
109+
110+
class MockWebService
111+
def initialize(response)
112+
@response = response
113+
end
114+
115+
def proxy
116+
@response
117+
end
118+
end
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
require 'webrick'
2+
require 'net/http'
3+
4+
class WebServer < WEBrick::HTTPServlet::AbstractServlet
5+
def do_GET(request, response)
6+
web_service = WebService.new("http://www.example.org")
7+
handlers = Handlers.new(web_service)
8+
9+
status_code, content_type, body = handlers.handle(request.path)
10+
11+
response.status = status_code
12+
response['Content-Type'] = content_type
13+
response.body = body
14+
end
15+
end
16+
17+
class Handlers
18+
def initialize(web_service)
19+
@web_service = web_service
20+
end
21+
22+
def handle(path)
23+
case path
24+
when "/"
25+
self.hello
26+
when "/api"
27+
self.api
28+
when "/web-service"
29+
self.web_service
30+
else
31+
self.not_found
32+
end
33+
end
34+
35+
def hello
36+
[200, 'text/plain', 'Hello, World']
37+
end
38+
39+
def api
40+
[201, 'application/json', '{"foo":"bar"}']
41+
end
42+
43+
def web_service
44+
@web_service.proxy
45+
end
46+
47+
def not_found
48+
[404, 'text/plain', 'Not Found']
49+
end
50+
end
51+
52+
class WebService
53+
def initialize(url)
54+
@uri = URI(url)
55+
end
56+
57+
def proxy
58+
response = Net::HTTP.get_response(@uri)
59+
[response.code.to_i, response['Content-Type'], response.body]
60+
end
61+
end
62+
63+
# This will only run if this script was called directly from the CLI, but
64+
# not if it was required from another file
65+
if __FILE__ == $0
66+
# Run the server on localhost at port 8000
67+
server = WEBrick::HTTPServer.new :Port => 8000
68+
server.mount '/', WebServer
69+
70+
# Shut down the server on CTRL+C
71+
trap 'INT' do server.shutdown end
72+
73+
# Start the server
74+
server.start
75+
end

0 commit comments

Comments
 (0)