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,156 +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 Endpoints manages a collection of endpoints
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- #
22
- class Endpoints
23
- include Enumerable
24
-
25
- #
26
- # @!attribute [rw] endpoints
27
- # @return [Concurrent::Map<Symbol, Endpoint>] a map with endpoints
28
- attr_reader :endpoints
29
-
30
- def initialize
31
- @endpoints = Concurrent::Map.new
32
- end
33
-
34
- #
35
- # Required by Enumerable
36
- #
37
- # @return [Concurrent::Map<Symbol, Service>] a map with endpoints
38
- #
39
- # @yield used by Enumerable
40
- #
41
- def each(&block)
42
- endpoints.each(&block)
43
- end
44
-
45
- #
46
- # Registers an endpoint in the collection
47
- #
48
- # @param [Symbol] endpoint_id the id of this Endpoint
49
- # @param [Symbol] verb a HTTP verb
50
- # @param [String] uri_template the URI to reach the endpoint
51
- # @param [optional, Hash<Symbol>] options default options
52
- #
53
- # @return [Endpoint]
54
- #
55
- # :reek:LongParameterList { max_params: 4 }
56
- def register(endpoint_id, verb, uri_template, options = {})
57
- endpoint =
58
- if (endpoint = find(endpoint_id))
59
- StubRequests.logger.warn("Endpoint already registered: #{endpoint}")
60
- endpoint.update(verb, uri_template, options)
61
- else
62
- Endpoint.new(endpoint_id, verb, uri_template, options)
63
- end
64
-
65
- endpoints[endpoint.id] = endpoint
66
- endpoint
67
- end
68
-
69
- #
70
- # Updates an endpoint
71
- #
72
- # @param [Symbol] endpoint_id the id of the endpoint
73
- # @param [Symbol] verb a HTTP verb
74
- # @param [String] uri_template how to reach the endpoint
75
- # @param [optional, Hash<Symbol>] options
76
- # @option options [optional, Hash<Symbol>] :request request options
77
- # @option options [optional, Hash<Symbol>] :response options
78
- # @option options [optional, Array, Exception, StandardError, String] :error to raise
79
- # @option options [optional, TrueClass] :timeout raise a timeout error?
80
- #
81
- # @raise [EndpointNotFound] when the endpoint couldn't be found
82
- #
83
- # @return [Endpoint] returns the updated endpoint
84
- #
85
- # :reek:LongParameterList { max_params: 4 }
86
- def update(endpoint_id, verb, uri_template, options)
87
- endpoint = find!(endpoint_id)
88
- endpoint.update(verb, uri_template, options)
89
- end
90
-
91
- #
92
- # Removes an endpoint from the collection
93
- #
94
- # @param [Symbol] endpoint_id the id of the endpoint, `:file_service`
95
- #
96
- # @return [Endpoint] the endpoint that was removed
97
- #
98
- def remove(endpoint_id)
99
- endpoints.delete(endpoint_id)
100
- end
101
-
102
- #
103
- # Fetches an endpoint from the collection
104
- #
105
- # @param [<type>] endpoint_id <description>
106
- #
107
- # @return [Endpoint]
108
- #
109
- def find(endpoint_id)
110
- endpoints[endpoint_id]
111
- end
112
-
113
- #
114
- # Fetches an endpoint from the collection or raises an error
115
- #
116
- # @param [Symbol] endpoint_id the id of the endpoint
117
- #
118
- # @raise [EndpointNotFound] when an endpoint couldn't be found
119
- #
120
- # @return [Endpoint, nil]
121
- #
122
- def find!(endpoint_id)
123
- find(endpoint_id) || raise(EndpointNotFound, "Couldn't find an endpoint with id=:#{endpoint_id}")
124
- end
125
-
126
- #
127
- # Returns a descriptive string with all endpoints in the collection
128
- #
129
- # @return [String]
130
- #
131
- def to_s
132
- [
133
- +"#<#{self.class} endpoints=",
134
- +endpoints_string,
135
- +">",
136
- ].join("")
137
- end
138
-
139
- #
140
- # Returns a nicely formatted string with an array of endpoints
141
- #
142
- #
143
- # @return [<type>] <description>
144
- #
145
- def endpoints_string
146
- "[#{endpoints_as_string}]"
147
- end
148
-
149
- private
150
-
151
- def endpoints_as_string
152
- endpoints.values.map(&:to_s).join(",") if endpoints.size.positive?
153
- end
154
- end
155
- end
156
- end
@@ -1,112 +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 Registry provides registration of services
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- #
22
- class Registry
23
- include Singleton
24
- include Enumerable
25
-
26
- #
27
- # @!attribute [rw] services
28
- # @return [Concurrent::Map<Symbol, Service>] a map with services
29
- attr_reader :services
30
-
31
- def initialize
32
- @services = Concurrent::Map.new
33
- end
34
-
35
- #
36
- # Resets the map with registered services
37
- #
38
- #
39
- # @api private
40
- def reset
41
- services.clear
42
- end
43
-
44
- #
45
- # Required by Enumerable
46
- #
47
- #
48
- # @return [Concurrent::Map<Symbol, Service>] an map with services
49
- #
50
- # @yield used by Enumerable
51
- #
52
- def each(&block)
53
- services.each(&block)
54
- end
55
-
56
- #
57
- # Registers a service in the registry
58
- #
59
- #
60
- # @param [Symbol] service_id a symbolic id of the service
61
- # @param [String] service_uri a string with a base_uri to the service
62
- #
63
- # @return [Registration::Service] the service that was just registered
64
- #
65
- def register(service_id, service_uri)
66
- if (service = find(service_id))
67
- StubRequests.logger.warn("Service already registered #{service}")
68
- raise ServiceHaveEndpoints, service if service.endpoints?
69
- end
70
- services[service_id] = Service.new(service_id, service_uri)
71
- end
72
-
73
- #
74
- # Removes a service from the registry
75
- #
76
- #
77
- # @param [Symbol] service_id the service_id to remove
78
- #
79
- # @raise [ServiceNotFound] when the service was not removed
80
- #
81
- def remove(service_id)
82
- services.delete(service_id) || raise(ServiceNotFound, service_id)
83
- end
84
-
85
- #
86
- # Fetches a service from the registry
87
- #
88
- #
89
- # @param [Symbol] service_id id of the service to remove
90
- #
91
- # @return [Registration::Service] the found service
92
- #
93
- def find(service_id)
94
- services[service_id]
95
- end
96
-
97
- #
98
- # Fetches a service from the registry or raises {ServiceNotFound}
99
- #
100
- #
101
- # @param [Symbol] service_id the id of a service
102
- #
103
- # @raise [ServiceNotFound] when an endpoint couldn't be found
104
- #
105
- # @return [Registration::Service]
106
- #
107
- def find!(service_id)
108
- find(service_id) || raise(ServiceNotFound, service_id)
109
- end
110
- end
111
- end
112
- end
@@ -1,85 +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 Service provides details for a registered service
19
- #
20
- # @author Mikael Henriksson <mikael@zoolutions.se>
21
- #
22
- class Service
23
- include Comparable
24
- include Property
25
-
26
- # @!attribute [rw] id
27
- # @return [Symbol] the id of the service
28
- property :id, type: Symbol
29
-
30
- # @!attribute [rw] uri
31
- # @return [String] the base uri to the service
32
- property :uri, type: String
33
-
34
- # @!attribute [rw] endpoints
35
- # @return [Endpoints] a list with defined endpoints
36
- attr_reader :endpoints
37
-
38
- #
39
- # Initializes a new instance of a Service
40
- #
41
- # @param [Symbol] service_id the id of this service
42
- # @param [String] service_uri the base uri to reach the service
43
- #
44
- def initialize(service_id, service_uri)
45
- self.id = service_id
46
- self.uri = service_uri
47
- @endpoints = Endpoints.new
48
- end
49
-
50
- #
51
- # Check if the endpoint registry has endpoints
52
- #
53
- # @return [true,false]
54
- #
55
- def endpoints?
56
- endpoints.any?
57
- end
58
-
59
- #
60
- # Returns a nicely formatted string with this service
61
- #
62
- # @return [String]
63
- #
64
- def to_s
65
- [
66
- +"#<#{self.class}",
67
- +" id=#{id}",
68
- +" uri=#{uri}",
69
- +" endpoints=#{endpoints.endpoints_string}",
70
- +">",
71
- ].join("")
72
- end
73
-
74
- def <=>(other)
75
- id <=> other.id
76
- end
77
-
78
- def hash
79
- [id, self.class].hash
80
- end
81
-
82
- alias eql? ==
83
- end
84
- end
85
- end
@@ -1,87 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module StubRequests
4
- #
5
- # Module Registration handles registration of stubbed endpoints and services
6
- #
7
- # @author Mikael Henriksson <mikael@zoolutions.se>
8
- # @since 0.1.3
9
- #
10
- module Registration
11
- # Register a service in the service registry
12
- #
13
- #
14
- # @param [Symbol] service_id a descriptive id for the service
15
- # @param [Symbol] service_uri the uri used to call the service
16
- #
17
- # @example Register a service with endpoints
18
- # register_service(:documents, "https://company.com/api/v1") do
19
- # register(:show, :get, "documents/:id")
20
- # register(:index, :get, "documents")
21
- # register(:create, :post, "documents")
22
- # register(:update, :patch, "documents/:id")
23
- # register(:destroy, :delete, "documents/:id")
24
- # end
25
- #
26
- # @return [Service] a new service or a previously registered service
27
- #
28
- def self.register_service(service_id, service_uri, &block)
29
- service = Registry.instance.register(service_id, service_uri)
30
- Docile.dsl_eval(service.endpoints, &block) if block.present?
31
- service
32
- end
33
-
34
- #
35
- # Stub a request to a registered service endpoint
36
- #
37
- #
38
- # @param [Symbol] service_id the id of a registered service
39
- # @param [Symbol] endpoint_id the id of a registered endpoint
40
- # @param [Hash<Symbol>] uri_replacements a list of URI replacements
41
- # @param [Hash<Symbol>] options
42
- # @option options [optional, Hash<Symbol>] :request webmock request options
43
- # @option options [optional, Hash<Symbol>] :response webmock response options
44
- # @option options [optional, Array, Exception, StandardError, String] :error webmock error to raise
45
- # @option options [optional, TrueClass] :timeout set to true to raise some kind of timeout error
46
- #
47
- # @note the kind of timeout error raised by webmock is depending on the HTTP client used
48
- #
49
- # @example Stub a request to a registered service endpoint
50
- # register_stub(
51
- # :google_api,
52
- # :get_map_location,
53
- # {}, # No URI replacements needed for this endpoint
54
- # { request: { headers: { "Accept" => "application/json" }}},
55
- # { response: { body: { id: "abyasdjasd", status: "successful" }}}
56
- # )
57
- #
58
- # @example Stub a request to a registered service endpoint using block version
59
- # register_stub(:documents, :index) do
60
- # with(headers: { "Accept" => "application/json" }}})
61
- # to_return(body: "No content", status: 204)
62
- # end
63
- #
64
- # @see #stub_http_request
65
- # @return [WebMock::RequestStub] a mocked request
66
- #
67
- # :reek:UtilityFunction
68
- # :reek:LongParameterList { max_params: 5 }
69
- def self.stub_endpoint(service_id, endpoint_id, uri_replacements = {}, options = {}, &callback)
70
- service, endpoint, uri = StubRequests::URI.for_service_endpoint(service_id, endpoint_id, uri_replacements)
71
- endpoint_stub = WebMock::Builder.build(endpoint.verb, uri, options, &callback)
72
-
73
- Metrics.record(service, endpoint, endpoint_stub)
74
- ::WebMock::StubRegistry.instance.register_request_stub(endpoint_stub)
75
- end
76
-
77
- # @api private
78
- # Used only for testing purposes
79
- # :reek:LongParameterList { max_params: 4 }
80
- def self.__stub_endpoint(service_id, endpoint_id, uri_replacements = {}, options = {})
81
- _service, endpoint, uri = StubRequests::URI.for_service_endpoint(service_id, endpoint_id, uri_replacements)
82
- endpoint_stub = WebMock::Builder.build(endpoint.verb, uri, options)
83
-
84
- ::WebMock::StubRegistry.instance.register_request_stub(endpoint_stub)
85
- end
86
- end
87
- end