http_stub 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/http_stub.rb +7 -3
- data/lib/http_stub/configurer.rb +75 -0
- data/lib/http_stub/controllers/alias_controller.rb +29 -0
- data/lib/http_stub/controllers/stub_controller.rb +27 -0
- data/lib/http_stub/models/alias.rb +22 -0
- data/lib/http_stub/models/registry.rb +29 -0
- data/lib/http_stub/models/stub.rb +35 -0
- data/lib/http_stub/response.rb +14 -0
- data/lib/http_stub/server.rb +24 -9
- data/lib/http_stub/start_server_rake_task.rb +1 -1
- data/lib/http_stub/version.rb +1 -1
- data/spec/lib/http_stub/configurer_integration_spec.rb +119 -0
- data/spec/lib/http_stub/controllers/alias_controller_spec.rb +75 -0
- data/spec/lib/http_stub/controllers/stub_controller_spec.rb +74 -0
- data/spec/lib/http_stub/models/alias_spec.rb +58 -0
- data/spec/lib/http_stub/models/registry_spec.rb +101 -0
- data/spec/lib/http_stub/{stub_spec.rb → models/stub_spec.rb} +18 -19
- data/spec/lib/http_stub/response_spec.rb +73 -0
- data/spec/lib/http_stub/server_spec.rb +117 -44
- data/spec/lib/http_stub/start_server_rake_task_integration_spec.rb +1 -1
- metadata +23 -11
- data/lib/http_stub/client.rb +0 -61
- data/lib/http_stub/registry.rb +0 -26
- data/lib/http_stub/stub.rb +0 -35
- data/spec/lib/http_stub/client_integration_spec.rb +0 -81
- data/spec/lib/http_stub/registry_spec.rb +0 -99
data/lib/http_stub.rb
CHANGED
@@ -7,7 +7,11 @@ require 'immutable_struct'
|
|
7
7
|
require 'net/http'
|
8
8
|
require 'json'
|
9
9
|
|
10
|
-
require File.expand_path('../http_stub/
|
11
|
-
require File.expand_path('../http_stub/
|
10
|
+
require File.expand_path('../http_stub/response', __FILE__)
|
11
|
+
require File.expand_path('../http_stub/models/stub', __FILE__)
|
12
|
+
require File.expand_path('../http_stub/models/alias', __FILE__)
|
13
|
+
require File.expand_path('../http_stub/models/registry', __FILE__)
|
14
|
+
require File.expand_path('../http_stub/controllers/stub_controller', __FILE__)
|
15
|
+
require File.expand_path('../http_stub/controllers/alias_controller', __FILE__)
|
12
16
|
require File.expand_path('../http_stub/server', __FILE__)
|
13
|
-
require File.expand_path('../http_stub/
|
17
|
+
require File.expand_path('../http_stub/configurer', __FILE__)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module HttpStub
|
2
|
+
|
3
|
+
module Configurer
|
4
|
+
|
5
|
+
def self.included(mod)
|
6
|
+
mod.extend(HttpStub::Configurer::ClassMethods)
|
7
|
+
mod.send(:include, HttpStub::Configurer::InstanceMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
|
12
|
+
def host(host)
|
13
|
+
@host = host
|
14
|
+
end
|
15
|
+
|
16
|
+
def port(port)
|
17
|
+
@port = port
|
18
|
+
end
|
19
|
+
|
20
|
+
def stub_alias(alias_uri, stub_uri, options)
|
21
|
+
response_options = options[:response]
|
22
|
+
request = Net::HTTP::Post.new("/stubs/aliases")
|
23
|
+
request.content_type = "application/json"
|
24
|
+
request.body = {
|
25
|
+
"alias_uri" => alias_uri,
|
26
|
+
"uri" => stub_uri,
|
27
|
+
"method" => options[:method],
|
28
|
+
"parameters" => options[:parameters] || {},
|
29
|
+
"response" => {
|
30
|
+
"status" => response_options[:status] || "200",
|
31
|
+
"body" => response_options[:body]
|
32
|
+
}
|
33
|
+
}.to_json
|
34
|
+
response = submit(request)
|
35
|
+
raise "Unable to establish stub alias: #{response.message}" unless response.code == "200"
|
36
|
+
end
|
37
|
+
|
38
|
+
def submit(request)
|
39
|
+
Net::HTTP.new(@host, @port).start { |http| http.request(request) }
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
module InstanceMethods
|
45
|
+
|
46
|
+
def stub!(uri, options)
|
47
|
+
response_options = options[:response]
|
48
|
+
request = Net::HTTP::Post.new("/stubs")
|
49
|
+
request.content_type = "application/json"
|
50
|
+
request.body = {
|
51
|
+
"uri" => uri,
|
52
|
+
"method" => options[:method],
|
53
|
+
"parameters" => options[:parameters] || {},
|
54
|
+
"response" => {
|
55
|
+
"status" => response_options[:status] || "200",
|
56
|
+
"body" => response_options[:body]
|
57
|
+
}
|
58
|
+
}.to_json
|
59
|
+
response = self.class.submit(request)
|
60
|
+
raise "Unable to establish stub: #{response.message}" unless response.code == "200"
|
61
|
+
end
|
62
|
+
|
63
|
+
alias_method :stub_response!, :stub!
|
64
|
+
|
65
|
+
def clear!
|
66
|
+
request = Net::HTTP::Delete.new("/stubs")
|
67
|
+
response = self.class.submit(request)
|
68
|
+
raise "Unable to clear stubs: #{response.message}" unless response.code == "200"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module HttpStub
|
2
|
+
module Controllers
|
3
|
+
|
4
|
+
class AliasController
|
5
|
+
|
6
|
+
def initialize(alias_registry, stub_registry)
|
7
|
+
@alias_registry = alias_registry
|
8
|
+
@stub_registry = stub_registry
|
9
|
+
end
|
10
|
+
|
11
|
+
def register(request)
|
12
|
+
@alias_registry.add(HttpStub::Models::Alias.new(request.body.read), request)
|
13
|
+
HttpStub::Response::SUCCESS
|
14
|
+
end
|
15
|
+
|
16
|
+
def activate(request)
|
17
|
+
the_alias = @alias_registry.find_for(request)
|
18
|
+
if the_alias
|
19
|
+
@stub_registry.add(the_alias.the_stub, request)
|
20
|
+
HttpStub::Response::SUCCESS
|
21
|
+
else
|
22
|
+
HttpStub::Response::EMPTY
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module HttpStub
|
2
|
+
module Controllers
|
3
|
+
|
4
|
+
class StubController
|
5
|
+
|
6
|
+
def initialize(registry)
|
7
|
+
@registry = registry
|
8
|
+
end
|
9
|
+
|
10
|
+
def register(request)
|
11
|
+
@registry.add(HttpStub::Models::Stub.new(request.body.read), request)
|
12
|
+
HttpStub::Response::SUCCESS
|
13
|
+
end
|
14
|
+
|
15
|
+
def replay(request)
|
16
|
+
stub = @registry.find_for(request)
|
17
|
+
stub ? stub.response : HttpStub::Response::EMPTY
|
18
|
+
end
|
19
|
+
|
20
|
+
def clear(request)
|
21
|
+
@registry.clear(request)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module HttpStub
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Alias
|
5
|
+
|
6
|
+
def initialize(request_body)
|
7
|
+
@data = JSON.parse(request_body)
|
8
|
+
@stub = HttpStub::Models::Stub.new(request_body)
|
9
|
+
end
|
10
|
+
|
11
|
+
def satisfies?(request)
|
12
|
+
@data["alias_uri"] == request.path_info
|
13
|
+
end
|
14
|
+
|
15
|
+
def the_stub
|
16
|
+
@stub
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module HttpStub
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Registry
|
5
|
+
|
6
|
+
def initialize(model_name)
|
7
|
+
@model_name = model_name
|
8
|
+
@models = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(model, request)
|
12
|
+
@models.unshift(model)
|
13
|
+
request.logger.info "Registered #{@model_name}: #{model}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def find_for(request)
|
17
|
+
request.logger.info "Finding #{@model_name} satisfying: #{request.inspect}"
|
18
|
+
@models.find { |model| model.satisfies?(request) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear(request)
|
22
|
+
request.logger.info "Clearing #{@model_name} registry"
|
23
|
+
@models.clear
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module HttpStub
|
2
|
+
module Models
|
3
|
+
|
4
|
+
class Stub
|
5
|
+
|
6
|
+
attr_reader :response
|
7
|
+
|
8
|
+
def initialize(request_body)
|
9
|
+
@data = JSON.parse(request_body)
|
10
|
+
@response = HttpStub::Response.new(status: @data["response"]["status"], body: @data["response"]["body"])
|
11
|
+
end
|
12
|
+
|
13
|
+
def satisfies?(request)
|
14
|
+
@data["uri"] == request.path_info &&
|
15
|
+
@data["method"].downcase == request.request_method.downcase &&
|
16
|
+
parameters_match?(request)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@data.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def parameters_match?(request)
|
26
|
+
parameters = @data["parameters"]
|
27
|
+
parameters.nil? || parameters.reduce(true) do |result, parameter|
|
28
|
+
result && (request.params[parameter[0]] == parameter[1])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module HttpStub
|
2
|
+
|
3
|
+
class Response < ImmutableStruct.new(:status, :body)
|
4
|
+
SUCCESS = HttpStub::Response.new(status: 200, body: "")
|
5
|
+
ERROR = HttpStub::Response.new(status: 404, body: "")
|
6
|
+
EMPTY = HttpStub::Response.new()
|
7
|
+
|
8
|
+
def empty?
|
9
|
+
self == HttpStub::Response::EMPTY
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
data/lib/http_stub/server.rb
CHANGED
@@ -6,7 +6,10 @@ module HttpStub
|
|
6
6
|
|
7
7
|
def initialize
|
8
8
|
super()
|
9
|
-
@
|
9
|
+
@stub_registry = HttpStub::Models::Registry.new("stub")
|
10
|
+
@alias_registry = HttpStub::Models::Registry.new("alias")
|
11
|
+
@stub_controller = HttpStub::Controllers::StubController.new(@stub_registry)
|
12
|
+
@alias_controller = HttpStub::Controllers::AliasController.new(@alias_registry, @stub_registry)
|
10
13
|
end
|
11
14
|
|
12
15
|
private
|
@@ -32,23 +35,35 @@ module HttpStub
|
|
32
35
|
# "body": "Hello World"
|
33
36
|
# }
|
34
37
|
# }
|
35
|
-
post "/
|
36
|
-
@
|
37
|
-
halt
|
38
|
+
post "/stubs" do
|
39
|
+
response = @stub_controller.register(request)
|
40
|
+
halt(response.status, response.body)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sample request body:
|
44
|
+
# {
|
45
|
+
# "alias_uri": "/some/path",
|
46
|
+
# ... see /stub ...
|
47
|
+
# }
|
48
|
+
post "/stubs/aliases" do
|
49
|
+
response = @alias_controller.register(request)
|
50
|
+
halt(response.status, response.body)
|
38
51
|
end
|
39
52
|
|
40
53
|
delete "/stubs" do
|
41
|
-
@
|
54
|
+
@stub_controller.clear(request)
|
42
55
|
halt 200
|
43
56
|
end
|
44
57
|
|
45
|
-
any_request_type(//) {
|
58
|
+
any_request_type(//) { handle_request }
|
46
59
|
|
47
60
|
private
|
48
61
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
62
|
+
def handle_request
|
63
|
+
response = @stub_controller.replay(request)
|
64
|
+
response = @alias_controller.activate(request) if response.empty?
|
65
|
+
response = HttpStub::Response::ERROR if response.empty?
|
66
|
+
halt(response.status, response.body)
|
52
67
|
end
|
53
68
|
|
54
69
|
end
|
data/lib/http_stub/version.rb
CHANGED
@@ -0,0 +1,119 @@
|
|
1
|
+
describe HttpStub::Configurer do
|
2
|
+
include_context "server integration"
|
3
|
+
|
4
|
+
before(:all) do
|
5
|
+
class TestConfigurer
|
6
|
+
include HttpStub::Configurer
|
7
|
+
|
8
|
+
host "localhost"
|
9
|
+
port 8001
|
10
|
+
|
11
|
+
stub_alias "/an_alias", "/path1", method: :get, response: { status: 200, body: "Stub alias body" }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:configurer) { TestConfigurer.new }
|
16
|
+
|
17
|
+
after(:each) { configurer.clear! }
|
18
|
+
|
19
|
+
describe "when a stub alias is activated" do
|
20
|
+
|
21
|
+
before(:each) { Net::HTTP.get_response("localhost", "/an_alias", 8001) }
|
22
|
+
|
23
|
+
describe "and the stub request is made" do
|
24
|
+
|
25
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path1", 8001) }
|
26
|
+
|
27
|
+
it "should replay the stubbed response" do
|
28
|
+
response.code.should eql("200")
|
29
|
+
response.body.should eql("Stub alias body")
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "when a stub alias is not activated" do
|
37
|
+
|
38
|
+
describe "and the stub request is made" do
|
39
|
+
|
40
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path1", 8001) }
|
41
|
+
|
42
|
+
it "should respond with a 404 status code" do
|
43
|
+
response.code.should eql("404")
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when a response for a request is stubbed" do
|
51
|
+
|
52
|
+
describe "that contains no parameters" do
|
53
|
+
|
54
|
+
before(:each) do
|
55
|
+
configurer.stub_response!("/path2", method: :get, response: { status: 201, body: "Stub body" })
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "and that request is made" do
|
59
|
+
|
60
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path2", 8001) }
|
61
|
+
|
62
|
+
it "should replay the stubbed response" do
|
63
|
+
response.code.should eql("201")
|
64
|
+
response.body.should eql("Stub body")
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "and the stub is cleared" do
|
70
|
+
|
71
|
+
before(:each) { configurer.clear! }
|
72
|
+
|
73
|
+
describe "and the original request is made" do
|
74
|
+
|
75
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path2", 8001) }
|
76
|
+
|
77
|
+
it "should respond with a 404 status code" do
|
78
|
+
response.code.should eql("404")
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "that contains parameters" do
|
88
|
+
|
89
|
+
before(:each) do
|
90
|
+
configurer.stub_response!("/path3", method: :get, parameters: { key: "value" },
|
91
|
+
response: { status: 202, body: "Another stub body" })
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "and that request is made" do
|
95
|
+
|
96
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path3?key=value", 8001) }
|
97
|
+
|
98
|
+
it "should replay the stubbed response" do
|
99
|
+
response.code.should eql("202")
|
100
|
+
response.body.should eql("Another stub body")
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "and a request with different parameters is made" do
|
106
|
+
|
107
|
+
let(:response) { Net::HTTP.get_response("localhost", "/path3?key=another_value", 8001) }
|
108
|
+
|
109
|
+
it "should respond with a 404 status code" do
|
110
|
+
response.code.should eql("404")
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
describe HttpStub::Controllers::AliasController do
|
2
|
+
|
3
|
+
let(:request_body) { "Some request body" }
|
4
|
+
let(:request) { double("HttpRequest", body: double("RequestBody", read: request_body)) }
|
5
|
+
let(:the_stub) { double(HttpStub::Models::Stub) }
|
6
|
+
let(:stub_alias) { double(HttpStub::Models::Alias, the_stub: the_stub) }
|
7
|
+
let(:alias_registry) { double("HttpStub::Models::AliasRegistry").as_null_object }
|
8
|
+
let(:stub_registry) { double("HttpStub::Models::StubRegistry").as_null_object }
|
9
|
+
let(:controller) { HttpStub::Controllers::AliasController.new(alias_registry, stub_registry) }
|
10
|
+
|
11
|
+
describe "#register" do
|
12
|
+
|
13
|
+
before(:each) do
|
14
|
+
HttpStub::Models::Alias.stub!(:new).and_return(stub_alias)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create an alias from the request body" do
|
18
|
+
HttpStub::Models::Alias.should_receive(:new).with(request_body).and_return(stub_alias)
|
19
|
+
|
20
|
+
controller.register(request)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should add the created alias to the alias registry" do
|
24
|
+
alias_registry.should_receive(:add).with(stub_alias, request)
|
25
|
+
|
26
|
+
controller.register(request)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return a success response" do
|
30
|
+
controller.register(request).should eql(HttpStub::Response::SUCCESS)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#activate" do
|
36
|
+
|
37
|
+
describe "when an alias has been registered that is activated by the request" do
|
38
|
+
|
39
|
+
before(:each) do
|
40
|
+
alias_registry.stub!(:find_for).with(request).and_return(stub_alias)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should add the aliases stub to the stub registry" do
|
44
|
+
stub_registry.should_receive(:add).with(the_stub, request)
|
45
|
+
|
46
|
+
controller.activate(request)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return a success response" do
|
50
|
+
controller.activate(request).should eql(HttpStub::Response::SUCCESS)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "when no alias is activated by the request" do
|
56
|
+
|
57
|
+
before(:each) do
|
58
|
+
alias_registry.stub!(:find_for).with(request).and_return(nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not add a stub to the registry" do
|
62
|
+
stub_registry.should_not_receive(:add)
|
63
|
+
|
64
|
+
controller.activate(request)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return an empty response" do
|
68
|
+
controller.activate(request).should eql(HttpStub::Response::EMPTY)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|