stub_requests 0.1.2 → 0.1.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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +27 -0
  5. data/gemfiles/webmock_2.3.gemfile.lock +1 -1
  6. data/gemfiles/webmock_3.5.gemfile.lock +1 -1
  7. data/gemfiles/webmock_develop.gemfile.lock +1 -1
  8. data/lib/stub_requests.rb +19 -14
  9. data/lib/stub_requests/api.rb +30 -16
  10. data/lib/stub_requests/argument_validation.rb +12 -12
  11. data/lib/stub_requests/endpoint.rb +12 -10
  12. data/lib/stub_requests/exceptions.rb +2 -6
  13. data/lib/stub_requests/metrics.rb +5 -4
  14. data/lib/stub_requests/metrics/{endpoint_stat.rb → endpoint.rb} +23 -22
  15. data/lib/stub_requests/metrics/registry.rb +25 -25
  16. data/lib/stub_requests/metrics/{stub_stat.rb → request.rb} +22 -13
  17. data/lib/stub_requests/observable.rb +62 -0
  18. data/lib/stub_requests/observable/registry.rb +152 -0
  19. data/lib/stub_requests/observable/subscription.rb +58 -0
  20. data/lib/stub_requests/property.rb +9 -3
  21. data/lib/stub_requests/property/validator.rb +4 -4
  22. data/lib/stub_requests/registration.rb +87 -0
  23. data/lib/stub_requests/registration/endpoint.rb +107 -0
  24. data/lib/stub_requests/registration/endpoints.rb +156 -0
  25. data/lib/stub_requests/registration/registry.rb +112 -0
  26. data/lib/stub_requests/registration/service.rb +85 -0
  27. data/lib/stub_requests/uri.rb +1 -1
  28. data/lib/stub_requests/version.rb +1 -1
  29. data/lib/tasks/changelog.rake +11 -2
  30. data/update_docs.sh +33 -0
  31. metadata +13 -8
  32. data/bin/update_docs.sh +0 -16
  33. data/lib/stub_requests/endpoint_registry.rb +0 -159
  34. data/lib/stub_requests/service.rb +0 -77
  35. data/lib/stub_requests/service_registry.rb +0 -104
@@ -8,7 +8,7 @@
8
8
  #
9
9
  module StubRequests
10
10
  #
11
- # Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
11
+ # Module Metrics contains logic for collecting metrics about requests stubs
12
12
  #
13
13
  # @author Mikael Henriksson <mikael@zoolutions.se>
14
14
  # @since 0.1.2
@@ -32,15 +32,15 @@ module StubRequests
32
32
 
33
33
  #
34
34
  # @!attribute [rw] services
35
- # @return [Concurrent::Array<EndpointStat>] a map with stubbed endpoints
36
- attr_reader :stats
35
+ # @return [Concurrent::Array<Endpoint>] a map with stubbed endpoints
36
+ attr_reader :endpoints
37
37
 
38
38
  #
39
39
  # Initialize a new registry
40
40
  #
41
41
  #
42
42
  def initialize
43
- @stats = Concurrent::Array.new
43
+ @endpoints = Concurrent::Array.new
44
44
  end
45
45
 
46
46
  #
@@ -49,41 +49,41 @@ module StubRequests
49
49
  #
50
50
  # @api private
51
51
  def reset
52
- stats.clear
52
+ endpoints.clear
53
53
  end
54
54
 
55
55
  #
56
56
  # Required by Enumerable
57
57
  #
58
58
  #
59
- # @return [Concurrent::Array<EndpointStat>] an array with stubbed endpoints
59
+ # @return [Concurrent::Array<Endpoint>] an array with stubbed endpoints
60
60
  #
61
61
  # @yield used by Enumerable
62
62
  #
63
63
  def each(&block)
64
- stats.each(&block)
64
+ endpoints.each(&block)
65
65
  end
66
66
 
67
67
  #
68
68
  # Records metrics about stubbed endpoints
69
69
  #
70
70
  #
71
- # @param [Service] service a symbolic id of the service
72
- # @param [Endpoint] endpoint a string with a base_uri to the service
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
73
  # @param [WebMock::RequestStub] request_stub the stubbed request
74
74
  #
75
75
  # @return [Service] the service that was just registered
76
76
  #
77
77
  def record(service, endpoint, request_stub)
78
- stat = find_or_initialize_stat(service, endpoint)
79
- stat.record(request_stub)
78
+ endpoint = find_or_initialize_endpoint(service, endpoint)
79
+ endpoint.record(request_stub)
80
80
 
81
- stats.push(stat)
82
- stat
81
+ endpoints.push(endpoint)
82
+ endpoint
83
83
  end
84
84
 
85
85
  #
86
- # Mark a {StubStat} as having responded
86
+ # Mark a {Request} as having responded
87
87
  #
88
88
  # @note Called when webmock responds successfully
89
89
  #
@@ -92,20 +92,20 @@ module StubRequests
92
92
  # @return [void]
93
93
  #
94
94
  def mark_as_responded(request_stub)
95
- return unless (stat = find_stub_stat(request_stub))
95
+ return unless (request = find_request(request_stub))
96
96
 
97
- stat.mark_as_responded
97
+ request.mark_as_responded
98
98
  end
99
99
 
100
100
  #
101
- # Finds a {StubStat} amongst the endpoint stubs
101
+ # Finds a {Request} amongst the endpoint stubs
102
102
  #
103
103
  #
104
104
  # @param [WebMock::RequestStub] request_stub a stubbed webmock response
105
105
  #
106
- # @return [StubStat] the stub_stat matching the request stub
106
+ # @return [Request] the request_stubbed matching the request stub
107
107
  #
108
- def find_stub_stat(request_stub)
108
+ def find_request(request_stub)
109
109
  map do |endpoint|
110
110
  endpoint.find_by(attribute: :request_stub, value: request_stub)
111
111
  end.compact.first
@@ -113,19 +113,19 @@ module StubRequests
113
113
 
114
114
  private
115
115
 
116
- def find_or_initialize_stat(service, endpoint)
117
- find_stat(service, endpoint) || initialize_stat(service, endpoint)
116
+ def find_or_initialize_endpoint(service, endpoint)
117
+ find_endpoint(service, endpoint) || initialize_endpoint(service, endpoint)
118
118
  end
119
119
 
120
120
  # :reek:UtilityFunction
121
121
  # :reek:FeatureEnvy
122
- def find_stat(service, endpoint)
123
- find { |stat| stat.service_id == service.id && stat.endpoint_id == endpoint.id }
122
+ def find_endpoint(service, endpoint)
123
+ find { |ep| ep.service_id == service.id && ep.endpoint_id == endpoint.id }
124
124
  end
125
125
 
126
126
  # :reek:UtilityFunction
127
- def initialize_stat(service, endpoint)
128
- Metrics::EndpointStat.new(service, endpoint)
127
+ def initialize_endpoint(service, endpoint)
128
+ Metrics::Endpoint.new(service, endpoint)
129
129
  end
130
130
  end
131
131
  end
@@ -8,21 +8,29 @@
8
8
  #
9
9
  module StubRequests
10
10
  #
11
- # Module Metrics contains logic for collecting metrics about {EndpointStat} and {StubStat}
11
+ # Module Metrics contains logic for collecting metrics about requests stubs
12
12
  #
13
13
  # @author Mikael Henriksson <mikael@zoolutions.se>
14
14
  # @since 0.1.2
15
15
  #
16
16
  module Metrics
17
17
  #
18
- # Class StubStat tracks the WebMock::RequestStub life cycle
18
+ # Class Stub tracks the WebMock::RequestStub life cycle
19
19
  #
20
20
  # @author Mikael Henriksson <mikael@zoolutions.se>
21
21
  # @since 0.1.2
22
22
  #
23
23
  # :reek:TooManyInstanceVariables
24
- class StubStat
24
+ class Request
25
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
26
34
  #
27
35
  # @!attribute [r] verb
28
36
  # @return [Symbol] a HTTP verb/method
@@ -52,18 +60,18 @@ module StubRequests
52
60
  # Initialize a new Record
53
61
  #
54
62
  #
55
- # @param [EndpointStat] endpoint_stat a stubbed endpoint
63
+ # @param [Endpoint] endpoint a stubbed endpoint
56
64
  # @param [WebMock::RequestStub] request_stub the stubbed webmock request
57
65
  #
58
- def initialize(endpoint_stat, request_stub)
66
+ def initialize(endpoint, request_stub)
59
67
  request_pattern = request_stub.request_pattern
60
- @endpoint_stat = endpoint_stat
61
- @verb = request_pattern.method_pattern.to_s.to_sym
62
- @uri = request_pattern.uri_pattern.to_s
63
- @request_stub = request_stub
64
- @recorded_at = Time.now
65
- @recorded_from = RSpec.current_example.metadata[:location]
66
- @responded_at = nil
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
67
75
  end
68
76
 
69
77
  #
@@ -73,7 +81,8 @@ module StubRequests
73
81
  # @return [Time] the time it was marked responded
74
82
  #
75
83
  def mark_as_responded
76
- @responded_at = Time.now
84
+ self.responded_at = Time.now
85
+ Observable.notify_subscribers(self)
77
86
  end
78
87
  end
79
88
  end
@@ -0,0 +1,62 @@
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 observing webmock requests
12
+ #
13
+ # @author Mikael Henriksson <mikael@zoolutions.se>
14
+ # @since 0.1.3
15
+ #
16
+ module Observable
17
+ #
18
+ # Subscribe to a service endpoint call
19
+ # @see Observable::Registry#subscribe
20
+ #
21
+ #
22
+ # @param [Symbol] service_id the id of a service
23
+ # @param [Symbol] endpoint_id the id of an endpoint
24
+ # @param [Symbol] verb the HTTP verb to subscribe to
25
+ # @param [Proc] callback the callback to use for when.a request was made
26
+ #
27
+ # @return [Subscription]
28
+ #
29
+ # :reek:LongParameterList
30
+ def self.subscribe_to(service_id, endpoint_id, verb, callback)
31
+ Registry.instance.subscribe(service_id, endpoint_id, verb, callback)
32
+ end
33
+
34
+ #
35
+ # Unsubscribe from a service endpoint call
36
+ # @see Observable::Registry#unsubscribe
37
+ #
38
+ #
39
+ # @param [Symbol] service_id the id of a service
40
+ # @param [Symbol] endpoint_id the id of an endpoint
41
+ # @param [Symbol] verb the HTTP verb to subscribe to
42
+ #
43
+ # @return [Subscription]
44
+ #
45
+ def self.unsubscribe_from(service_id, endpoint_id, verb)
46
+ Registry.instance.unsubscribe(service_id, endpoint_id, verb)
47
+ end
48
+
49
+ #
50
+ # Notifies subscribers that a request was made
51
+ # @see Observable::Registry#notify_subscribers
52
+ #
53
+ #
54
+ # @param [Metrics::Request] request the stubbed request
55
+ #
56
+ # @return [Request]
57
+ #
58
+ def self.notify_subscribers(request)
59
+ Registry.instance.notify_subscribers(request)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,152 @@
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
@@ -0,0 +1,58 @@
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