stub_requests 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.reek.yml +1 -0
  3. data/CHANGELOG.md +2 -0
  4. data/README.md +2 -2
  5. data/lib/stub_requests/api.rb +8 -22
  6. data/lib/stub_requests/callback.rb +58 -0
  7. data/lib/stub_requests/callback_registry.rb +188 -0
  8. data/lib/stub_requests/core_ext/all.rb +1 -0
  9. data/lib/stub_requests/core_ext/array/extract_options.rb +4 -6
  10. data/lib/stub_requests/core_ext/class/attribute.rb +2 -3
  11. data/lib/stub_requests/core_ext/kernel/singleton_class.rb +2 -3
  12. data/lib/stub_requests/core_ext/module/redefine_method.rb +6 -0
  13. data/lib/stub_requests/core_ext/object/blank.rb +21 -22
  14. data/lib/stub_requests/core_ext/string/to_route_param.rb +35 -0
  15. data/lib/stub_requests/dsl/define_method.rb +49 -0
  16. data/lib/stub_requests/dsl/method_definition.rb +72 -0
  17. data/lib/stub_requests/dsl.rb +94 -0
  18. data/lib/stub_requests/endpoint.rb +48 -36
  19. data/lib/stub_requests/endpoint_stub.rb +89 -0
  20. data/lib/stub_requests/endpoints.rb +147 -0
  21. data/lib/stub_requests/observable.rb +0 -44
  22. data/lib/stub_requests/request_stub.rb +80 -0
  23. data/lib/stub_requests/service.rb +77 -0
  24. data/lib/stub_requests/service_registry.rb +174 -0
  25. data/lib/stub_requests/stub_registry.rb +159 -0
  26. data/lib/stub_requests/uri/builder.rb +27 -34
  27. data/lib/stub_requests/uri.rb +31 -4
  28. data/lib/stub_requests/version.rb +1 -1
  29. data/lib/stub_requests/webmock/stub_registry_extension.rb +1 -1
  30. data/lib/stub_requests.rb +12 -12
  31. data/lib/tasks/changelog.rake +2 -1
  32. metadata +14 -16
  33. data/gemfiles/webmock_2.3.gemfile.lock +0 -206
  34. data/gemfiles/webmock_3.5.gemfile.lock +0 -206
  35. data/gemfiles/webmock_develop.gemfile.lock +0 -211
  36. data/lib/stub_requests/metrics/endpoint.rb +0 -98
  37. data/lib/stub_requests/metrics/registry.rb +0 -132
  38. data/lib/stub_requests/metrics/request.rb +0 -89
  39. data/lib/stub_requests/metrics.rb +0 -33
  40. data/lib/stub_requests/observable/registry.rb +0 -152
  41. data/lib/stub_requests/observable/subscription.rb +0 -58
  42. data/lib/stub_requests/registration/endpoint.rb +0 -107
  43. data/lib/stub_requests/registration/endpoints.rb +0 -156
  44. data/lib/stub_requests/registration/registry.rb +0 -112
  45. data/lib/stub_requests/registration/service.rb +0 -85
  46. data/lib/stub_requests/registration.rb +0 -87
@@ -1,98 +0,0 @@
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 Metrics contains logic for collecting metrics about requests stubs
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.2
15
- #
16
- # :reek:TooManyInstanceVariables
17
- module Metrics
18
- #
19
- # Class Endpoint provides metrics for stubbed endpoints
20
- #
21
- # @author Mikael Henriksson <mikael@zoolutions.se>
22
- # @since 0.1.2
23
- #
24
- class Endpoint
25
- # includes "Enumerable"
26
- # @!parse include Enumerable
27
- include Enumerable
28
- # @api private
29
- include Property
30
- # @api private
31
-
32
- #
33
- # @!attribute [r] service_id
34
- # @return [Symbol] the id of a {StubRequests::Registration::Service}
35
- property :service_id, type: Symbol
36
- #
37
- # @!attribute [r] endpoint_id
38
- # @return [Symbol] the id of an endpoint
39
- property :endpoint_id, type: Symbol
40
- #
41
- # @!attribute [r] verb
42
- # @return [String] the HTTP verb/method for this endpoint
43
- property :verb, type: Symbol
44
- #
45
- # @!attribute [r] uri_template
46
- # @return [String] the full URI template for the endpoint
47
- property :uri_template, type: String
48
- #
49
- # @!attribute [r] stubs
50
- # @return [Array] an array with recorded requests
51
- attr_reader :requests
52
-
53
- #
54
- # Initializes a new Endpoint
55
- #
56
- # @param [Registration::Service] service a service
57
- # @param [Registration::Endpoint] endpoint an endpoint
58
- #
59
- def initialize(service, endpoint)
60
- self.service_id = service.id
61
- self.endpoint_id = endpoint.id
62
- self.verb = endpoint.verb
63
- self.uri_template = [service.uri, endpoint.uri_template].join("/")
64
-
65
- @requests = Concurrent::Array.new
66
- end
67
-
68
- def find_by(attribute:, value:)
69
- find { |request| request.send(attribute) == value }
70
- end
71
-
72
- #
73
- # Required by Enumerable
74
- #
75
- #
76
- # @return [Concurrent::Map<Symbol, Service>] an map with services
77
- #
78
- # @yield used by Enumerable
79
- #
80
- def each(&block)
81
- requests.each(&block)
82
- end
83
-
84
- #
85
- # Records a WebMock::RequestStub as stubbed
86
- #
87
- # @param [WebMock::RequestStub] request_stub <description>
88
- #
89
- # @return [Record]
90
- #
91
- def record(request_stub)
92
- request = Request.new(self, request_stub)
93
- requests.push(request)
94
- request
95
- end
96
- end
97
- end
98
- end
@@ -1,132 +0,0 @@
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 Metrics contains logic for collecting metrics about requests stubs
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.2
15
- #
16
- # :reek:DataClump
17
- module Metrics
18
- #
19
- # Class Registry maintains a registry of stubbed endpoints.
20
- # Also allows provides querying capabilities for said entities.
21
- #
22
- # @author Mikael Henriksson <mikael@zoolutions.se>
23
- # @since 0.1.2
24
- #
25
- class Registry
26
- # includes "Singleton"
27
- # @!parse include Singleton
28
- include Singleton
29
- # includes "Enumerable"
30
- # @!parse include Enumerable
31
- include Enumerable
32
-
33
- #
34
- # @!attribute [rw] services
35
- # @return [Concurrent::Array<Endpoint>] a map with stubbed endpoints
36
- attr_reader :endpoints
37
-
38
- #
39
- # Initialize a new registry
40
- #
41
- #
42
- def initialize
43
- @endpoints = Concurrent::Array.new
44
- end
45
-
46
- #
47
- # Resets the map with stubbed endpoints
48
- #
49
- #
50
- # @api private
51
- def reset
52
- endpoints.clear
53
- end
54
-
55
- #
56
- # Required by Enumerable
57
- #
58
- #
59
- # @return [Concurrent::Array<Endpoint>] an array with stubbed endpoints
60
- #
61
- # @yield used by Enumerable
62
- #
63
- def each(&block)
64
- endpoints.each(&block)
65
- end
66
-
67
- #
68
- # Records metrics about stubbed endpoints
69
- #
70
- #
71
- # @param [Registration::Service] service a symbolic id of the service
72
- # @param [Registration::Endpoint] endpoint a string with a base_uri to the service
73
- # @param [WebMock::RequestStub] request_stub the stubbed request
74
- #
75
- # @return [Service] the service that was just registered
76
- #
77
- def record(service, endpoint, request_stub)
78
- endpoint = find_or_initialize_endpoint(service, endpoint)
79
- endpoint.record(request_stub)
80
-
81
- endpoints.push(endpoint)
82
- endpoint
83
- end
84
-
85
- #
86
- # Mark a {Request} as having responded
87
- #
88
- # @note Called when webmock responds successfully
89
- #
90
- # @param [WebMock::RequestStub] request_stub the stubbed webmock request
91
- #
92
- # @return [void]
93
- #
94
- def mark_as_responded(request_stub)
95
- return unless (request = find_request(request_stub))
96
-
97
- request.mark_as_responded
98
- end
99
-
100
- #
101
- # Finds a {Request} amongst the endpoint stubs
102
- #
103
- #
104
- # @param [WebMock::RequestStub] request_stub a stubbed webmock response
105
- #
106
- # @return [Request] the request_stubbed matching the request stub
107
- #
108
- def find_request(request_stub)
109
- map do |endpoint|
110
- endpoint.find_by(attribute: :request_stub, value: request_stub)
111
- end.compact.first
112
- end
113
-
114
- private
115
-
116
- def find_or_initialize_endpoint(service, endpoint)
117
- find_endpoint(service, endpoint) || initialize_endpoint(service, endpoint)
118
- end
119
-
120
- # :reek:UtilityFunction
121
- # :reek:FeatureEnvy
122
- def find_endpoint(service, endpoint)
123
- find { |ep| ep.service_id == service.id && ep.endpoint_id == endpoint.id }
124
- end
125
-
126
- # :reek:UtilityFunction
127
- def initialize_endpoint(service, endpoint)
128
- Metrics::Endpoint.new(service, endpoint)
129
- end
130
- end
131
- end
132
- end
@@ -1,89 +0,0 @@
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 Metrics contains logic for collecting metrics about requests stubs
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.2
15
- #
16
- module Metrics
17
- #
18
- # Class Stub tracks the WebMock::RequestStub life cycle
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- # @since 0.1.2
22
- #
23
- # :reek:TooManyInstanceVariables
24
- class Request
25
- include Property
26
- extend Forwardable
27
-
28
- # Delegate service_id, endpoint_id, verb and uri_template to endpoint
29
- delegate [:service_id, :endpoint_id, :verb, :uri_template] => :endpoint
30
- #
31
- # @!attribute [r] endpoint
32
- # @return [StubRequests::Metrics::Endpoint] a stubbed endpoint
33
- property :endpoint, type: StubRequests::Metrics::Endpoint
34
- #
35
- # @!attribute [r] verb
36
- # @return [Symbol] a HTTP verb/method
37
- property :verb, type: Symbol
38
- #
39
- # @!attribute [r] uri
40
- # @return [String] the full URI for this endpoint
41
- property :uri, type: String
42
- #
43
- # @!attribute [r] request_stub
44
- # @return [WebMock::RequestStub] a webmock stubbed request
45
- property :request_stub, type: WebMock::RequestStub
46
- #
47
- # @!attribute [r] recorded_at
48
- # @return [Time] the time this record was recorded
49
- property :recorded_at, type: Time
50
- #
51
- # @!attribute [r] recorded_from
52
- # @return [String] the relative path to the spec that recorded it
53
- property :recorded_from, type: String
54
- #
55
- # @!attribute [r] responded_at
56
- # @return [Time] the time this stubs response was used
57
- property :responded_at, type: Time
58
-
59
- #
60
- # Initialize a new Record
61
- #
62
- #
63
- # @param [Endpoint] endpoint a stubbed endpoint
64
- # @param [WebMock::RequestStub] request_stub the stubbed webmock request
65
- #
66
- def initialize(endpoint, request_stub)
67
- request_pattern = request_stub.request_pattern
68
- self.endpoint = endpoint
69
- self.verb = request_pattern.method_pattern.to_s.to_sym
70
- self.uri = request_pattern.uri_pattern.to_s
71
- self.request_stub = request_stub
72
- self.recorded_at = Time.now
73
- self.recorded_from = RSpec.current_example.metadata[:location]
74
- @responded_at = nil # ByPass the validation for the initializer
75
- end
76
-
77
- #
78
- # Marks this record as having responded
79
- #
80
- #
81
- # @return [Time] the time it was marked responded
82
- #
83
- def mark_as_responded
84
- self.responded_at = Time.now
85
- Observable.notify_subscribers(self)
86
- end
87
- end
88
- end
89
- end
@@ -1,33 +0,0 @@
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 Metrics contains logic for collecting metrics about {Metrics::Endpoint} and {Metrics::Request}
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.2
15
- #
16
- module Metrics
17
- #
18
- # Records metrics about stubbed endpoints
19
- #
20
- #
21
- # @param [Registration::Service] service a Service
22
- # @param [Registration::Endpoint] endpoint an Endpoint
23
- # @param [WebMock::RequestStub] endpoint_stub the stubbed webmock request
24
- #
25
- # @return [Metrics::Endpoint] the stat that was recorded
26
- #
27
- def self.record(service, endpoint, endpoint_stub)
28
- return unless StubRequests.config.record_metrics?
29
-
30
- Registry.instance.record(service, endpoint, endpoint_stub)
31
- end
32
- end
33
- end
@@ -1,152 +0,0 @@
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 Observable handles listening to endpoint invocations
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.3
15
- #
16
- module Observable
17
- #
18
- # Class Registry handles subscriptions to webmock requests
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- # @since 0.1.3
22
- #
23
- # :reek:UtilityFunction
24
- # :reek:DataClump
25
- # :reek:FeatureEnvy
26
- class Registry
27
- include Singleton
28
- include Enumerable
29
-
30
- #
31
- # @!attribute [r] subscriptions
32
- # @return [Concurrent::Array<Subscription>] a list of subscriptions
33
- attr_reader :subscriptions
34
-
35
- #
36
- # Used by Singleton
37
- #
38
- #
39
- def initialize
40
- @subscriptions = Concurrent::Array.new
41
- end
42
-
43
- #
44
- # Resets the map with registered services
45
- #
46
- #
47
- # @api private
48
- def reset
49
- subscriptions.clear
50
- end
51
-
52
- #
53
- # Required by Enumerable
54
- #
55
- #
56
- # @return [Concurrent::Array<Subscription>] a list with subscriptions
57
- #
58
- # @yield used by Enumerable
59
- #
60
- def each(&block)
61
- subscriptions.each(&block)
62
- end
63
-
64
- #
65
- # Subscribe to a service endpoint call
66
- #
67
- #
68
- # @param [Symbol] service_id the id of a service
69
- # @param [Symbol] endpoint_id the id of an endpoint
70
- # @param [optional, Symbol] verb the HTTP verb to subscribe to
71
- # @param [proc] callback the callback to use for when.a request was made
72
- #
73
- # @return [Subscription] the added subscription
74
- #
75
- # :reek:LongParameterList
76
- def subscribe(service_id, endpoint_id, verb, callback)
77
- subscription = find_by(service_id, endpoint_id, verb)
78
- return subscription if subscription
79
-
80
- subscription = Subscription.new(service_id, endpoint_id, verb, callback)
81
- subscriptions.push(subscription)
82
- subscription
83
- end
84
-
85
- #
86
- # Unsubscribe to a service endpoint call
87
- #
88
- #
89
- # @param [Symbol] service_id the id of a service
90
- # @param [Symbol] endpoint_id the id of an endpoint
91
- # @param [optional, Symbol] verb the HTTP verb to subscribe to
92
- #
93
- # @return [Subscription] the deleted subscription
94
- #
95
- # :reek:ControlParameter
96
- def unsubscribe(service_id, endpoint_id, verb)
97
- return unless (subscription = find_by(service_id, endpoint_id, verb))
98
-
99
- subscriptions.delete(subscription)
100
- end
101
-
102
- #
103
- # Notifies subscribers that a request was made
104
- #
105
- # @param [Metrics::Request] request the stubbed request
106
- #
107
- # @return [void]
108
- #
109
- def notify_subscribers(request)
110
- return unless (subscription = find_by(request.service_id, request.endpoint_id, request.verb))
111
-
112
- send_notification(request, subscription)
113
- end
114
-
115
- private
116
-
117
- #
118
- # Finds a subscription for a service endpoint
119
- #
120
- #
121
- # @param [Symbol] service_id the id of a service
122
- # @param [Symbol] endpoint_id the id of an endpoint
123
- # @param [optional, Symbol] verb the HTTP verb to subscribe to
124
- #
125
- # @return [Subscription]
126
- #
127
- # :reek:ControlParameter
128
- # :reek:DuplicateMethodCall
129
- def find_by(service_id, endpoint_id, verb)
130
- find do |sub|
131
- sub.service_id == service_id &&
132
- sub.endpoint_id == endpoint_id &&
133
- ([sub.verb, verb].include?(:any) || sub.verb == verb)
134
- end
135
- end
136
-
137
- def send_notification(request, subscription)
138
- callback = subscription.callback
139
- arity = callback.arity
140
-
141
- case arity
142
- when 0
143
- callback.call
144
- when 1
145
- callback.call(request)
146
- else
147
- raise InvalidCallback, "The callback for a subscription can either take 0 or 1 arguments (was #{arity})"
148
- end
149
- end
150
- end
151
- end
152
- end
@@ -1,58 +0,0 @@
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 Observable handles listening to endpoint invocations
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.3
15
- #
16
- module Observable
17
- #
18
- # Class Subscription contains information about a subscription
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- # @since 0.1.3
22
- #
23
- class Subscription
24
- include Property
25
- #
26
- # @!attribute [rw] service_id
27
- # @return [Symbol] the id of a service
28
- property :service_id, type: Symbol
29
- #
30
- # @!attribute [rw] endpoint_id
31
- # @return [Symbol] the id of an endpoint
32
- property :endpoint_id, type: Symbol
33
- #
34
- # @!attribute [rw] verb
35
- # @return [Symbol] the HTTP verb/method
36
- property :verb, type: Symbol, default: :any
37
- #
38
- # @!attribute [rw] callback
39
- # @return [Proc] a proc to callback on notify
40
- property :callback, type: Proc
41
-
42
- #
43
- # Initialize a new Subscription
44
- #
45
- # @param [Symbol] service_id the id of a service
46
- # @param [Symbol] endpoint_id the id of an endpoint
47
- # @param [Symbol] verb the HTTP verb/method
48
- # @param [Proc] callback a proc to callback on notify
49
- #
50
- def initialize(service_id, endpoint_id, verb, callback)
51
- self.service_id = service_id
52
- self.endpoint_id = endpoint_id
53
- self.verb = verb
54
- self.callback = callback
55
- end
56
- end
57
- end
58
- end
@@ -1,107 +0,0 @@
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 Registration provides registration of stubbed endpoints and services
12
- #
13
- # @author Mikael Henriksson <mikael@zoolutions.se>
14
- # @since 0.1.3
15
- #
16
- module Registration
17
- #
18
- # Class Endpoint provides registration of stubbed endpoints
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- #
22
- class Endpoint
23
- extend Forwardable
24
-
25
- include Comparable
26
- include Property
27
-
28
- # Delegate id, uri and endpoints to service
29
- delegate [:id, :uri, :endpoints] => :service
30
- #
31
- # @!attribute [rw] id
32
- # @return [Symbol] the id of the endpoint
33
- property :id, type: Symbol
34
- #
35
- # @!attribute [rw] verb
36
- # @return [Symbol] a HTTP verb
37
- property :verb, type: Symbol
38
- #
39
- # @!attribute [rw] uri_template
40
- # @return [String] a string template for the endpoint
41
- property :uri_template, type: String
42
- #
43
- # @!attribute [rw] options
44
- # @see
45
- # @return [Hash<Symbol>] a Hash with default request/response options
46
- property :options, type: Hash, default: {}
47
-
48
- #
49
- # An endpoint for a specific {StubRequests::Registration::Service}
50
- #
51
- # @param [Symbol] endpoint_id a descriptive id for the endpoint
52
- # @param [Symbol] verb a HTTP verb
53
- # @param [String] uri_template how to reach the endpoint
54
- # @param [optional, Hash<Symbol>] options
55
- # @option options [optional, Hash<Symbol>] :request for request_stub.with
56
- # @option options [optional, Hash<Symbol>] :response for request_stub.to_return
57
- # @option options [optional, Array, Exception, StandardError, String] :error for request_stub.to_raise
58
- # @option options [optional, TrueClass] :timeout for request_stub.to_timeout
59
- #
60
- def initialize(endpoint_id, verb, uri_template, options = {})
61
- self.id = endpoint_id
62
- self.verb = verb
63
- self.uri_template = uri_template
64
- self.options = options
65
- end
66
-
67
- #
68
- # Updates this endpoint
69
- #
70
- # @param [Symbol] verb a HTTP verb
71
- # @param [String] uri_template how to reach the endpoint
72
- # @param [optional, Hash<Symbol>] options
73
- # @option options [optional, Hash<Symbol>] :request for request_stub.with
74
- # @option options [optional, Hash<Symbol>] :response for request_stub.to_return
75
- # @option options [optional, Array, Exception, StandardError, String] :error for request_stub.to_raise
76
- # @option options [optional, TrueClass] :timeout for request_stub.to_timeout
77
- #
78
- # @return [Registration::Endpoint] returns the updated endpoint
79
- #
80
- def update(verb, uri_template, options)
81
- self.verb = verb
82
- self.uri_template = uri_template
83
- self.options = options
84
- self
85
- end
86
-
87
- def <=>(other)
88
- id <=> other.id
89
- end
90
-
91
- def hash
92
- [id, self.class].hash
93
- end
94
-
95
- alias eql? ==
96
-
97
- #
98
- # Returns a descriptive string of this endpoint
99
- #
100
- # @return [String]
101
- #
102
- def to_s
103
- "#<#{self.class} id=:#{id} verb=:#{verb} uri_template='#{uri_template}'>"
104
- end
105
- end
106
- end
107
- end