stub_requests 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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