configuration_service 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +41 -0
- data/README.md +30 -0
- data/README.rdoc +17 -0
- data/Rakefile +16 -0
- data/configuration_service.gemspec +24 -0
- data/lib/configuration_service/base.rb +82 -0
- data/lib/configuration_service/configuration.rb +29 -0
- data/lib/configuration_service/errors.rb +18 -0
- data/lib/configuration_service/provider/broken.rb +30 -0
- data/lib/configuration_service/provider/stub.rb +96 -0
- data/lib/configuration_service/provider/stub_store.rb +58 -0
- data/lib/configuration_service/provider.rb +13 -0
- data/lib/configuration_service/test/orchestration_provider.rb +252 -0
- data/lib/configuration_service/test/orchestration_provider_registry.rb +52 -0
- data/lib/configuration_service/test/orchestrator.rb +240 -0
- data/lib/configuration_service/test/orchestrator_environment_factory.rb +31 -0
- data/lib/configuration_service/test/response.rb +141 -0
- data/lib/configuration_service/test/stub_orchestration_provider.rb +61 -0
- data/lib/configuration_service/test.rb +25 -0
- data/lib/configuration_service.rb +17 -0
- metadata +121 -0
@@ -0,0 +1,252 @@
|
|
1
|
+
require 'configuration_service'
|
2
|
+
|
3
|
+
module ConfigurationService
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
##
|
8
|
+
# Abstract Orchestrator provider
|
9
|
+
#
|
10
|
+
# Extend this class if you want your test orchestration provider to
|
11
|
+
# constrain your implementation's interface to work as a configuration
|
12
|
+
# service provider. If you have no intention of plugging your
|
13
|
+
# implementation into ConfigurationService::Base, build your own test
|
14
|
+
# orchestration provider from scratch, using Orchestrator as a guide.
|
15
|
+
#
|
16
|
+
# Extensions should implement #service_provider, #broken_service_provider,
|
17
|
+
# #token_for and #delete_configuration.
|
18
|
+
#
|
19
|
+
class OrchestrationProvider
|
20
|
+
|
21
|
+
##
|
22
|
+
# * +:requesting_configurations+
|
23
|
+
# * +:publishing_configurations+
|
24
|
+
# * +:nothing+ (if possible, provide credentials that don't allow
|
25
|
+
# operations on the configuration +identifier+)
|
26
|
+
ACTIVITY_ROLE_MAP = {
|
27
|
+
:requesting_configurations => :consumer,
|
28
|
+
:publishing_configurations => :publisher,
|
29
|
+
:nothing => :none
|
30
|
+
} unless defined?(ACTIVITY_ROLE_MAP)
|
31
|
+
##
|
32
|
+
# * +:consumer+
|
33
|
+
# * +:publisher+
|
34
|
+
# * +:none+
|
35
|
+
#
|
36
|
+
ROLES = ACTIVITY_ROLE_MAP.values unless defined?(ROLES)
|
37
|
+
|
38
|
+
##
|
39
|
+
# Returns a new Orchestrator provider
|
40
|
+
#
|
41
|
+
# The provider is always initialized with the same configuration +identifier+
|
42
|
+
#
|
43
|
+
def initialize
|
44
|
+
@identifier = "acme"
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# See Orchestrator#authorize
|
49
|
+
#
|
50
|
+
def authorize(role)
|
51
|
+
@token = token_for(role)
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# See Orchestrator#deauthorize
|
56
|
+
#
|
57
|
+
def deauthorize
|
58
|
+
@token = nil
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# See Orchestrator#given_metadata
|
63
|
+
#
|
64
|
+
def given_metadata
|
65
|
+
@metadata = {"version" => "1.0"}
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# See Orchestrator#given_metadata_filter
|
70
|
+
#
|
71
|
+
def given_metadata_filter
|
72
|
+
@metadata_filter = {"revision" => "d4d40eab-cf66-4af5-9a77-d956a11682de"}
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# See Orchestrator#given_existing_configuration
|
77
|
+
#
|
78
|
+
def given_existing_configuration
|
79
|
+
authorized_as(:publisher) do
|
80
|
+
@existing_configuration = publish_configuration
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# See Orchestrator#given_invalid_configuration
|
86
|
+
#
|
87
|
+
def given_invalid_configuration
|
88
|
+
@configuration = "This should be an object!"
|
89
|
+
end
|
90
|
+
|
91
|
+
##
|
92
|
+
# See Orchestrator#given_missing_configuration
|
93
|
+
#
|
94
|
+
def given_missing_configuration
|
95
|
+
authorized_as(:publisher) do
|
96
|
+
delete_configuration
|
97
|
+
@existing_configuration = nil
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# See Orchestrator#given_existing_configuration_matching_metadata_filter
|
103
|
+
#
|
104
|
+
def given_existing_configuration_matching_metadata_filter
|
105
|
+
@metadata_matching_filter = (@metadata || {}).merge(@metadata_filter)
|
106
|
+
given_existing_configuration
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# See Orchestrator#given_existing_configuration_not_matching_metadata_filter
|
111
|
+
#
|
112
|
+
def given_existing_configuration_not_matching_metadata_filter
|
113
|
+
@metadata_matching_filter = {}
|
114
|
+
given_existing_configuration
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# See Orchestrator#existing_configuration
|
119
|
+
#
|
120
|
+
def existing_configuration
|
121
|
+
@existing_configuration.data
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# See Orchestrator#existing_revision
|
126
|
+
#
|
127
|
+
def existing_revision
|
128
|
+
@existing_configuration.revision
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Perform a consuming operation against the service under test
|
133
|
+
#
|
134
|
+
# The response from the service is wrapped in a test Response.
|
135
|
+
#
|
136
|
+
def request_configuration
|
137
|
+
wrap_response do
|
138
|
+
if @metadata_filter
|
139
|
+
service.request_configuration(@metadata_filter)
|
140
|
+
else
|
141
|
+
service.request_configuration
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
##
|
147
|
+
# Perform a publishing operation against the service under test
|
148
|
+
#
|
149
|
+
# The response from the service is wrapped in a test Response.
|
150
|
+
#
|
151
|
+
def publish_configuration
|
152
|
+
wrap_response do
|
153
|
+
if @metadata
|
154
|
+
service.publish_configuration(configuration, @metadata)
|
155
|
+
elsif @metadata_matching_filter
|
156
|
+
service.publish_configuration(configuration, @metadata_matching_filter)
|
157
|
+
else
|
158
|
+
service.publish_configuration(configuration)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Arrange for the next publication or consuming operation to fail
|
165
|
+
#
|
166
|
+
# This is done by using a #broken_service_provider to service the
|
167
|
+
# next operation.
|
168
|
+
#
|
169
|
+
def fail_next_request
|
170
|
+
@fail_next = true
|
171
|
+
end
|
172
|
+
|
173
|
+
private
|
174
|
+
|
175
|
+
##
|
176
|
+
# Return a ConfigurationService::Base provider
|
177
|
+
#
|
178
|
+
# The provider should use a consistent +identifier+.
|
179
|
+
#
|
180
|
+
def service_provider # :doc:
|
181
|
+
raise NotImplementedError, "#{self.class} must implement service_provider"
|
182
|
+
end
|
183
|
+
|
184
|
+
##
|
185
|
+
# Return a broken ConfigurationService::Base provider
|
186
|
+
#
|
187
|
+
# The provider's #publish_configuration and #request_configuration
|
188
|
+
# methods must raise an Error other than AuthorizationError.
|
189
|
+
#
|
190
|
+
def broken_service_provider # :doc:
|
191
|
+
raise NotImplementedError, "#{self.class} must implement broken_service_provider"
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Delete the configuration identified by the consistent +identifier+
|
196
|
+
#
|
197
|
+
# Deleting non-existent configuration should not produce an error.
|
198
|
+
#
|
199
|
+
def delete_configuration # :doc:
|
200
|
+
raise NotImplementedError, "#{self.class} must implement delete_configuration"
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Return a token that authorizes +role+
|
205
|
+
#
|
206
|
+
# Valid roles are:
|
207
|
+
#
|
208
|
+
# * +:consumer+
|
209
|
+
# * +:publisher+
|
210
|
+
# * +:nothing+
|
211
|
+
#
|
212
|
+
# Note that a token should be returned for +:nothing+, but the token should
|
213
|
+
# not be authorized to consume or publish to the +identifier+.
|
214
|
+
#
|
215
|
+
def token_for(role) # :doc:
|
216
|
+
raise NotImplementedError, "#{self.class} must implement token_for(role)"
|
217
|
+
end
|
218
|
+
|
219
|
+
def configuration
|
220
|
+
@configuration ||= {"verbose" => true}
|
221
|
+
end
|
222
|
+
|
223
|
+
def service
|
224
|
+
if @fail_next
|
225
|
+
@fail_next = false
|
226
|
+
ConfigurationService.new(broken_service_provider)
|
227
|
+
else
|
228
|
+
ConfigurationService.new(service_provider)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def authorized_as(role)
|
233
|
+
restore_token = @token
|
234
|
+
authorize(role)
|
235
|
+
yield.tap do
|
236
|
+
@token = restore_token
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def wrap_response # :nodoc:
|
241
|
+
begin
|
242
|
+
ConfigurationService::Test::Response::Success.new(yield)
|
243
|
+
rescue ConfigurationService::Error => e
|
244
|
+
ConfigurationService::Test::Response::Failure.new(e)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "singleton"
|
2
|
+
|
3
|
+
module ConfigurationService
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
# The Singleton module deletes the instance on include!
|
8
|
+
unless defined?(OrchestrationProviderRegistry)
|
9
|
+
|
10
|
+
##
|
11
|
+
# Singleton registry of Orchestrator providers
|
12
|
+
#
|
13
|
+
class OrchestrationProviderRegistry
|
14
|
+
include Singleton
|
15
|
+
|
16
|
+
def initialize ## :nodoc:
|
17
|
+
@providers = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Register a +provider+ identified by the string +identifier+
|
22
|
+
#
|
23
|
+
# The +provider+ should be a class with a default (nullary) constructor.
|
24
|
+
#
|
25
|
+
def register(identifier, provider)
|
26
|
+
@providers[identifier] = provider
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Return the +provider+ identified by the string +identifier+
|
31
|
+
#
|
32
|
+
# The +provider must already have been registered with #register,
|
33
|
+
# and should be a class with a default (nullary) constructor.
|
34
|
+
#
|
35
|
+
# Returns +nil+ if no provider has been registered with the given
|
36
|
+
# +identifier+.
|
37
|
+
#
|
38
|
+
def lookup(identifier)
|
39
|
+
@providers[identifier]
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Return the singleton registry instance
|
44
|
+
# :singleton-method: instance
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
require 'configuration_service'
|
2
|
+
|
3
|
+
module ConfigurationService
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
##
|
8
|
+
# The declarative test orchestration API
|
9
|
+
#
|
10
|
+
# This is the declarative API that describes what must be done to test a
|
11
|
+
# configuration service provider. It catalogues all the services that the
|
12
|
+
# cucumber step definitions expect from a test orchestration provider.
|
13
|
+
#
|
14
|
+
# It keeps no domain state, because that would couple it to the
|
15
|
+
# service implementation. By making no assumptions at all about the API
|
16
|
+
# or data, it allows implementors to produce service implementations
|
17
|
+
# that do not adhere to the anticipated ConfigurationService::Base API,
|
18
|
+
# by writing their own OrchestrationProvider from scratch.
|
19
|
+
#
|
20
|
+
# However, implementors who are trying to produce ConfigurationService::Base
|
21
|
+
# providers should extend OrchestrationProvider, which anticipates a
|
22
|
+
# compatible provider API.
|
23
|
+
#
|
24
|
+
# Note that the +response+ instance variable is not domain state; it is
|
25
|
+
# a test artifact (Response or similar) that orchestration providers use
|
26
|
+
# to wrap responses from the service provider.
|
27
|
+
#
|
28
|
+
class Orchestrator
|
29
|
+
|
30
|
+
##
|
31
|
+
# Return a new orchestrator initialized with a new instance of +provider_class+.
|
32
|
+
#
|
33
|
+
# The provider is expected to use a consistent configuration +identifier+ for
|
34
|
+
# all publishing and consuming operations.
|
35
|
+
#
|
36
|
+
def initialize(provider_class)
|
37
|
+
@provider = provider_class.new
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Include metadata in the next publishing operation
|
42
|
+
#
|
43
|
+
def given_metadata
|
44
|
+
@provider.given_metadata
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Include a metadata filter in the next consuming operation
|
49
|
+
#
|
50
|
+
def given_metadata_filter
|
51
|
+
@provider.given_metadata_filter
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Arrange a published configuration fixture
|
56
|
+
def given_existing_configuration
|
57
|
+
@provider.given_existing_configuration
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Use invalid configuration data in the next publishing operation
|
62
|
+
#
|
63
|
+
def given_invalid_configuration
|
64
|
+
@provider.given_invalid_configuration
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Delete any existing configuration
|
69
|
+
#
|
70
|
+
def given_missing_configuration
|
71
|
+
@provider.given_missing_configuration
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Arrange a published configuration fixture
|
76
|
+
#
|
77
|
+
# Use a metadata filter that matches the fixture's metadata in the next consuming operation.
|
78
|
+
#
|
79
|
+
def given_existing_configuration_matching_metadata_filter
|
80
|
+
@provider.given_existing_configuration_matching_metadata_filter
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Arrange a published configuration fixture
|
85
|
+
#
|
86
|
+
# Use a metadata filter that does not match the fixture's metadata in the next consuming operation.
|
87
|
+
#
|
88
|
+
def given_existing_configuration_not_matching_metadata_filter
|
89
|
+
@provider.given_existing_configuration_not_matching_metadata_filter
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Return a published configuration fixture
|
94
|
+
#
|
95
|
+
# E.g. as arranged by #given_existing_configuration.
|
96
|
+
#
|
97
|
+
# TODO remove; step definitions expect this to be Comparable
|
98
|
+
#
|
99
|
+
def existing_configuration
|
100
|
+
@provider.existing_configuration
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Return the revision of a published configuration fixture
|
105
|
+
#
|
106
|
+
# E.g. as arranged by #given_existing_configuration.
|
107
|
+
#
|
108
|
+
# TODO remove; step definitions expect this to be Comparable
|
109
|
+
#
|
110
|
+
def existing_revision
|
111
|
+
@provider.existing_revision
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Authorize the next consuming or publishing operation for +activity+
|
116
|
+
#
|
117
|
+
# Valid activities (as per ACTIVITY_ROLE_MAP in ConfigurationService::Test::OrchestrationProvider) are:
|
118
|
+
#
|
119
|
+
# * +:requesting_configurations+
|
120
|
+
# * +:publishing_configurations+
|
121
|
+
# * +:nothing+
|
122
|
+
#
|
123
|
+
# Where possible, the orchestration provider should authorize +:nothing+
|
124
|
+
# by providing valid credentials that don't allow operations on the
|
125
|
+
# configuration +identifier+ that it tests against.
|
126
|
+
#
|
127
|
+
def authorize(activity)
|
128
|
+
role = role_for(activity) or raise "unknown authorizable activity #{activity.inspect}"
|
129
|
+
@provider.authorize(role)
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Remove any previous authorization
|
134
|
+
#
|
135
|
+
# E.g. as arranged by #authorize.
|
136
|
+
#
|
137
|
+
def deauthorize
|
138
|
+
@provider.deauthorize
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Perform a consuming operation against the service under test
|
143
|
+
#
|
144
|
+
# The provider is expected to wrap the response in a Response (or
|
145
|
+
# simimlar) and return that.
|
146
|
+
#
|
147
|
+
def request_configuration
|
148
|
+
@response = @provider.request_configuration
|
149
|
+
end
|
150
|
+
|
151
|
+
##
|
152
|
+
# Perform a publishing operation against the service under test
|
153
|
+
#
|
154
|
+
# The provider is expected to wrap the response in a Response (or
|
155
|
+
# simimlar) and return that.
|
156
|
+
#
|
157
|
+
def publish_configuration
|
158
|
+
@response = @provider.publish_configuration
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# True if the last consuming or publishing operation was allowed
|
163
|
+
#
|
164
|
+
def request_allowed?
|
165
|
+
@response.allowed?
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# True if the last consuming or publishing operation failed
|
170
|
+
#
|
171
|
+
# Operations that were not allowed (as per #request_allowed?) or
|
172
|
+
# considered failed.
|
173
|
+
#
|
174
|
+
def request_failed?
|
175
|
+
@response.failed?
|
176
|
+
end
|
177
|
+
|
178
|
+
##
|
179
|
+
# True if the last consuming operation did not return data
|
180
|
+
#
|
181
|
+
def request_not_found?
|
182
|
+
not @response.found?
|
183
|
+
end
|
184
|
+
|
185
|
+
##
|
186
|
+
# True if the last consuming operation did not return data
|
187
|
+
#
|
188
|
+
# TODO: distinguish #request_not_matched? to mean "found data, but filtered out by metadata filter"
|
189
|
+
def request_not_matched?
|
190
|
+
not @response.found?
|
191
|
+
end
|
192
|
+
|
193
|
+
##
|
194
|
+
# The last published or consumed configuration data
|
195
|
+
#
|
196
|
+
# Note that this is the data itself, not a Configuration object.
|
197
|
+
#
|
198
|
+
def published_configuration
|
199
|
+
@response.data
|
200
|
+
end
|
201
|
+
alias :requested_configuration :published_configuration
|
202
|
+
|
203
|
+
##
|
204
|
+
# The revision of the last published or consumed configuration
|
205
|
+
#
|
206
|
+
def published_revision
|
207
|
+
@response.revision
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# The last published metadata
|
212
|
+
#
|
213
|
+
def published_metadata
|
214
|
+
@response.metadata
|
215
|
+
end
|
216
|
+
|
217
|
+
##
|
218
|
+
# Arrange for the next publication operation to fail
|
219
|
+
#
|
220
|
+
def given_publication_failure
|
221
|
+
@provider.fail_next_request
|
222
|
+
end
|
223
|
+
|
224
|
+
##
|
225
|
+
# Arrange for the next consuming operation to fail
|
226
|
+
#
|
227
|
+
def given_request_failure
|
228
|
+
@provider.fail_next_request
|
229
|
+
end
|
230
|
+
|
231
|
+
private
|
232
|
+
|
233
|
+
def role_for(activity)
|
234
|
+
ConfigurationService::Test::OrchestrationProvider::ACTIVITY_ROLE_MAP[activity]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ConfigurationService
|
2
|
+
|
3
|
+
module Test
|
4
|
+
|
5
|
+
##
|
6
|
+
# Builds an Orchestrator using a provider selected from the environment
|
7
|
+
#
|
8
|
+
module OrchestratorEnvironmentFactory
|
9
|
+
|
10
|
+
##
|
11
|
+
# Looks up the provider registered to the OrchestrationProviderRegistry
|
12
|
+
# with the name provided in the +TEST_ORCHESTRATION_PROVIDER+ environment
|
13
|
+
# variable, and returns a new Orchestrator initialized with that
|
14
|
+
# provider.
|
15
|
+
#
|
16
|
+
# Returns a new Orchestrator, or raises a +RuntimeError+ if the
|
17
|
+
# +TEST_ORCHESTRATION_PROVIDER+ environment variable does not name a
|
18
|
+
# provider known to the OrchestrationProviderRegistry.
|
19
|
+
#
|
20
|
+
def self.build
|
21
|
+
identifier = ENV["TEST_ORCHESTRATION_PROVIDER"] or raise "missing environment variable: TEST_ORCHESTRATION_PROVIDER"
|
22
|
+
registry = ConfigurationService::Test::OrchestrationProviderRegistry.instance
|
23
|
+
provider = registry.lookup(identifier) or raise "unknown test orchestration provider: #{identifier}"
|
24
|
+
@test = ConfigurationService::Test::Orchestrator.new(provider)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require "configuration_service"
|
2
|
+
|
3
|
+
module ConfigurationService
|
4
|
+
|
5
|
+
module Test
|
6
|
+
|
7
|
+
##
|
8
|
+
# Encapsulation of ConfigurationService::Base responses
|
9
|
+
#
|
10
|
+
# See Success and Failure.
|
11
|
+
#
|
12
|
+
module Response
|
13
|
+
|
14
|
+
##
|
15
|
+
# Encapsulates a non-error ConfigurationService::Base response
|
16
|
+
#
|
17
|
+
# This allows an OrchestrationProvider to decouple the Orchestrator
|
18
|
+
# from the implementation details of the service provider's responses.
|
19
|
+
#
|
20
|
+
class Success
|
21
|
+
|
22
|
+
##
|
23
|
+
# Initialize a new Success with a response
|
24
|
+
#
|
25
|
+
# The response should be a Configuration object or +nil+ (because
|
26
|
+
# the ConfigurationService::Base API communicates +not found+ as
|
27
|
+
# +nil+).
|
28
|
+
#
|
29
|
+
def initialize(response)
|
30
|
+
@response = response
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Always true
|
35
|
+
#
|
36
|
+
def allowed?
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Always false
|
42
|
+
#
|
43
|
+
def failed?
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# True if the +response+ was not +nil+
|
49
|
+
#
|
50
|
+
def found?
|
51
|
+
not @response.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# The configuration data dictionary of the response, or +nil+ if not #found?
|
56
|
+
#
|
57
|
+
def data
|
58
|
+
@response and @response.data
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# The revision from the response's metadata, or +nil+ if not #found?
|
63
|
+
#
|
64
|
+
def revision
|
65
|
+
@response and @response.revision
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# The metadata dictionary of the response, or +nil+ if not #found?
|
70
|
+
#
|
71
|
+
def metadata
|
72
|
+
@response and @response.metadata
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Encapsulates an error ConfigurationService::Base response
|
79
|
+
#
|
80
|
+
# This allows an OrchestrationProvider to decouple the Orchestrator
|
81
|
+
# from the implementation details of the service provider's error
|
82
|
+
# handling.
|
83
|
+
#
|
84
|
+
class Failure
|
85
|
+
|
86
|
+
##
|
87
|
+
# Initialize a new Failure with an exception
|
88
|
+
#
|
89
|
+
def initialize(exception)
|
90
|
+
@exception = exception
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# True unless the exception was an AuthorizationError
|
95
|
+
#
|
96
|
+
def allowed?
|
97
|
+
!@exception.is_a?(ConfigurationService::AuthorizationError)
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# True if the exception was an Error but not an AuthorizationError
|
102
|
+
#
|
103
|
+
def failed?
|
104
|
+
allowed? and @exception.is_a?(ConfigurationService::Error)
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Always false
|
109
|
+
#
|
110
|
+
def found?
|
111
|
+
false
|
112
|
+
end
|
113
|
+
|
114
|
+
##
|
115
|
+
# Raises +NotImplementedError+
|
116
|
+
#
|
117
|
+
def data
|
118
|
+
raise NotImplementedError, "configuration not available after #{@exception.inspect}"
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Raises +NotImplementedError+
|
123
|
+
#
|
124
|
+
def revision
|
125
|
+
raise NotImplementedError, "revision not available after #{@exception.inspect}"
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Raises +NotImplementedError+
|
130
|
+
#
|
131
|
+
def metadata
|
132
|
+
raise NotImplementedError, "metadata not available after #{@exception.inspect}"
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|