stub_requests 0.1.3 → 0.1.4

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