http_stub 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ module Http
2
+ module Stub
3
+
4
+ class Registry
5
+
6
+ def initialize
7
+ @stubs = []
8
+ end
9
+
10
+ def add(stub, request)
11
+ @stubs.unshift(stub)
12
+ request.logger.info "Stub registered: #{stub}"
13
+ end
14
+
15
+ def find_for(request)
16
+ request.logger.info "Finding stub fulfilling: #{request}"
17
+ @stubs.find { |stub| stub.stubs?(request) }
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
@@ -3,17 +3,17 @@ module Http
3
3
 
4
4
  class Server < ::Sinatra::Base
5
5
 
6
- SUPPORTED_REQUEST_TYPES = [:get, :post, :put, :delete, :patch, :options].freeze
7
-
8
6
  enable :dump_errors, :logging
9
7
 
10
- def initialize()
8
+ def initialize
11
9
  super()
12
- @response_register = {}
10
+ @registry = Http::Stub::Registry.new
13
11
  end
14
12
 
15
13
  private
16
14
 
15
+ SUPPORTED_REQUEST_TYPES = [:get, :post, :put, :delete, :patch, :options].freeze
16
+
17
17
  def self.any_request_type(path, opts={}, &block)
18
18
  SUPPORTED_REQUEST_TYPES.each { |type| self.send(type, path, opts, &block) }
19
19
  end
@@ -24,15 +24,17 @@ module Http
24
24
  # {
25
25
  # "uri": "/some/path",
26
26
  # "method": "get",
27
+ # "parameters": {
28
+ # "key": "value",
29
+ # ...
30
+ # },
27
31
  # "response": {
28
32
  # "status": "200",
29
33
  # "body": "Hello World"
30
34
  # }
31
35
  # }
32
36
  post "/stub" do
33
- data = JSON.parse(request.body.read)
34
- logger.info "Stub registered: #{data}"
35
- @response_register[data["uri"]] = data
37
+ @registry.add(Http::Stub::Stub.new(request), request)
36
38
  halt 200
37
39
  end
38
40
 
@@ -41,14 +43,8 @@ module Http
41
43
  private
42
44
 
43
45
  def handle_stub_request
44
- logger.info "Stub response requested: #{request}"
45
- stub_data = @response_register[request.path_info]
46
- if stub_data && stub_data["method"].downcase == request.request_method.downcase
47
- response_data = stub_data["response"]
48
- halt response_data["status"].to_i, response_data["body"]
49
- else
50
- halt 404
51
- end
46
+ stub = @registry.find_for(request)
47
+ stub ? halt(stub.response.status, stub.response.body) : halt(404)
52
48
  end
53
49
 
54
50
  end
@@ -0,0 +1,32 @@
1
+ module Http
2
+ module Stub
3
+ class Stub
4
+
5
+ Response = ImmutableStruct.new(:status, :body)
6
+
7
+ attr_reader :response
8
+
9
+ def initialize(request)
10
+ @data = JSON.parse(request.body.read)
11
+ @response = Response.new(status: @data["response"]["status"], body: @data["response"]["body"])
12
+ end
13
+
14
+ def stubs?(request)
15
+ @data["uri"] == request.path_info &&
16
+ @data["method"].downcase == request.request_method.downcase &&
17
+ parameters == request.params
18
+ end
19
+
20
+ def to_s
21
+ @data.to_s
22
+ end
23
+
24
+ private
25
+
26
+ def parameters
27
+ @data["parameters"] || {}
28
+ end
29
+
30
+ end
31
+ end
32
+ end
@@ -1,5 +1,5 @@
1
1
  module Http
2
2
  module Stub
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
data/lib/http_stub.rb CHANGED
@@ -3,8 +3,11 @@ require 'bundler/setup'
3
3
  Bundler.require(:default)
4
4
 
5
5
  require 'sinatra'
6
+ require 'immutable_struct'
6
7
  require 'net/http'
7
8
  require 'json'
8
9
 
10
+ require File.expand_path('../http/stub/stub', __FILE__)
11
+ require File.expand_path('../http/stub/registry', __FILE__)
9
12
  require File.expand_path('../http/stub/server', __FILE__)
10
13
  require File.expand_path('../http/stub/client', __FILE__)
@@ -12,9 +12,7 @@ describe Http::Stub::Client do
12
12
 
13
13
  describe "when a response for a request is stubbed" do
14
14
 
15
- before(:each) do
16
- client.stub_response!("/a_path", method: :get, status: 200, body: "Some body")
17
- end
15
+ before(:each) { client.stub_response!("/a_path", method: :get, status: 200, body: "Some body") }
18
16
 
19
17
  describe "and that request is made" do
20
18
 
@@ -5,7 +5,7 @@ describe Http::Stub::RakeTask do
5
5
 
6
6
  it "should start a stub server that responds to stub requests" do
7
7
  request = Net::HTTP::Post.new("/stub")
8
- request.body = "{}"
8
+ request.body = { "response" => { "status" => 302, "body" => "Some Body" } }.to_json
9
9
 
10
10
  response = Net::HTTP.new("localhost", 8001).start { |http| http.request(request) }
11
11
 
@@ -0,0 +1,79 @@
1
+ describe Http::Stub::Registry do
2
+
3
+ let(:registry) { Http::Stub::Registry.new }
4
+
5
+ let(:logger) { double("Logger").as_null_object }
6
+ let(:request) { double("HttpRequest", logger: logger, to_s: "Request as String") }
7
+
8
+ describe "#add" do
9
+
10
+ it "should log that the stub has been registered" do
11
+ stub = double(Http::Stub::Stub, to_s: "Stub as String")
12
+ logger.should_receive(:info).with(/Stub as String/)
13
+
14
+ registry.add(stub, request)
15
+ end
16
+
17
+ end
18
+
19
+ describe "#find_for" do
20
+
21
+ describe "when multiple stubs have been registered" do
22
+
23
+ let(:stubs) do
24
+ (1..3).map { |i| double("#{Http::Stub::Stub}#{i}", :stubs? => false) }
25
+ end
26
+
27
+ before(:each) do
28
+ stubs.each { |stub| registry.add(stub, request) }
29
+ end
30
+
31
+ describe "and one registered stub matches the request" do
32
+
33
+ before(:each) { stubs[1].stub!(:stubs?).and_return(true) }
34
+
35
+ it "should return the stub" do
36
+ registry.find_for(request).should eql(stubs[1])
37
+ end
38
+
39
+ end
40
+
41
+ describe "and multiple registered stubs match the request" do
42
+
43
+ before(:each) do
44
+ [0, 2].each { |i| stubs[i].stub!(:stubs?).and_return(true) }
45
+ end
46
+
47
+ it "should support stub overrides by returning the last stub registered" do
48
+ registry.find_for(request).should eql(stubs[2])
49
+ end
50
+
51
+ end
52
+
53
+ describe "and no registered stubs match the request" do
54
+
55
+ it "should return nil" do
56
+ registry.find_for(request).should be_nil
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ describe "when no stub has been registered" do
64
+
65
+ it "should return nil" do
66
+ registry.find_for(request).should be_nil
67
+ end
68
+
69
+ end
70
+
71
+ it "it should log that a stub is being found" do
72
+ logger.should_receive(:info).with(/Request as String/)
73
+
74
+ registry.find_for(request)
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -1,65 +1,74 @@
1
1
  describe Http::Stub::Server do
2
2
  include Rack::Test::Methods
3
3
 
4
- let(:app) { Http::Stub::Server }
4
+ let(:app) { Http::Stub::Server.new }
5
+
6
+ let(:registry) { double(Http::Stub::Registry).as_null_object }
7
+ before(:each) { Http::Stub::Registry.stub!(:new).and_return(registry) }
8
+
5
9
  let(:response) { last_response }
6
10
  let(:response_body) { response.body.to_s }
7
11
 
8
- shared_examples "a server that stubs a response" do |options|
12
+ describe "when a stub request is received" do
9
13
 
10
- let(:request_type) { options[:request_type] }
11
- let(:different_request_type) { options[:different_request_type] }
12
- let(:test_url) { "/test_#{request_type}" }
14
+ it "should register a stub encapsulating the request" do
15
+ stub = double(Http::Stub::Stub)
16
+ Http::Stub::Stub.should_receive(:new).and_return(stub)
17
+ registry.should_receive(:add).with(stub, anything)
13
18
 
14
- before(:each) do
15
- post "/stub", '{"uri": "' + test_url + '", "method": "' + request_type.to_s + '", "response": {"status":"200", "body":"Foo"}}'
19
+ issue_stub_request
16
20
  end
17
21
 
18
- describe "when a #{options[:request_type]} request is made" do
22
+ end
19
23
 
20
- before(:each) { self.send(request_type, test_url) }
24
+ describe "when a playback request is received" do
21
25
 
22
- it "should respond with the stubbed response code" do
23
- response.status.should eql(200)
24
- end
26
+ describe "and the request has been stubbed" do
25
27
 
26
- it "should respond with the stubbed body" do
27
- response_body.should eql("Foo")
28
+ before(:each) do
29
+ registry.stub!(:find_for).and_return(
30
+ double(Http::Stub::Stub, response: double("StubResponse", status: 500, body: "Some text")))
28
31
  end
29
32
 
30
- end
33
+ it "should respond with the configured status" do
34
+ get "/a_path"
31
35
 
32
- describe "and a request of type '#{options[:different_request_type]}' is made" do
36
+ response.status.should eql(500)
37
+ end
33
38
 
34
- before(:each) { self.send(different_request_type, test_url) }
39
+ it "should respond with the configured body" do
40
+ get "/a_path"
35
41
 
36
- it "should respond with a 404 response code" do
37
- response.status.should eql(404)
42
+ response_body.should eql("Some text")
38
43
  end
39
44
 
40
45
  end
41
46
 
42
- end
47
+ describe "and the request has not been stubbed" do
43
48
 
44
- all_request_types = [:get, :post, :put, :delete, :patch, :options]
45
- all_request_types.each_with_index do |request_type, i|
49
+ before(:each) do
50
+ registry.stub!(:find_for).and_return(nil)
51
+ end
46
52
 
47
- describe "when a #{request_type} request is stubbed" do
53
+ it "should respond with a 404" do
54
+ get "/a_path"
48
55
 
49
- it_should_behave_like "a server that stubs a response", request_type: request_type, different_request_type: all_request_types[i - 1]
56
+ response.status.should eql(404)
57
+ end
50
58
 
51
59
  end
52
60
 
53
61
  end
54
62
 
55
- describe "when a request is made that is not stubbed" do
56
-
57
- before(:each) { get "/not_stubbed" }
58
-
59
- it "should respond with 404 response code" do
60
- response.status.should eql(404)
61
- end
62
-
63
+ def issue_stub_request
64
+ post "/stub", {
65
+ "uri" => "/a_path",
66
+ "method" => "a method",
67
+ "response" => {
68
+ "status" => 200,
69
+ "body" => "Foo"
70
+ }
71
+ }.to_json
63
72
  end
64
73
 
65
74
  end
@@ -0,0 +1,157 @@
1
+ describe Http::Stub::Stub do
2
+
3
+ let(:stub_uri) { "/a_path" }
4
+ let(:stub_method) { "get" }
5
+ let(:stub_parameters) { {} }
6
+ let(:stub_body) do
7
+ {
8
+ "uri" => stub_uri,
9
+ "method" => stub_method,
10
+ "parameters" => stub_parameters,
11
+ "response" => {
12
+ "status" => 201,
13
+ "body" => "Foo"
14
+ }
15
+ }.to_json
16
+ end
17
+ let(:stub_request) { double("HttpRequest", :body => double("HttpRequestBody", :read => stub_body)) }
18
+ let(:stub_instance) { Http::Stub::Stub.new(stub_request) }
19
+
20
+ describe "#stubs?" do
21
+
22
+ let(:request_uri) { stub_uri }
23
+ let(:request_method) { stub_method }
24
+ let(:request_parameters) { stub_parameters }
25
+ let(:request) do
26
+ double("HttpRequest", :path_info => request_uri, :request_method => request_method, :params => request_parameters)
27
+ end
28
+
29
+ describe "when the request uri matches" do
30
+
31
+ describe "and the request method matches" do
32
+
33
+ describe "and a parameter match is configured" do
34
+
35
+ let(:stub_parameters) do
36
+ {
37
+ "param1" => "value1",
38
+ "param2" => "value2",
39
+ "param3" => "value3"
40
+ }
41
+ end
42
+
43
+ describe "and the parameters match" do
44
+
45
+ it "should return true" do
46
+ stub_instance.stubs?(request).should be_true
47
+ end
48
+
49
+ end
50
+
51
+ describe "and the parameter values do not match" do
52
+
53
+ let(:request_parameters) do
54
+ {
55
+ "param1" => "value1",
56
+ "param2" => "aDifferentValue",
57
+ "param3" => "value3"
58
+ }
59
+ end
60
+
61
+ it "should return false" do
62
+ stub_instance.stubs?(request).should be_false
63
+ end
64
+
65
+ end
66
+
67
+ describe "and not all parameters are provided" do
68
+
69
+ let(:request_parameters) do
70
+ {
71
+ "param1" => "value1",
72
+ "param3" => "value3"
73
+ }
74
+ end
75
+
76
+ it "should be false" do
77
+ stub_instance.stubs?(request).should be_false
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
86
+ end
87
+
88
+ describe "when the request uri does not match" do
89
+
90
+ let(:request_uri) { "/a_different_path" }
91
+
92
+ it "should return false" do
93
+ stub_instance.stubs?(request).should be_false
94
+ end
95
+
96
+ end
97
+
98
+ describe "when the request method does not match" do
99
+
100
+ let(:request_method) { "post" }
101
+
102
+ it "should return false" do
103
+ stub_instance.stubs?(request).should be_false
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ describe "#response" do
111
+
112
+ it "should expose the provided response status" do
113
+ stub_instance.response.status.should eql(201)
114
+ end
115
+
116
+ it "should expose the provided response body" do
117
+ stub_instance.response.body.should eql("Foo")
118
+ end
119
+
120
+ end
121
+
122
+ describe "#to_s" do
123
+
124
+ let(:stub_parameters) do
125
+ {
126
+ "param1" => "value1",
127
+ "param2" => "value2",
128
+ "param3" => "value3"
129
+ }
130
+ end
131
+
132
+ it "should return a string containing the stubbed uri" do
133
+ stub_instance.to_s.should match(/\/a_path/)
134
+ end
135
+
136
+ it "should return a string containing the stubbed request method" do
137
+ stub_instance.to_s.should match(/get/)
138
+ end
139
+
140
+ it "should return a string containing the stubbed parameters" do
141
+ stub_parameters.each_pair do |key, value|
142
+ stub_instance.to_s.should match(/#{Regexp.escape(key)}/)
143
+ stub_instance.to_s.should match(/#{Regexp.escape(value)}/)
144
+ end
145
+ end
146
+
147
+ it "should return a string containing the intended response code" do
148
+ stub_instance.to_s.should match(/201/)
149
+ end
150
+
151
+ it "should return a string containing the intended response body" do
152
+ stub_instance.to_s.should match(/Foo/)
153
+ end
154
+
155
+ end
156
+
157
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_stub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-02-10 00:00:00.000000000 Z
13
+ date: 2013-02-11 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sinatra
@@ -28,6 +28,22 @@ dependencies:
28
28
  - - ~>
29
29
  - !ruby/object:Gem::Version
30
30
  version: 1.3.4
31
+ - !ruby/object:Gem::Dependency
32
+ name: immutable_struct
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 1.1.0
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.0
31
47
  description: Configure server responses via requests to /stub. Intended as an acceptance
32
48
  / integration testing tool.
33
49
  email: matthew.ueckerman@myob.com
@@ -37,13 +53,17 @@ extra_rdoc_files: []
37
53
  files:
38
54
  - ./lib/http/stub/client.rb
39
55
  - ./lib/http/stub/rake_task.rb
56
+ - ./lib/http/stub/registry.rb
40
57
  - ./lib/http/stub/server.rb
58
+ - ./lib/http/stub/stub.rb
41
59
  - ./lib/http/stub/version.rb
42
60
  - ./lib/http_stub.rb
43
61
  - ./spec/curl_sample.txt
44
62
  - ./spec/lib/http/client_integration_spec.rb
45
63
  - ./spec/lib/http/rake_task_integration_spec.rb
64
+ - ./spec/lib/http/registry_spec.rb
46
65
  - ./spec/lib/http/server_spec.rb
66
+ - ./spec/lib/http/stub_spec.rb
47
67
  - ./spec/spec_helper.rb
48
68
  - ./spec/support/server_integration.rb
49
69
  homepage: http://github.com/MYOB-Technology/http_stub
@@ -67,7 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
87
  version: '0'
68
88
  segments:
69
89
  - 0
70
- hash: -1339898744489492428
90
+ hash: 2752646787075504105
71
91
  requirements: []
72
92
  rubyforge_project: http_stub
73
93
  rubygems_version: 1.8.25
@@ -78,6 +98,8 @@ test_files:
78
98
  - ./spec/curl_sample.txt
79
99
  - ./spec/lib/http/client_integration_spec.rb
80
100
  - ./spec/lib/http/rake_task_integration_spec.rb
101
+ - ./spec/lib/http/registry_spec.rb
81
102
  - ./spec/lib/http/server_spec.rb
103
+ - ./spec/lib/http/stub_spec.rb
82
104
  - ./spec/spec_helper.rb
83
105
  - ./spec/support/server_integration.rb