http_stub 0.0.2 → 0.0.3

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.
@@ -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