stub_requests 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +23 -0
- data/.editorconfig +13 -0
- data/.gitignore +10 -0
- data/.mdlrc +1 -0
- data/.reek.yml +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +112 -0
- data/.ruby-version +1 -0
- data/.simplecov +23 -0
- data/.travis.yml +37 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +0 -0
- data/CODE_OF_CONDUCT.md +64 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +138 -0
- data/Rakefile +8 -0
- data/_config.yml +1 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/index.md +37 -0
- data/lib/stub_requests/api.rb +73 -0
- data/lib/stub_requests/argument_validation.rb +39 -0
- data/lib/stub_requests/core_ext/all.rb +3 -0
- data/lib/stub_requests/core_ext/object/blank.rb +171 -0
- data/lib/stub_requests/core_ext.rb +3 -0
- data/lib/stub_requests/endpoint.rb +100 -0
- data/lib/stub_requests/endpoint_registry.rb +157 -0
- data/lib/stub_requests/hash_util.rb +30 -0
- data/lib/stub_requests/service.rb +118 -0
- data/lib/stub_requests/service_registry.rb +105 -0
- data/lib/stub_requests/stub_requests.rb +90 -0
- data/lib/stub_requests/uri/builder.rb +226 -0
- data/lib/stub_requests/uri/scheme.rb +34 -0
- data/lib/stub_requests/uri/suffix.rb +31 -0
- data/lib/stub_requests/uri/validator.rb +69 -0
- data/lib/stub_requests/version.rb +13 -0
- data/lib/stub_requests/webmock_builder.rb +108 -0
- data/lib/stub_requests.rb +25 -0
- data/stub_requests.gemspec +56 -0
- metadata +363 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "concurrent/map"
|
5
|
+
|
6
|
+
#
|
7
|
+
# Abstraction over WebMock to reduce duplication
|
8
|
+
#
|
9
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
10
|
+
# @since 0.1.0
|
11
|
+
#
|
12
|
+
module StubRequests
|
13
|
+
#
|
14
|
+
# Class ServiceRegistry provides registration of services
|
15
|
+
#
|
16
|
+
class ServiceRegistry
|
17
|
+
include Singleton
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
#
|
21
|
+
# @!attribute [rw] services
|
22
|
+
# @return [Concurrent::Map<Symbol, Service>] a map with services
|
23
|
+
attr_reader :services
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@services = Concurrent::Map.new
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Resets the map with registered services
|
31
|
+
#
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
def reset
|
35
|
+
services.clear
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Required by Enumerable
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# @return [Concurrent::Map<Symbol, Service>] an map with services
|
43
|
+
#
|
44
|
+
# @yield used by Enumerable
|
45
|
+
#
|
46
|
+
def each(&block)
|
47
|
+
services.each(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Registers a service in the registry
|
52
|
+
#
|
53
|
+
#
|
54
|
+
# @param [Symbol] service_id a symbolic id of the service
|
55
|
+
# @param [String] service_uri a string with a base_uri to the service
|
56
|
+
#
|
57
|
+
# @return [Service] the service that was just registered
|
58
|
+
#
|
59
|
+
def register_service(service_id, service_uri)
|
60
|
+
if (service = get_service(service_id))
|
61
|
+
StubRequests.logger.warn("Service already registered #{service}")
|
62
|
+
raise ServiceHaveEndpoints, service if service.endpoints?
|
63
|
+
end
|
64
|
+
services[service_id] = Service.new(service_id, service_uri)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Removes a service from the registry
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# @param [Symbol] service_id the service_id to remove
|
72
|
+
#
|
73
|
+
# @raise [ServiceNotFound] when the service was not removed
|
74
|
+
#
|
75
|
+
def remove_service(service_id)
|
76
|
+
services.delete(service_id) || raise(ServiceNotFound, service_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Fetches a service from the registry
|
81
|
+
#
|
82
|
+
#
|
83
|
+
# @param [Symbol] service_id id of the service to remove
|
84
|
+
#
|
85
|
+
# @return [Service] the found service
|
86
|
+
#
|
87
|
+
def get_service(service_id)
|
88
|
+
services[service_id]
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Fetches a service from the registry or raises {ServiceNotFound}
|
93
|
+
#
|
94
|
+
#
|
95
|
+
# @param [Symbol] service_id the id of a service
|
96
|
+
#
|
97
|
+
# @raise [ServiceNotFound] when an endpoint couldn't be found
|
98
|
+
#
|
99
|
+
# @return [Endpoint]
|
100
|
+
#
|
101
|
+
def get_service!(service_id)
|
102
|
+
get_service(service_id) || raise(ServiceNotFound, service_id)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Error is a base class for all gem errors
|
12
|
+
#
|
13
|
+
class Error < StandardError; end
|
14
|
+
|
15
|
+
#
|
16
|
+
# ServiceHaveEndpoints is raised to prevent overwriting a registered service's endpoints
|
17
|
+
#
|
18
|
+
class ServiceHaveEndpoints < StandardError
|
19
|
+
def initialize(service)
|
20
|
+
super("Service with id #{service.id} have already been registered. #{service}")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# InvalidType is raised when an argument is invalid
|
26
|
+
#
|
27
|
+
class InvalidType < Error
|
28
|
+
def initialize(actual:, expected:)
|
29
|
+
super("Expected `#{actual}` to be any of [#{expected}]")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# EndpointNotFound is raised when an endpoint cannot be found
|
35
|
+
#
|
36
|
+
class EndpointNotFound < Error; end
|
37
|
+
|
38
|
+
#
|
39
|
+
# ServiceNotFound is raised when a service cannot be found
|
40
|
+
#
|
41
|
+
class ServiceNotFound < Error
|
42
|
+
def initialize(service_id)
|
43
|
+
super("Couldn't find a service with id=:#{service_id}")
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# UriSegmentMismatch is raised when a segment cannot be replaced
|
49
|
+
#
|
50
|
+
class UriSegmentMismatch < Error; end
|
51
|
+
|
52
|
+
#
|
53
|
+
# InvalidUri is raised when a URI is invalid
|
54
|
+
#
|
55
|
+
class InvalidUri < Error
|
56
|
+
def initialize(uri)
|
57
|
+
super("'#{uri}' is not a valid URI.")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# extends "self"
|
62
|
+
# @!parse extend self
|
63
|
+
extend self
|
64
|
+
|
65
|
+
# includes "UriFor" and extends "UriFor"
|
66
|
+
# using the API.included callback
|
67
|
+
# @!parse include UriFor
|
68
|
+
# @!parse extend UriFor
|
69
|
+
|
70
|
+
# includes "API" and extends "API"
|
71
|
+
# using the API.included callback
|
72
|
+
# @!parse include API
|
73
|
+
# @!parse extend API
|
74
|
+
include API
|
75
|
+
|
76
|
+
#
|
77
|
+
# @!attribute [rw] logger
|
78
|
+
# @return [Logger] the logger to use in the gem
|
79
|
+
attr_accessor :logger
|
80
|
+
|
81
|
+
#
|
82
|
+
# The current version of the gem
|
83
|
+
#
|
84
|
+
#
|
85
|
+
# @return [String] version string, `"1.0.0"`
|
86
|
+
#
|
87
|
+
def version
|
88
|
+
VERSION
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Builds a URI from a #host, #template and #replacements
|
12
|
+
#
|
13
|
+
module URI
|
14
|
+
#
|
15
|
+
# Builder constructs and validates URIs
|
16
|
+
#
|
17
|
+
# :reek:TooManyInstanceVariables { max_instance_variables: 6 }
|
18
|
+
class Builder
|
19
|
+
#
|
20
|
+
# @return [Regexp] A pattern for matching url segment keys
|
21
|
+
URL_SEGMENT_REGEX = /(:\w+)/.freeze
|
22
|
+
|
23
|
+
#
|
24
|
+
# Convenience method to avoid .new.build
|
25
|
+
#
|
26
|
+
#
|
27
|
+
# @raise [UriSegmentMismatch] when there are unused URI segments
|
28
|
+
# @raise [UriSegmentMismatch] when the template have unplaced URI segments
|
29
|
+
#
|
30
|
+
# @param [String] host the URI used to reach the service
|
31
|
+
# @param [String] template the endpoint template
|
32
|
+
# @param [Hash<Symbol>] replacements a list of uri_replacement keys
|
33
|
+
#
|
34
|
+
# @return [String] a validated URI string
|
35
|
+
#
|
36
|
+
def self.build(host, template, replacements = {})
|
37
|
+
new(host, template, replacements).build
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# @!attribute [r] uri
|
42
|
+
# @return [String] the request host {Service#service_uri}
|
43
|
+
attr_reader :host
|
44
|
+
#
|
45
|
+
# @!attribute [r] template
|
46
|
+
# @return [String] a string template for the endpoint
|
47
|
+
attr_reader :template
|
48
|
+
#
|
49
|
+
# @!attribute [r] path
|
50
|
+
# @return [String] a valid URI path
|
51
|
+
attr_reader :path
|
52
|
+
#
|
53
|
+
# @!attribute [r] replacements
|
54
|
+
# @return [Hash<Symbol] a hash with keys matching the {#template}
|
55
|
+
attr_reader :replacements
|
56
|
+
#
|
57
|
+
# @!attribute [r] unused
|
58
|
+
# @return [Array<String>] a list with unused {#replacements}
|
59
|
+
attr_reader :unused
|
60
|
+
#
|
61
|
+
# @!attribute [r] unreplaced
|
62
|
+
# @return [Array<String>] a list of uri_segments that should have been replaced
|
63
|
+
attr_reader :unreplaced
|
64
|
+
|
65
|
+
#
|
66
|
+
# Initializes a new Builder
|
67
|
+
#
|
68
|
+
#
|
69
|
+
# @param [String] host the URI used to reach the service
|
70
|
+
# @param [String] template the endpoint template
|
71
|
+
# @param [Hash<Symbol>] replacements a list of uri_replacement keys
|
72
|
+
#
|
73
|
+
def initialize(host, template, replacements = {})
|
74
|
+
@host = +host
|
75
|
+
@template = +template
|
76
|
+
@path = +@template.dup
|
77
|
+
@replacements = replacements
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Builds a URI string
|
82
|
+
#
|
83
|
+
#
|
84
|
+
# @raise [UriSegmentMismatch] when there are unused URI segments
|
85
|
+
# @raise [UriSegmentMismatch] when the template have unplaced URI segments
|
86
|
+
#
|
87
|
+
# @return [String] a validated URI string
|
88
|
+
#
|
89
|
+
def build
|
90
|
+
build_uri
|
91
|
+
run_validations
|
92
|
+
|
93
|
+
uri
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def build_uri
|
99
|
+
replace_segments
|
100
|
+
parse_unreplaced_segments
|
101
|
+
end
|
102
|
+
|
103
|
+
def uri
|
104
|
+
@uri ||= [host, path].join("/")
|
105
|
+
end
|
106
|
+
|
107
|
+
def run_validations
|
108
|
+
validate_replacements_used
|
109
|
+
validate_segments_replaced
|
110
|
+
validate_uri
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# Replaces the URI segments with the arguments in replacements
|
115
|
+
#
|
116
|
+
#
|
117
|
+
# @return [Array] an list with unused replacements
|
118
|
+
#
|
119
|
+
def replace_segments
|
120
|
+
@unused = replacements.map do |key, value|
|
121
|
+
uri_segment = ":#{key}"
|
122
|
+
if path.include?(uri_segment)
|
123
|
+
path.gsub!(uri_segment.to_s, value.to_s)
|
124
|
+
next
|
125
|
+
else
|
126
|
+
uri_segment
|
127
|
+
end
|
128
|
+
end.compact
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Validates that all replacements have been used
|
133
|
+
#
|
134
|
+
#
|
135
|
+
# @raise [UriSegmentMismatch] when there are unused replacements
|
136
|
+
#
|
137
|
+
# @return [void]
|
138
|
+
#
|
139
|
+
def validate_replacements_used
|
140
|
+
return if replacents_used?
|
141
|
+
|
142
|
+
raise UriSegmentMismatch,
|
143
|
+
"The URI segment(s) [#{unused.join(',')}] are missing in template (#{path})"
|
144
|
+
end
|
145
|
+
|
146
|
+
#
|
147
|
+
# Checks that no replacements are left
|
148
|
+
#
|
149
|
+
#
|
150
|
+
# @return [true,false]
|
151
|
+
#
|
152
|
+
def replacents_used?
|
153
|
+
unused.none?
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Validates that all URI segments have been replaced in {#path}
|
158
|
+
#
|
159
|
+
#
|
160
|
+
# @raise [UriSegmentMismatch] when the path have unplaced URI segments
|
161
|
+
#
|
162
|
+
# @return [void]
|
163
|
+
#
|
164
|
+
def validate_segments_replaced
|
165
|
+
return if segments_replaced?
|
166
|
+
|
167
|
+
raise UriSegmentMismatch,
|
168
|
+
"The URI segment(s) [#{unreplaced.join(',')}]" \
|
169
|
+
" were not replaced in template (#{path})." \
|
170
|
+
" Given replacements=[#{segment_keys.join(',')}]"
|
171
|
+
end
|
172
|
+
|
173
|
+
def segment_keys
|
174
|
+
@segment_keys ||= replacements.keys.map { |segment_key| ":#{segment_key}" }
|
175
|
+
end
|
176
|
+
|
177
|
+
#
|
178
|
+
# Checks that all URI segments were replaced
|
179
|
+
#
|
180
|
+
#
|
181
|
+
# @return [true,false]
|
182
|
+
#
|
183
|
+
def segments_replaced?
|
184
|
+
unreplaced.none?
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Parses out all unused URI segments
|
189
|
+
#
|
190
|
+
#
|
191
|
+
# @return [Array<String>] a list of not replaced uri_segments
|
192
|
+
#
|
193
|
+
def parse_unreplaced_segments
|
194
|
+
@unreplaced = URL_SEGMENT_REGEX.match(path).to_a.uniq
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Validates {#uri} is valid
|
199
|
+
#
|
200
|
+
#
|
201
|
+
# @return [true, false]
|
202
|
+
#
|
203
|
+
def validate_uri
|
204
|
+
StubRequests::URI::Validator.valid?(uri)
|
205
|
+
rescue InvalidUri
|
206
|
+
StubRequests.logger.warn("URI (#{uri}) is not valid.")
|
207
|
+
false
|
208
|
+
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Raise exception when {#validate_uri} is false
|
212
|
+
#
|
213
|
+
# @see #validate_uri
|
214
|
+
#
|
215
|
+
# @raise [InvalidUri] when #{uri} is invalid
|
216
|
+
#
|
217
|
+
# @return [void]
|
218
|
+
#
|
219
|
+
# :nocov:
|
220
|
+
# :nodoc:
|
221
|
+
def validate_uri!
|
222
|
+
raise InvalidUri, uri unless validate_uri
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Provides convenience methods for URI
|
12
|
+
#
|
13
|
+
module URI
|
14
|
+
#
|
15
|
+
# Module Scheme handles validation of {URI} schemes
|
16
|
+
#
|
17
|
+
module Scheme
|
18
|
+
#
|
19
|
+
# @return [Array<String>] a list of valid HTTP schemes
|
20
|
+
SCHEMES = %w[http https].freeze
|
21
|
+
|
22
|
+
#
|
23
|
+
# Checks if the scheme is valid
|
24
|
+
#
|
25
|
+
# @param [String] scheme a string with the URI scheme to check
|
26
|
+
#
|
27
|
+
# @return [true,false]
|
28
|
+
#
|
29
|
+
def self.valid?(scheme)
|
30
|
+
SCHEMES.include?(scheme.to_s)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
module URI
|
11
|
+
#
|
12
|
+
# Module Suffix deals with validating {URI} suffix
|
13
|
+
#
|
14
|
+
module Suffix
|
15
|
+
#
|
16
|
+
# @return [RegExp] a pattern used for matching HTTP(S) ports
|
17
|
+
PORT_REGEX = %r{:(\d+)/}.freeze
|
18
|
+
|
19
|
+
#
|
20
|
+
# Checks if the host has a valid suffix
|
21
|
+
#
|
22
|
+
# @param [String] host a string to check
|
23
|
+
#
|
24
|
+
# @return [true,false]
|
25
|
+
#
|
26
|
+
def self.valid?(host)
|
27
|
+
PublicSuffix.valid?(host, default_rule: nil)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Provides convenience methods for URI
|
12
|
+
#
|
13
|
+
module URI
|
14
|
+
#
|
15
|
+
# Validator provides functionality for validating a {::URI}
|
16
|
+
#
|
17
|
+
class Validator
|
18
|
+
#
|
19
|
+
# Validates a URI
|
20
|
+
#
|
21
|
+
# @param [String] uri a full uri with path
|
22
|
+
#
|
23
|
+
# @return [true, false]
|
24
|
+
#
|
25
|
+
def self.valid?(uri)
|
26
|
+
new(uri).valid?
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# @!attribute [r] uri
|
31
|
+
# @return [String] a complete URI
|
32
|
+
attr_reader :uri
|
33
|
+
#
|
34
|
+
# @!attribute [r] host
|
35
|
+
# @return [String] the URI host
|
36
|
+
attr_reader :host
|
37
|
+
#
|
38
|
+
# @!attribute [r] scheme
|
39
|
+
# @return [String] the URI scheme
|
40
|
+
attr_reader :scheme
|
41
|
+
|
42
|
+
#
|
43
|
+
# Initialize a new instance of {Validator}
|
44
|
+
#
|
45
|
+
# @raise [InvalidUri] when URI can't be parsed
|
46
|
+
#
|
47
|
+
# @param [String] uri the full URI
|
48
|
+
#
|
49
|
+
#
|
50
|
+
def initialize(uri)
|
51
|
+
@uri = ::URI.parse(uri)
|
52
|
+
@host = @uri.host
|
53
|
+
@scheme = @uri.scheme
|
54
|
+
rescue ::URI::InvalidURIError
|
55
|
+
raise InvalidUri, uri
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Checks if a URI is valid
|
60
|
+
#
|
61
|
+
#
|
62
|
+
# @return [true,false] <description>
|
63
|
+
#
|
64
|
+
def valid?
|
65
|
+
URI::Scheme.valid?(scheme) && URI::Suffix.valid?(host)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# @return [String] a version string
|
12
|
+
VERSION = "0.1.0"
|
13
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Abstraction over WebMock to reduce duplication
|
5
|
+
#
|
6
|
+
# @author Mikael Henriksson <mikael@zoolutions.se>
|
7
|
+
# @since 0.1.0
|
8
|
+
#
|
9
|
+
module StubRequests
|
10
|
+
#
|
11
|
+
# Module API abstraction to reduce the amount of WebMock.stub_request
|
12
|
+
#
|
13
|
+
# @note This module can either be used by its class methods
|
14
|
+
# or included in say RSpec
|
15
|
+
#
|
16
|
+
class WebMockBuilder
|
17
|
+
include HashUtil
|
18
|
+
|
19
|
+
#
|
20
|
+
# Builds and registers a WebMock::RequestStub
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# @param [Symbol] verb a HTTP verb/method
|
24
|
+
# @param [String] uri a URI to call
|
25
|
+
# @param [Hash<Symbol>] options request/response options for Webmock::RequestStub
|
26
|
+
#
|
27
|
+
# @yield a callback to eventually yield to the caller
|
28
|
+
#
|
29
|
+
# @return [WebMock::RequestStub] the registered stub
|
30
|
+
#
|
31
|
+
def self.build(verb, uri, options = {}, &callback)
|
32
|
+
new(verb, uri, options, &callback).build
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# @!attribute [r] request_stub
|
37
|
+
# @return [WebMock::RequestStub] a stubbed webmock request
|
38
|
+
attr_reader :request_stub
|
39
|
+
#
|
40
|
+
# @!attribute [r] options
|
41
|
+
# @return [Hash<Symbol>] options for the stub_request
|
42
|
+
attr_reader :options
|
43
|
+
#
|
44
|
+
# @!attribute [r] callback
|
45
|
+
# @return [Block] call back when given a block
|
46
|
+
attr_reader :callback
|
47
|
+
|
48
|
+
#
|
49
|
+
# Initializes a new instance of
|
50
|
+
#
|
51
|
+
#
|
52
|
+
# @param [Symbol] verb a HTTP verb/method
|
53
|
+
# @param [String] uri a URI to call
|
54
|
+
# @param [Hash<Symbol>] options request/response options for Webmock::RequestStub
|
55
|
+
#
|
56
|
+
# @yield a block to eventually yield to the caller
|
57
|
+
#
|
58
|
+
def initialize(verb, uri, options = {}, &callback)
|
59
|
+
@request_stub = WebMock::RequestStub.new(verb, uri)
|
60
|
+
@options = options
|
61
|
+
@callback = callback
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Prepares a WebMock::RequestStub and registers it in WebMock
|
66
|
+
#
|
67
|
+
#
|
68
|
+
# @return [WebMock::RequestStub] the registered stub
|
69
|
+
#
|
70
|
+
def build
|
71
|
+
if callback.present?
|
72
|
+
Docile.dsl_eval(request_stub, &callback)
|
73
|
+
else
|
74
|
+
prepare_mock_request
|
75
|
+
end
|
76
|
+
|
77
|
+
WebMock::StubRegistry.instance.register_request_stub(request_stub)
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def prepare_mock_request
|
83
|
+
prepare_with
|
84
|
+
prepare_to_return
|
85
|
+
prepare_to_raise
|
86
|
+
request_stub.to_timeout if options[:timeout]
|
87
|
+
request_stub
|
88
|
+
end
|
89
|
+
|
90
|
+
def prepare_with
|
91
|
+
HashUtil.compact(options[:request]) do |request_options|
|
92
|
+
request_stub.with(request_options)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def prepare_to_return
|
97
|
+
HashUtil.compact(options[:response]) do |response_options|
|
98
|
+
request_stub.to_return(response_options)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def prepare_to_raise
|
103
|
+
return unless (error = options[:error])
|
104
|
+
|
105
|
+
request_stub.to_raise(*Array(error))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "singleton"
|
4
|
+
require "docile"
|
5
|
+
require "webmock"
|
6
|
+
require "webmock/api"
|
7
|
+
|
8
|
+
require "stub_requests/version"
|
9
|
+
|
10
|
+
require "stub_requests/core_ext"
|
11
|
+
require "stub_requests/hash_util"
|
12
|
+
require "stub_requests/argument_validation"
|
13
|
+
require "stub_requests/endpoint"
|
14
|
+
require "stub_requests/endpoint_registry"
|
15
|
+
require "stub_requests/service"
|
16
|
+
require "stub_requests/service_registry"
|
17
|
+
require "stub_requests/uri/scheme"
|
18
|
+
require "stub_requests/uri/suffix"
|
19
|
+
require "stub_requests/uri/validator"
|
20
|
+
require "stub_requests/uri/builder"
|
21
|
+
require "stub_requests/webmock_builder"
|
22
|
+
|
23
|
+
require "stub_requests/api"
|
24
|
+
|
25
|
+
require "stub_requests/stub_requests"
|