hoodoo 1.0.2
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/bin/hoodoo +5 -0
- data/lib/hoodoo.rb +27 -0
- data/lib/hoodoo/active.rb +32 -0
- data/lib/hoodoo/active/active_model/uuid_validator.rb +45 -0
- data/lib/hoodoo/active/active_record/base.rb +81 -0
- data/lib/hoodoo/active/active_record/creator.rb +134 -0
- data/lib/hoodoo/active/active_record/dated.rb +343 -0
- data/lib/hoodoo/active/active_record/error_mapping.rb +351 -0
- data/lib/hoodoo/active/active_record/finder.rb +606 -0
- data/lib/hoodoo/active/active_record/search_helper.rb +189 -0
- data/lib/hoodoo/active/active_record/secure.rb +431 -0
- data/lib/hoodoo/active/active_record/support.rb +106 -0
- data/lib/hoodoo/active/active_record/translated.rb +87 -0
- data/lib/hoodoo/active/active_record/uuid.rb +80 -0
- data/lib/hoodoo/active/active_record/writer.rb +321 -0
- data/lib/hoodoo/client.rb +23 -0
- data/lib/hoodoo/client/augmented_array.rb +29 -0
- data/lib/hoodoo/client/augmented_base.rb +168 -0
- data/lib/hoodoo/client/augmented_hash.rb +23 -0
- data/lib/hoodoo/client/client.rb +354 -0
- data/lib/hoodoo/client/endpoint/endpoint.rb +427 -0
- data/lib/hoodoo/client/endpoint/endpoints/amqp.rb +180 -0
- data/lib/hoodoo/client/endpoint/endpoints/auto_session.rb +194 -0
- data/lib/hoodoo/client/endpoint/endpoints/http.rb +203 -0
- data/lib/hoodoo/client/endpoint/endpoints/http_based.rb +367 -0
- data/lib/hoodoo/client/endpoint/endpoints/not_found.rb +59 -0
- data/lib/hoodoo/client/headers.rb +269 -0
- data/lib/hoodoo/communicators.rb +23 -0
- data/lib/hoodoo/communicators/fast.rb +44 -0
- data/lib/hoodoo/communicators/pool.rb +601 -0
- data/lib/hoodoo/communicators/slow.rb +84 -0
- data/lib/hoodoo/data.rb +51 -0
- data/lib/hoodoo/data/resources/caller.rb +39 -0
- data/lib/hoodoo/data/resources/errors.rb +28 -0
- data/lib/hoodoo/data/resources/log.rb +31 -0
- data/lib/hoodoo/data/resources/session.rb +26 -0
- data/lib/hoodoo/data/types/error_primitive.rb +27 -0
- data/lib/hoodoo/data/types/permissions.rb +40 -0
- data/lib/hoodoo/data/types/permissions_defaults.rb +32 -0
- data/lib/hoodoo/data/types/permissions_full.rb +28 -0
- data/lib/hoodoo/data/types/permissions_resources.rb +31 -0
- data/lib/hoodoo/discovery.rb +20 -0
- data/lib/hoodoo/errors.rb +19 -0
- data/lib/hoodoo/errors/error_descriptions.rb +229 -0
- data/lib/hoodoo/errors/errors.rb +322 -0
- data/lib/hoodoo/generator.rb +139 -0
- data/lib/hoodoo/logger.rb +23 -0
- data/lib/hoodoo/logger/fast_writer.rb +27 -0
- data/lib/hoodoo/logger/flattener_mixin.rb +36 -0
- data/lib/hoodoo/logger/logger.rb +387 -0
- data/lib/hoodoo/logger/slow_writer.rb +49 -0
- data/lib/hoodoo/logger/writer_mixin.rb +52 -0
- data/lib/hoodoo/logger/writers/file_writer.rb +45 -0
- data/lib/hoodoo/logger/writers/log_entries_dot_com_writer.rb +64 -0
- data/lib/hoodoo/logger/writers/stream_writer.rb +43 -0
- data/lib/hoodoo/middleware.rb +33 -0
- data/lib/hoodoo/presenters.rb +45 -0
- data/lib/hoodoo/presenters/base.rb +281 -0
- data/lib/hoodoo/presenters/base_dsl.rb +519 -0
- data/lib/hoodoo/presenters/common_resource_fields.rb +31 -0
- data/lib/hoodoo/presenters/embedding.rb +232 -0
- data/lib/hoodoo/presenters/types/array.rb +118 -0
- data/lib/hoodoo/presenters/types/boolean.rb +26 -0
- data/lib/hoodoo/presenters/types/date.rb +26 -0
- data/lib/hoodoo/presenters/types/date_time.rb +26 -0
- data/lib/hoodoo/presenters/types/decimal.rb +47 -0
- data/lib/hoodoo/presenters/types/enum.rb +55 -0
- data/lib/hoodoo/presenters/types/field.rb +158 -0
- data/lib/hoodoo/presenters/types/float.rb +26 -0
- data/lib/hoodoo/presenters/types/hash.rb +361 -0
- data/lib/hoodoo/presenters/types/integer.rb +26 -0
- data/lib/hoodoo/presenters/types/object.rb +117 -0
- data/lib/hoodoo/presenters/types/string.rb +53 -0
- data/lib/hoodoo/presenters/types/tags.rb +24 -0
- data/lib/hoodoo/presenters/types/text.rb +26 -0
- data/lib/hoodoo/presenters/types/uuid.rb +54 -0
- data/lib/hoodoo/services.rb +34 -0
- data/lib/hoodoo/services/discovery/discoverers/by_consul.rb +66 -0
- data/lib/hoodoo/services/discovery/discoverers/by_convention.rb +173 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +195 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server.rb +166 -0
- data/lib/hoodoo/services/discovery/discoverers/by_drb/drb_server_start.rb +37 -0
- data/lib/hoodoo/services/discovery/discovery.rb +186 -0
- data/lib/hoodoo/services/discovery/results/for_amqp.rb +58 -0
- data/lib/hoodoo/services/discovery/results/for_http.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_local.rb +85 -0
- data/lib/hoodoo/services/discovery/results/for_remote.rb +57 -0
- data/lib/hoodoo/services/middleware/amqp_log_message.rb +186 -0
- data/lib/hoodoo/services/middleware/amqp_log_writer.rb +119 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_local.rb +130 -0
- data/lib/hoodoo/services/middleware/endpoints/inter_resource_remote.rb +202 -0
- data/lib/hoodoo/services/middleware/exception_reporting/base_reporter.rb +105 -0
- data/lib/hoodoo/services/middleware/exception_reporting/exception_reporting.rb +115 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +64 -0
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/raygun_reporter.rb +63 -0
- data/lib/hoodoo/services/middleware/interaction.rb +127 -0
- data/lib/hoodoo/services/middleware/middleware.rb +2705 -0
- data/lib/hoodoo/services/middleware/rack_monkey_patch.rb +73 -0
- data/lib/hoodoo/services/services/context.rb +153 -0
- data/lib/hoodoo/services/services/implementation.rb +132 -0
- data/lib/hoodoo/services/services/interface.rb +934 -0
- data/lib/hoodoo/services/services/permissions.rb +250 -0
- data/lib/hoodoo/services/services/request.rb +189 -0
- data/lib/hoodoo/services/services/response.rb +316 -0
- data/lib/hoodoo/services/services/service.rb +141 -0
- data/lib/hoodoo/services/services/session.rb +729 -0
- data/lib/hoodoo/utilities.rb +12 -0
- data/lib/hoodoo/utilities/string_inquirer.rb +54 -0
- data/lib/hoodoo/utilities/utilities.rb +380 -0
- data/lib/hoodoo/utilities/uuid.rb +44 -0
- data/lib/hoodoo/version.rb +17 -0
- data/spec/active/active_record/base_spec.rb +57 -0
- data/spec/active/active_record/creator_spec.rb +88 -0
- data/spec/active/active_record/dated_spec.rb +248 -0
- data/spec/active/active_record/error_mapping_spec.rb +360 -0
- data/spec/active/active_record/finder_spec.rb +744 -0
- data/spec/active/active_record/search_helper_spec.rb +384 -0
- data/spec/active/active_record/secure_spec.rb +435 -0
- data/spec/active/active_record/support_spec.rb +225 -0
- data/spec/active/active_record/translated_spec.rb +19 -0
- data/spec/active/active_record/uuid_spec.rb +72 -0
- data/spec/active/active_record/writer_spec.rb +272 -0
- data/spec/alchemy/alchemy-amq.rb +33 -0
- data/spec/client/augmented_array_spec.rb +15 -0
- data/spec/client/augmented_base_spec.rb +50 -0
- data/spec/client/augmented_hash_spec.rb +15 -0
- data/spec/client/client_spec.rb +955 -0
- data/spec/client/endpoint/endpoint_spec.rb +70 -0
- data/spec/client/endpoint/endpoints/amqp_spec.rb +16 -0
- data/spec/client/endpoint/endpoints/auto_session_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_based_spec.rb +9 -0
- data/spec/client/endpoint/endpoints/http_spec.rb +103 -0
- data/spec/client/endpoint/endpoints/not_found_spec.rb +35 -0
- data/spec/client/headers_spec.rb +172 -0
- data/spec/communicators/fast_spec.rb +9 -0
- data/spec/communicators/pool_spec.rb +339 -0
- data/spec/communicators/slow_spec.rb +15 -0
- data/spec/data/resources/caller_spec.rb +156 -0
- data/spec/data/resources/errors_spec.rb +22 -0
- data/spec/data/resources/log_spec.rb +20 -0
- data/spec/data/resources/session_spec.rb +15 -0
- data/spec/data/types/error_primitive_spec.rb +15 -0
- data/spec/data/types/permissions_defaults_spec.rb +25 -0
- data/spec/data/types/permissions_full_spec.rb +44 -0
- data/spec/data/types/permissions_resources_spec.rb +34 -0
- data/spec/data/types/permissions_spec.rb +37 -0
- data/spec/errors/error_descriptions_spec.rb +98 -0
- data/spec/errors/errors_spec.rb +346 -0
- data/spec/integration/service_actions_spec.rb +112 -0
- data/spec/logger/fast_writer_spec.rb +18 -0
- data/spec/logger/logger_spec.rb +259 -0
- data/spec/logger/slow_writer_spec.rb +144 -0
- data/spec/logger/writers/file_writer_spec.rb +37 -0
- data/spec/logger/writers/log_entries_dot_com_writer_spec.rb +29 -0
- data/spec/logger/writers/stream_writer_spec.rb +38 -0
- data/spec/presenters/base_dsl_spec.rb +111 -0
- data/spec/presenters/base_spec.rb +871 -0
- data/spec/presenters/common_resource_fields_spec.rb +30 -0
- data/spec/presenters/embedding_spec.rb +87 -0
- data/spec/presenters/types/array_spec.rb +249 -0
- data/spec/presenters/types/boolean_spec.rb +51 -0
- data/spec/presenters/types/date_spec.rb +57 -0
- data/spec/presenters/types/date_time_spec.rb +59 -0
- data/spec/presenters/types/decimal_spec.rb +58 -0
- data/spec/presenters/types/enum_spec.rb +71 -0
- data/spec/presenters/types/field_spec.rb +77 -0
- data/spec/presenters/types/float_spec.rb +50 -0
- data/spec/presenters/types/hash_spec.rb +1069 -0
- data/spec/presenters/types/integer_spec.rb +50 -0
- data/spec/presenters/types/object_spec.rb +177 -0
- data/spec/presenters/types/string_spec.rb +65 -0
- data/spec/presenters/types/tags_spec.rb +56 -0
- data/spec/presenters/types/text_spec.rb +50 -0
- data/spec/presenters/types/uuid_spec.rb +46 -0
- data/spec/presenters/walk_spec.rb +198 -0
- data/spec/services/discovery/discoverers/by_consul_spec.rb +29 -0
- data/spec/services/discovery/discoverers/by_convention_spec.rb +67 -0
- data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +80 -0
- data/spec/services/discovery/discoverers/by_drb/drb_server_spec.rb +205 -0
- data/spec/services/discovery/discovery_spec.rb +73 -0
- data/spec/services/discovery/results/for_amqp_spec.rb +17 -0
- data/spec/services/discovery/results/for_http_spec.rb +37 -0
- data/spec/services/discovery/results/for_local_spec.rb +21 -0
- data/spec/services/discovery/results/for_remote_spec.rb +15 -0
- data/spec/services/middleware/amqp_log_message_spec.rb +60 -0
- data/spec/services/middleware/amqp_log_writer_spec.rb +95 -0
- data/spec/services/middleware/endpoints/inter_resource_local_spec.rb +9 -0
- data/spec/services/middleware/endpoints/inter_resource_remote_spec.rb +9 -0
- data/spec/services/middleware/exception_reporting/base_reporter_spec.rb +16 -0
- data/spec/services/middleware/exception_reporting/exception_reporting_spec.rb +92 -0
- data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +24 -0
- data/spec/services/middleware/exception_reporting/reporters/raygun_reporter_spec.rb +23 -0
- data/spec/services/middleware/middleware_cors_spec.rb +93 -0
- data/spec/services/middleware/middleware_create_update_spec.rb +489 -0
- data/spec/services/middleware/middleware_dated_at_spec.rb +186 -0
- data/spec/services/middleware/middleware_exotic_communication_spec.rb +560 -0
- data/spec/services/middleware/middleware_logging_spec.rb +356 -0
- data/spec/services/middleware/middleware_multi_local_spec.rb +1094 -0
- data/spec/services/middleware/middleware_multi_remote_spec.rb +1440 -0
- data/spec/services/middleware/middleware_permissions_spec.rb +1014 -0
- data/spec/services/middleware/middleware_public_spec.rb +238 -0
- data/spec/services/middleware/middleware_spec.rb +1569 -0
- data/spec/services/middleware/string_inquirer_spec.rb +30 -0
- data/spec/services/services/application_spec.rb +74 -0
- data/spec/services/services/context_spec.rb +48 -0
- data/spec/services/services/implementation_spec.rb +45 -0
- data/spec/services/services/interface_spec.rb +262 -0
- data/spec/services/services/permissions_spec.rb +249 -0
- data/spec/services/services/request_spec.rb +95 -0
- data/spec/services/services/response_spec.rb +250 -0
- data/spec/services/services/session_spec.rb +432 -0
- data/spec/spec_helper.rb +298 -0
- data/spec/utilities/utilities_spec.rb +537 -0
- data/spec/utilities/uuid_spec.rb +20 -0
- metadata +615 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
# service_middleware_spec.rb is already large, so split out tests related
|
2
|
+
# explicitly to public actions in interfaces here.
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
# Create three service applications. The first has one interface with no public
|
7
|
+
# actions. The second has one interface with a public and private action. The
|
8
|
+
# last contains both interfaces.
|
9
|
+
|
10
|
+
class TestNoPublicActionImplementation < Hoodoo::Services::Implementation
|
11
|
+
def list( context )
|
12
|
+
context.response.set_resources( [ { 'private' => true } ] )
|
13
|
+
end
|
14
|
+
|
15
|
+
def show( context )
|
16
|
+
context.response.set_resources( { 'private' => true } )
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class TestPublicActionImplementation < Hoodoo::Services::Implementation
|
21
|
+
def list( context )
|
22
|
+
context.response.set_resources( [ { 'public' => true } ] )
|
23
|
+
end
|
24
|
+
|
25
|
+
def show( context )
|
26
|
+
context.response.set_resources( { 'public' => true } )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class TestNoPublicActionInterface < Hoodoo::Services::Interface
|
31
|
+
interface :NoPublicAction do
|
32
|
+
endpoint :no_public_action, TestNoPublicActionImplementation
|
33
|
+
actions :show, :list
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class TestPublicActionInterface < Hoodoo::Services::Interface
|
38
|
+
interface :PublicAction do
|
39
|
+
endpoint :public_action, TestPublicActionImplementation
|
40
|
+
actions :show, :list
|
41
|
+
public_actions :list
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TestNoPublicActionService < Hoodoo::Services::Service
|
46
|
+
comprised_of TestNoPublicActionInterface
|
47
|
+
end
|
48
|
+
|
49
|
+
class TestPublicActionService < Hoodoo::Services::Service
|
50
|
+
comprised_of TestPublicActionInterface
|
51
|
+
end
|
52
|
+
|
53
|
+
class TestMixPublicActionService < Hoodoo::Services::Service
|
54
|
+
comprised_of TestNoPublicActionInterface,
|
55
|
+
TestPublicActionInterface
|
56
|
+
end
|
57
|
+
|
58
|
+
# Run the tests
|
59
|
+
|
60
|
+
describe Hoodoo::Services::Middleware do
|
61
|
+
|
62
|
+
def try_to_call( endpoint, ident = nil )
|
63
|
+
get(
|
64
|
+
"/v1/#{ endpoint }/#{ ident }",
|
65
|
+
nil,
|
66
|
+
{ 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
before :example do
|
71
|
+
@old_test_session = Hoodoo::Services::Middleware.test_session()
|
72
|
+
Hoodoo::Services::Middleware.set_test_session( Hoodoo::Services::Middleware::DEFAULT_TEST_SESSION )
|
73
|
+
end
|
74
|
+
|
75
|
+
before :example, :without_session => true do
|
76
|
+
@old_test_session = Hoodoo::Services::Middleware.test_session()
|
77
|
+
Hoodoo::Services::Middleware.set_test_session( nil )
|
78
|
+
end
|
79
|
+
|
80
|
+
after :example do
|
81
|
+
Hoodoo::Services::Middleware.set_test_session( @old_test_session )
|
82
|
+
end
|
83
|
+
|
84
|
+
# -------------------------------------------------------------------------
|
85
|
+
|
86
|
+
context 'with only secure actions' do
|
87
|
+
|
88
|
+
# Middleware maintains class-level record of whether or not any interfaces
|
89
|
+
# had public actions for efficiency; in case any other test dirtied this by
|
90
|
+
# accident, clean out the record here.
|
91
|
+
#
|
92
|
+
before :all do
|
93
|
+
Hoodoo::Services::Middleware.class_variable_set( '@@interfaces_have_public_methods', false )
|
94
|
+
end
|
95
|
+
|
96
|
+
def app
|
97
|
+
Rack::Builder.new do
|
98
|
+
use Hoodoo::Services::Middleware
|
99
|
+
run TestNoPublicActionService.new
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context '#list' do
|
104
|
+
it 'prohibits actions without session', :without_session => true do
|
105
|
+
try_to_call( 'no_public_action' )
|
106
|
+
expect( last_response.status ).to eq( 401 )
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'allows actions with session' do
|
110
|
+
try_to_call( 'no_public_action' )
|
111
|
+
expect( last_response.status ).to eq( 200 )
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context '#show' do
|
116
|
+
it 'prohibits actions without session', :without_session => true do
|
117
|
+
try_to_call( 'no_public_action', 'some_uuid' )
|
118
|
+
expect( last_response.status ).to eq( 401 )
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'allows actions with session' do
|
122
|
+
try_to_call( 'no_public_action', 'some_uuid' )
|
123
|
+
expect( last_response.status ).to eq( 200 )
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# -------------------------------------------------------------------------
|
129
|
+
|
130
|
+
context 'with a public action' do
|
131
|
+
|
132
|
+
# Middleware maintains class-level record of whether or not any interfaces
|
133
|
+
# had public actions for efficiency; ensure this is cleared after all these
|
134
|
+
# tests run, so it's a clean slate for the next set.
|
135
|
+
#
|
136
|
+
after :all do
|
137
|
+
Hoodoo::Services::Middleware::class_variable_set( '@@interfaces_have_public_methods', false )
|
138
|
+
end
|
139
|
+
|
140
|
+
def app
|
141
|
+
Rack::Builder.new do
|
142
|
+
use Hoodoo::Services::Middleware
|
143
|
+
run TestPublicActionService.new
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'prohibits secure actions without session', :without_session => true do
|
148
|
+
try_to_call( 'public_action', 'some_uuid' )
|
149
|
+
expect( last_response.status ).to eq( 401 )
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'allows secure actions with session' do
|
153
|
+
try_to_call( 'public_action', 'some_uuid' )
|
154
|
+
expect( last_response.status ).to eq( 200 )
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'allows public actions without session', :without_session => true do
|
158
|
+
try_to_call( 'public_action' )
|
159
|
+
expect( last_response.status ).to eq( 200 )
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'allows public actions with session' do
|
163
|
+
try_to_call( 'public_action' )
|
164
|
+
expect( last_response.status ).to eq( 200 )
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# -------------------------------------------------------------------------
|
169
|
+
|
170
|
+
context 'with mixed access across interfaces' do
|
171
|
+
|
172
|
+
# Middleware maintains class-level record of whether or not any interfaces
|
173
|
+
# had public actions for efficiency; ensure this is cleared after all these
|
174
|
+
# tests run, so it's a clean slate for the next set.
|
175
|
+
#
|
176
|
+
after :all do
|
177
|
+
Hoodoo::Services::Middleware::class_variable_set( '@@interfaces_have_public_methods', false )
|
178
|
+
end
|
179
|
+
|
180
|
+
def app
|
181
|
+
Rack::Builder.new do
|
182
|
+
use Hoodoo::Services::Middleware
|
183
|
+
run TestMixPublicActionService.new
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'in interface with no public actions' do
|
188
|
+
context '#list' do
|
189
|
+
it 'prohibits actions without session', :without_session => true do
|
190
|
+
try_to_call( 'no_public_action' )
|
191
|
+
expect( last_response.status ).to eq( 401 )
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'allows actions with session' do
|
195
|
+
try_to_call( 'no_public_action' )
|
196
|
+
expect( last_response.status ).to eq( 200 )
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context '#show' do
|
201
|
+
it 'prohibits actions without session', :without_session => true do
|
202
|
+
try_to_call( 'no_public_action', 'some_uuid' )
|
203
|
+
expect( last_response.status ).to eq( 401 )
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'allows actions with session' do
|
207
|
+
try_to_call( 'no_public_action', 'some_uuid' )
|
208
|
+
expect( last_response.status ).to eq( 200 )
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context 'in interface with public actions' do
|
214
|
+
it 'prohibits secure actions without session', :without_session => true do
|
215
|
+
try_to_call( 'public_action', 'some_uuid' )
|
216
|
+
expect( last_response.status ).to eq( 401 )
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'allows secure actions with session' do
|
220
|
+
try_to_call( 'public_action', 'some_uuid' )
|
221
|
+
expect( last_response.status ).to eq( 200 )
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'allows public actions without session', :without_session => true do
|
225
|
+
try_to_call( 'public_action' )
|
226
|
+
expect( last_response.status ).to eq( 200 )
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'allows public actions with session' do
|
230
|
+
try_to_call( 'public_action' )
|
231
|
+
expect( last_response.status ).to eq( 200 )
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# -------------------------------------------------------------------------
|
237
|
+
|
238
|
+
end
|
@@ -0,0 +1,1569 @@
|
|
1
|
+
# This unavoidably combines a lot of elements of integration testing since
|
2
|
+
# little of the middleware is really usable in isolation. We could test its
|
3
|
+
# component methods individually, but the interesting ones are all part of
|
4
|
+
# request processing anyway. Code coverage lets us know if we missed any
|
5
|
+
# internal methods when testing the request processing flow.
|
6
|
+
|
7
|
+
require 'spec_helper'
|
8
|
+
|
9
|
+
|
10
|
+
###############################################################################
|
11
|
+
# Single endpoint
|
12
|
+
###############################################################################
|
13
|
+
|
14
|
+
|
15
|
+
class RSpecTestServiceStubImplementation < Hoodoo::Services::Implementation
|
16
|
+
end
|
17
|
+
|
18
|
+
class RSpecTestServiceStubBeforeAfterImplementation < Hoodoo::Services::Implementation
|
19
|
+
def before(context)
|
20
|
+
end
|
21
|
+
|
22
|
+
def after(context)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class RSpecTestServiceStubInterface < Hoodoo::Services::Interface
|
27
|
+
interface :RSpecTestResource do
|
28
|
+
version 2
|
29
|
+
endpoint :rspec_test_service_stub, RSpecTestServiceStubImplementation
|
30
|
+
embeds :emb, :embs
|
31
|
+
to_list do
|
32
|
+
sort :extra => [:up, :down]
|
33
|
+
search :foo, :bar
|
34
|
+
filter :baz, :boo
|
35
|
+
end
|
36
|
+
to_create do
|
37
|
+
text :foo, :required => true
|
38
|
+
integer :bar
|
39
|
+
end
|
40
|
+
to_update do
|
41
|
+
text :baz
|
42
|
+
integer :foo, :required => true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class RSpecTestMatchingServiceStubInterface < Hoodoo::Services::Interface
|
48
|
+
interface :RSpecTestResource do
|
49
|
+
version 2
|
50
|
+
endpoint :rspec_test_service_stub, RSpecTestServiceStubImplementation
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class RSpecTestServiceStubBeforeInterface < Hoodoo::Services::Interface
|
55
|
+
interface :RSpecTestResource do
|
56
|
+
version 2
|
57
|
+
endpoint :rspec_test_service_before_after_stub, RSpecTestServiceStubBeforeAfterImplementation
|
58
|
+
embeds :emb, :embs
|
59
|
+
to_list do
|
60
|
+
sort :extra => [:up, :down]
|
61
|
+
search :foo, :bar
|
62
|
+
filter :baz, :boo
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class RSpecTestServiceStub < Hoodoo::Services::Service
|
68
|
+
comprised_of RSpecTestServiceStubInterface, RSpecTestServiceStubBeforeInterface
|
69
|
+
end
|
70
|
+
|
71
|
+
describe Hoodoo::Services::Middleware do
|
72
|
+
|
73
|
+
def app
|
74
|
+
Rack::Builder.new do
|
75
|
+
use Hoodoo::Services::Middleware
|
76
|
+
run RSpecTestServiceStub.new
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'internal sanity checks' do
|
81
|
+
it 'should complain about bad instantiation' do
|
82
|
+
expect {
|
83
|
+
Hoodoo::Services::Middleware.new( {} )
|
84
|
+
}.to raise_error(RuntimeError, "Hoodoo::Services::Middleware instance created with non-Service entity of class 'Hash' - is this the last middleware in the chain via 'use()' and is Rack 'run()'-ing the correct thing?")
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should complain about bad instantiation due to bad NewRelic' do
|
88
|
+
expect {
|
89
|
+
module NewRelic
|
90
|
+
module Agent
|
91
|
+
module Instrumentation
|
92
|
+
class MiddlewareProxy
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
Hoodoo::Services::Middleware.new( NewRelic::Agent::Instrumentation::MiddlewareProxy.new )
|
99
|
+
}.to raise_error(RuntimeError, "Hoodoo::Services::Middleware instance created with NewRelic-wrapped Service entity, but NewRelic API is not as expected by Hoodoo; incompatible NewRelic version.")
|
100
|
+
|
101
|
+
Object.send( :remove_const, :NewRelic )
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should complain about bad instantiation via NewRelic' do
|
105
|
+
expect {
|
106
|
+
module NewRelic
|
107
|
+
module Agent
|
108
|
+
module Instrumentation
|
109
|
+
class MiddlewareProxy
|
110
|
+
def target
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
Hoodoo::Services::Middleware.new( NewRelic::Agent::Instrumentation::MiddlewareProxy.new )
|
119
|
+
}.to raise_error(RuntimeError, "Hoodoo::Services::Middleware instance created with non-Service entity of class 'Hash' - is this the last middleware in the chain via 'use()' and is Rack 'run()'-ing the correct thing?")
|
120
|
+
|
121
|
+
Object.send( :remove_const, :NewRelic )
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should complain about bad applications directly or via NewRelic' do
|
125
|
+
class RSpecTestServiceStubBadInterface < Hoodoo::Services::Interface
|
126
|
+
end
|
127
|
+
class RSpecTestServiceStubBad < Hoodoo::Services::Service
|
128
|
+
comprised_of RSpecTestServiceStubBadInterface
|
129
|
+
end
|
130
|
+
|
131
|
+
expect {
|
132
|
+
Hoodoo::Services::Middleware.new( RSpecTestServiceStubBad.new )
|
133
|
+
}.to raise_error(RuntimeError, "Hoodoo::Services::Middleware encountered invalid interface class RSpecTestServiceStubBadInterface via service class RSpecTestServiceStubBad")
|
134
|
+
|
135
|
+
expect {
|
136
|
+
module NewRelic
|
137
|
+
module Agent
|
138
|
+
module Instrumentation
|
139
|
+
class MiddlewareProxy
|
140
|
+
def target
|
141
|
+
RSpecTestServiceStubBad.new
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
Hoodoo::Services::Middleware.new( NewRelic::Agent::Instrumentation::MiddlewareProxy.new )
|
149
|
+
}.to raise_error(RuntimeError, "Hoodoo::Services::Middleware encountered invalid interface class RSpecTestServiceStubBadInterface via service class RSpecTestServiceStubBad")
|
150
|
+
|
151
|
+
Object.send( :remove_const, :NewRelic )
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should self-check content type' do
|
155
|
+
mw = Hoodoo::Services::Middleware.new( RSpecTestServiceStub.new )
|
156
|
+
interaction = Hoodoo::Services::Middleware::Interaction.new( {}, mw )
|
157
|
+
interaction.requested_content_type = 'application/xml'
|
158
|
+
expect {
|
159
|
+
mw.send( :parse_body_string_into, interaction, '{}' )
|
160
|
+
}.to raise_error(RuntimeError, "Internal error - content type 'application/xml' is not supported here; \#deal_with_content_type_header() should have caught that");
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should detect a local versus remote endpoint mismatch' do
|
164
|
+
mw = Hoodoo::Services::Middleware.new( RSpecTestServiceStub.new )
|
165
|
+
interaction = Hoodoo::Services::Middleware::Interaction.new( {}, mw )
|
166
|
+
|
167
|
+
mock_discoverer = OpenStruct.new
|
168
|
+
mw.instance_variable_set( '@discoverer', mock_discoverer )
|
169
|
+
expect( mock_discoverer ).to receive( :is_local? ).and_return( true )
|
170
|
+
|
171
|
+
expect {
|
172
|
+
mw.send( :inter_resource_endpoint_for, :NotALocalResource, 1, interaction )
|
173
|
+
}.to raise_error(RuntimeError, 'Hoodoo::Services::Middleware#inter_resource_endpoint_for: Internal error - version 1 of resource NotALocalResource endpoint is local according to the discovery engine, but no local service discovery record can be found')
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'utility methods' do
|
178
|
+
it 'should know about Memcached via environment variable' do
|
179
|
+
old = ENV[ 'MEMCACHED_HOST' ]
|
180
|
+
ENV[ 'MEMCACHED_HOST' ] = nil
|
181
|
+
expect(Hoodoo::Services::Middleware.has_memcached?).to eq(false)
|
182
|
+
ENV[ 'MEMCACHED_HOST' ] = 'foo'
|
183
|
+
expect(Hoodoo::Services::Middleware.has_memcached?).to eq(true)
|
184
|
+
ENV[ 'MEMCACHED_HOST' ] = old
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should know about Memcached via legacy environment variable' do
|
188
|
+
old = ENV[ 'MEMCACHED_HOST' ]
|
189
|
+
ENV[ 'MEMCACHED_HOST' ] = nil
|
190
|
+
expect(Hoodoo::Services::Middleware.has_memcached?).to eq(false)
|
191
|
+
ENV[ 'MEMCACHED_HOST' ] = 'foo'
|
192
|
+
expect(Hoodoo::Services::Middleware.has_memcached?).to eq(true)
|
193
|
+
ENV[ 'MEMCACHED_HOST' ] = old
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should know about a queue' do
|
197
|
+
old = ENV[ 'AMQ_ENDPOINT' ]
|
198
|
+
ENV[ 'AMQ_ENDPOINT' ] = nil
|
199
|
+
expect(Hoodoo::Services::Middleware.on_queue?).to eq(false)
|
200
|
+
ENV[ 'AMQ_ENDPOINT' ] = 'foo'
|
201
|
+
expect(Hoodoo::Services::Middleware.on_queue?).to eq(true)
|
202
|
+
ENV[ 'AMQ_ENDPOINT' ] = old
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context 'malformed basics in requests' do
|
207
|
+
|
208
|
+
it 'should complain about entirely missing content type' do
|
209
|
+
get '/v2/rspec_test_service_stub'
|
210
|
+
|
211
|
+
expect(last_response.status).to eq(422)
|
212
|
+
|
213
|
+
result = JSON.parse(last_response.body)
|
214
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
215
|
+
expect(result['errors'][0]['message']).to eq("Content-Type '<unknown>' does not match supported types '[\"application/json\"]' and/or encodings '[\"utf-8\"]'")
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should complain about missing charset' do
|
219
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json' }
|
220
|
+
|
221
|
+
expect(last_response.status).to eq(422)
|
222
|
+
|
223
|
+
result = JSON.parse(last_response.body)
|
224
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
225
|
+
expect(result['errors'][0]['message']).to eq("Content-Type 'application/json' does not match supported types '[\"application/json\"]' and/or encodings '[\"utf-8\"]'")
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should complain about incorrect content type' do
|
229
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'some/thing; charset=utf-8' }
|
230
|
+
|
231
|
+
expect(last_response.status).to eq(422)
|
232
|
+
|
233
|
+
result = JSON.parse(last_response.body)
|
234
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
235
|
+
expect(result['errors'][0]['message']).to eq("Content-Type 'some/thing; charset=utf-8' does not match supported types '[\"application/json\"]' and/or encodings '[\"utf-8\"]'")
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'should complain about incorrect content type' do
|
239
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=madeup' }
|
240
|
+
|
241
|
+
expect(last_response.status).to eq(422)
|
242
|
+
|
243
|
+
result = JSON.parse(last_response.body)
|
244
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
245
|
+
expect(result['errors'][0]['message']).to eq("Content-Type 'application/json; charset=madeup' does not match supported types '[\"application/json\"]' and/or encodings '[\"utf-8\"]'")
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should generate interaction IDs and other standard headers even for error states' do
|
249
|
+
get '/v2/rspec_test_service_stub'
|
250
|
+
|
251
|
+
expect(last_response.status).to eq(422)
|
252
|
+
expect(last_response.headers['X-Interaction-ID']).to_not be_nil
|
253
|
+
expect(last_response.headers['X-Interaction-ID'].size).to eq(32)
|
254
|
+
expect(last_response.headers['Content-Type']).to eq('application/json; charset=utf-8')
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
context 'sessions' do
|
260
|
+
|
261
|
+
# This leans on assumption that Permissions#permitted? has already
|
262
|
+
# got adequate test coverage elsewhere, so we just make sure that
|
263
|
+
# it seems to allow or deny as expected via the session.
|
264
|
+
|
265
|
+
context 'present' do
|
266
|
+
it 'should check for session permissions' do
|
267
|
+
expect_any_instance_of(Hoodoo::Services::Session).to receive(:permissions).at_least( 1 ).times.and_call_original
|
268
|
+
expect_any_instance_of(Hoodoo::Services::Permissions).to receive(:permitted?).at_least( 1 ).times.and_call_original
|
269
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once.and_return([])
|
270
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
271
|
+
expect(last_response.status).to eq(200)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
context 'with restricted permissions' do
|
276
|
+
before :example do
|
277
|
+
@old_test_session = Hoodoo::Services::Middleware.test_session()
|
278
|
+
test_session = @old_test_session.dup
|
279
|
+
permissions = Hoodoo::Services::Permissions.new # (this is "default-else-deny")
|
280
|
+
permissions.set_resource( :RSpecTestResource, :list, Hoodoo::Services::Permissions::ALLOW )
|
281
|
+
permissions.set_resource( :RSpecTestResource, :show, Hoodoo::Services::Permissions::ASK )
|
282
|
+
test_session.permissions = permissions
|
283
|
+
Hoodoo::Services::Middleware.set_test_session( test_session )
|
284
|
+
end
|
285
|
+
|
286
|
+
after :example do
|
287
|
+
Hoodoo::Services::Middleware.set_test_session( @old_test_session )
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'denies' do
|
291
|
+
delete '/v2/rspec_test_service_stub/uuid', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
292
|
+
expect(last_response.status).to eq(403)
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'allows' do
|
296
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once.and_return([])
|
297
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
298
|
+
expect(last_response.status).to eq(200)
|
299
|
+
end
|
300
|
+
|
301
|
+
it 'asks' do
|
302
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:verify).once.and_return(Hoodoo::Services::Permissions::ALLOW)
|
303
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once.and_return({})
|
304
|
+
get '/v2/rspec_test_service_stub/uuid', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
305
|
+
expect(last_response.status).to eq(200)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context 'absent' do
|
310
|
+
before :example do
|
311
|
+
@old_test_session = Hoodoo::Services::Middleware.test_session()
|
312
|
+
Hoodoo::Services::Middleware.set_test_session( nil )
|
313
|
+
end
|
314
|
+
|
315
|
+
after :example do
|
316
|
+
Hoodoo::Services::Middleware.set_test_session( @old_test_session )
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'should check for missing session data' do
|
320
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
321
|
+
expect(last_response.status).to eq(401)
|
322
|
+
result = JSON.parse(last_response.body)
|
323
|
+
expect(result['errors'][0]['code']).to eq('platform.invalid_session')
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'well formed request for' do
|
330
|
+
|
331
|
+
it 'no matching endpoint should return 404 with lower case in content type' do
|
332
|
+
get '/v2/where_are_you', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
333
|
+
expect(last_response.status).to eq(404)
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'no matching endpoint should return 404 with mixed case in content type' do
|
337
|
+
get '/v2/where_are_you', nil, { 'CONTENT_TYPE' => 'APPLICATION/json; charset=UTF-8' }
|
338
|
+
expect(last_response.status).to eq(404)
|
339
|
+
end
|
340
|
+
|
341
|
+
it 'a matching endpoint should use fallback exception handler if early failures occur' do
|
342
|
+
|
343
|
+
# Stub out anything early in request handling inside call() and make it
|
344
|
+
# throw an exception.
|
345
|
+
|
346
|
+
expect_any_instance_of(Hoodoo::Services::Middleware).to receive(:debug_log).and_raise("boo!")
|
347
|
+
expect_any_instance_of(Hoodoo::Services::Middleware).to receive(:record_exception).and_raise("boo!")
|
348
|
+
|
349
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
350
|
+
|
351
|
+
expect(last_response.status).to eq(500)
|
352
|
+
expect(last_response.body).to include('Middleware exception in exception handler')
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'a matching endpoint should use fallback exception handler if the primary handler fails' do
|
356
|
+
|
357
|
+
# This implicitly tests that Hoodoo' exception handler checks for test
|
358
|
+
# and development mode and if both are false, calls the exception reporter.
|
359
|
+
#
|
360
|
+
# So, first, these are part of routine processing.
|
361
|
+
|
362
|
+
expect(Hoodoo::Services::Middleware.environment).to receive(:test?).exactly(2).times.and_return(true)
|
363
|
+
|
364
|
+
# The check for 'unless test or development' is made prior to trying to use
|
365
|
+
# the ExceptionReporter class, so say 'no' to both then get the reporter to
|
366
|
+
# itself raise an error.
|
367
|
+
|
368
|
+
expect(Hoodoo::Services::Middleware.environment).to receive(:test?).once.and_return(false)
|
369
|
+
expect(Hoodoo::Services::Middleware.environment).to receive(:development?).and_return(false)
|
370
|
+
expect(Hoodoo::Services::Middleware::ExceptionReporting).to receive(:report).and_raise("boo!")
|
371
|
+
|
372
|
+
# Route through to the unimplemented "list" call, so the subclass raises
|
373
|
+
# an exception. This is tested independently elsewhere too. This causes
|
374
|
+
# the normal exception handler to run, which breaks because of the above
|
375
|
+
# code, so we get the fallback.
|
376
|
+
|
377
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).and_call_original
|
378
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
379
|
+
|
380
|
+
expect(last_response.status).to eq(500)
|
381
|
+
expect(last_response.body).to eq('Middleware exception in exception handler')
|
382
|
+
end
|
383
|
+
|
384
|
+
# -------------------------------------------------------------------------
|
385
|
+
|
386
|
+
describe 'service implementation #before and #after' do
|
387
|
+
it 'should get called if defined in correct order' do
|
388
|
+
expect_any_instance_of(RSpecTestServiceStubBeforeAfterImplementation).to receive(:before).once do | ignored_rspec_mock_instance, context |
|
389
|
+
expect(context).to be_a(Hoodoo::Services::Context)
|
390
|
+
end
|
391
|
+
|
392
|
+
expect_any_instance_of(RSpecTestServiceStubBeforeAfterImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
393
|
+
expect(context).to be_a(Hoodoo::Services::Context)
|
394
|
+
end
|
395
|
+
|
396
|
+
expect_any_instance_of(RSpecTestServiceStubBeforeAfterImplementation).to receive(:after).once do | ignored_rspec_mock_instance, context |
|
397
|
+
expect(context).to be_a(Hoodoo::Services::Context)
|
398
|
+
end
|
399
|
+
|
400
|
+
get '/v2/rspec_test_service_before_after_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'should not call action if before generates errors' do
|
404
|
+
expect_any_instance_of(RSpecTestServiceStubBeforeAfterImplementation).to receive(:before).once do | ignored_rspec_mock_instance, context |
|
405
|
+
response.add_error( 'service_calls_a.triggered')
|
406
|
+
end
|
407
|
+
|
408
|
+
expect_any_instance_of(RSpecTestServiceStubBeforeAfterImplementation).not_to receive(:list)
|
409
|
+
|
410
|
+
get '/v2/rspec_test_service_before_after_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
# -------------------------------------------------------------------------
|
415
|
+
|
416
|
+
describe 'service implementation #list' do
|
417
|
+
it 'should get called with default values' do
|
418
|
+
|
419
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
420
|
+
expect(context).to be_a(Hoodoo::Services::Context)
|
421
|
+
|
422
|
+
session = context.session
|
423
|
+
request = context.request
|
424
|
+
response = context.response
|
425
|
+
|
426
|
+
expect(session).to be_a(Hoodoo::Services::Session)
|
427
|
+
expect(request).to be_a(Hoodoo::Services::Request)
|
428
|
+
expect(response).to be_a(Hoodoo::Services::Response)
|
429
|
+
|
430
|
+
expect(request.locale).to eq('en-nz')
|
431
|
+
expect(request.uri_path_components).to be_empty
|
432
|
+
expect(request.ident).to be_nil
|
433
|
+
expect(request.uri_path_extension).to eq('')
|
434
|
+
expect(request.list.offset).to eq(0)
|
435
|
+
expect(request.list.limit).to eq(50)
|
436
|
+
expect(request.list.sort_data).to eq({'created_at'=>'desc'})
|
437
|
+
expect(request.list.search_data).to eq({})
|
438
|
+
expect(request.list.filter_data).to eq({})
|
439
|
+
expect(request.embeds).to eq([])
|
440
|
+
expect(request.references).to eq([])
|
441
|
+
end
|
442
|
+
|
443
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
444
|
+
expect(last_response.status).to eq(200)
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'should pass on locale correctly (1)' do
|
448
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
449
|
+
expect(context.request.locale).to eq('en-gb')
|
450
|
+
end
|
451
|
+
|
452
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8',
|
453
|
+
'HTTP_CONTENT_LANGUAGE' => 'EN-GB' }
|
454
|
+
expect(last_response.status).to eq(200)
|
455
|
+
end
|
456
|
+
|
457
|
+
it 'should pass on locale correctly (2)' do
|
458
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
459
|
+
expect(context.request.locale).to eq('en-gb')
|
460
|
+
end
|
461
|
+
|
462
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8',
|
463
|
+
'HTTP_ACCEPT_LANGUAGE' => 'en-GB;q=0.8, en;q=0.7' }
|
464
|
+
expect(last_response.status).to eq(200)
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'should get called on varied path forms (1)' do
|
468
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list)
|
469
|
+
get '/v2/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
470
|
+
expect(last_response.status).to eq(200)
|
471
|
+
end
|
472
|
+
|
473
|
+
it 'should get called on varied path forms (2)' do
|
474
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list)
|
475
|
+
get '/v2/rspec_test_service_stub.json', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
476
|
+
expect(last_response.status).to eq(200)
|
477
|
+
end
|
478
|
+
|
479
|
+
context 'without ActiveRecord' do
|
480
|
+
before :each do
|
481
|
+
@ar = ActiveRecord
|
482
|
+
Object.send( :remove_const, :ActiveRecord )
|
483
|
+
end
|
484
|
+
|
485
|
+
after :each do
|
486
|
+
ActiveRecord = @ar
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'still calls the service' do
|
490
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list)
|
491
|
+
get '/v2/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
492
|
+
expect(last_response.status).to eq(200)
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
# We allow this odd form because if it were to be considered 'show', then
|
497
|
+
# it'd be show with no path components and a JSON format request. That
|
498
|
+
# makes no sense. So it drops out logically as 'list'.
|
499
|
+
#
|
500
|
+
it 'should get called on varied path forms (3)' do
|
501
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list)
|
502
|
+
get '/v2/rspec_test_service_stub/.json', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
503
|
+
expect(last_response.status).to eq(200)
|
504
|
+
end
|
505
|
+
|
506
|
+
it 'should complain if the subclass omits the implementation' do
|
507
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).and_call_original
|
508
|
+
get '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
509
|
+
expect(last_response.status).to eq(500)
|
510
|
+
result = JSON.parse(last_response.body)
|
511
|
+
expect(result['errors'][0]['message']).to eq("Hoodoo::Services::Implementation subclasses must implement 'list'")
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'should complain if any body data is given' do
|
515
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
516
|
+
get '/v2/rspec_test_service_stub/', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
517
|
+
expect(last_response.status).to eq(422)
|
518
|
+
result = JSON.parse(last_response.body)
|
519
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'should complain about prohibited query entries' do
|
523
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
524
|
+
get '/v2/rspec_test_service_stub?imaginary=42', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
525
|
+
expect(last_response.status).to eq(422)
|
526
|
+
result = JSON.parse(last_response.body)
|
527
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'should respond to limit query parameter' do
|
531
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
532
|
+
expect(context.request.list.offset).to eq(0)
|
533
|
+
expect(context.request.list.limit).to eq(42)
|
534
|
+
end
|
535
|
+
|
536
|
+
get '/v2/rspec_test_service_stub?limit=42', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
537
|
+
expect(last_response.status).to eq(200)
|
538
|
+
end
|
539
|
+
|
540
|
+
it 'should take the last limit query parameter if several are given' do
|
541
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
542
|
+
expect(context.request.list.offset).to eq(0)
|
543
|
+
expect(context.request.list.limit).to eq(9)
|
544
|
+
end
|
545
|
+
|
546
|
+
get '/v2/rspec_test_service_stub?limit=15&limit=42&limit=9', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
547
|
+
expect(last_response.status).to eq(200)
|
548
|
+
end
|
549
|
+
|
550
|
+
def test_with_limit( limit )
|
551
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
552
|
+
get "/v2/rspec_test_service_stub?limit=#{ limit }", nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
553
|
+
expect(last_response.status).to eq(422)
|
554
|
+
result = JSON.parse(last_response.body)
|
555
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
556
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
557
|
+
expect(result['errors'][0]['reference']).to eq('limit')
|
558
|
+
end
|
559
|
+
|
560
|
+
it 'should complain about non-numeric limit query parameter' do
|
561
|
+
test_with_limit( 'foo' )
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'should complain about zero limit query parameter' do
|
565
|
+
test_with_limit( 0 )
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'should complain about negative limit query parameter' do
|
569
|
+
test_with_limit( -1 )
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'should respond to offset query parameter' do
|
573
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
574
|
+
expect(context.request.list.offset).to eq(42)
|
575
|
+
expect(context.request.list.limit).to eq(50)
|
576
|
+
end
|
577
|
+
|
578
|
+
get '/v2/rspec_test_service_stub?offset=42', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
579
|
+
expect(last_response.status).to eq(200)
|
580
|
+
end
|
581
|
+
|
582
|
+
it 'should take the last offset query parameter if several are given' do
|
583
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
584
|
+
expect(context.request.list.offset).to eq(24)
|
585
|
+
expect(context.request.list.limit).to eq(50)
|
586
|
+
end
|
587
|
+
|
588
|
+
get '/v2/rspec_test_service_stub?offset=4&offset=42&offset=24', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
589
|
+
expect(last_response.status).to eq(200)
|
590
|
+
end
|
591
|
+
|
592
|
+
def test_with_offset( offset )
|
593
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
594
|
+
get "/v2/rspec_test_service_stub?offset=#{ offset }", nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
595
|
+
expect(last_response.status).to eq(422)
|
596
|
+
result = JSON.parse(last_response.body)
|
597
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
598
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
599
|
+
expect(result['errors'][0]['reference']).to eq('offset')
|
600
|
+
end
|
601
|
+
|
602
|
+
it 'should complain about non-numeric offset query parameter' do
|
603
|
+
test_with_offset( 'foo' )
|
604
|
+
end
|
605
|
+
|
606
|
+
it 'should complain about negative offset query parameter' do
|
607
|
+
test_with_offset( -1 )
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'should take the last offset and last query parameter if several are given' do
|
611
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
612
|
+
expect(context.request.list.offset).to eq(24)
|
613
|
+
expect(context.request.list.limit).to eq(23)
|
614
|
+
end
|
615
|
+
|
616
|
+
get '/v2/rspec_test_service_stub?limit=2&offset=42&limit=14&limit=23&offset=24', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
617
|
+
expect(last_response.status).to eq(200)
|
618
|
+
end
|
619
|
+
|
620
|
+
it 'should respond to sort query parameter' do
|
621
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
622
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'up'})
|
623
|
+
end
|
624
|
+
|
625
|
+
get '/v2/rspec_test_service_stub?sort=extra', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
626
|
+
expect(last_response.status).to eq(200)
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'should respond to several sort query parameters (form 1)' do
|
630
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
631
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'up', 'created_at'=>'desc'})
|
632
|
+
end
|
633
|
+
|
634
|
+
get '/v2/rspec_test_service_stub?sort=extra,created_at&direction=up,desc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
635
|
+
expect(last_response.status).to eq(200)
|
636
|
+
end
|
637
|
+
|
638
|
+
it 'should respond to several sort query parameters (form 2)' do
|
639
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
640
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'up', 'created_at'=>'desc'})
|
641
|
+
end
|
642
|
+
|
643
|
+
get '/v2/rspec_test_service_stub?sort=extra&sort=created_at&direction=up,desc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
644
|
+
expect(last_response.status).to eq(200)
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should respond to several sort query parameters, with duplicates' do
|
648
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
649
|
+
expect(context.request.list.sort_data).to eq({'created_at'=>'desc', 'extra'=>'up'})
|
650
|
+
end
|
651
|
+
|
652
|
+
get '/v2/rspec_test_service_stub?sort=extra,extra&sort=created_at&sort=extra&direction=up,desc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
653
|
+
expect(last_response.status).to eq(200)
|
654
|
+
end
|
655
|
+
|
656
|
+
it 'should complain about bad sort query parameter' do
|
657
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
658
|
+
get '/v2/rspec_test_service_stub?sort=foo', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
659
|
+
expect(last_response.status).to eq(422)
|
660
|
+
result = JSON.parse(last_response.body)
|
661
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
662
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
663
|
+
expect(result['errors'][0]['reference']).to eq('sort')
|
664
|
+
end
|
665
|
+
|
666
|
+
it 'should respond to direction query parameter, with infered sort' do
|
667
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
668
|
+
expect(context.request.list.sort_data).to eq({'created_at'=>'asc'})
|
669
|
+
end
|
670
|
+
|
671
|
+
get '/v2/rspec_test_service_stub?direction=asc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
672
|
+
expect(last_response.status).to eq(200)
|
673
|
+
end
|
674
|
+
|
675
|
+
it 'should respond to direction query parameter, with explicit sort' do
|
676
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
677
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'down'})
|
678
|
+
end
|
679
|
+
|
680
|
+
get '/v2/rspec_test_service_stub?sort=extra&direction=down', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
681
|
+
expect(last_response.status).to eq(200)
|
682
|
+
end
|
683
|
+
|
684
|
+
it 'should respond to multiple direction query parameters (form 1)' do
|
685
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
686
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'down', 'created_at'=>'asc'})
|
687
|
+
end
|
688
|
+
|
689
|
+
get '/v2/rspec_test_service_stub?sort=extra,created_at&direction=down,asc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
690
|
+
expect(last_response.status).to eq(200)
|
691
|
+
end
|
692
|
+
|
693
|
+
it 'should respond to multiple direction query parameters (form 2)' do
|
694
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
695
|
+
expect(context.request.list.sort_data).to eq({'extra'=>'down', 'created_at'=>'asc'})
|
696
|
+
end
|
697
|
+
|
698
|
+
get '/v2/rspec_test_service_stub?direction=down&sort=extra,created_at&direction=asc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
699
|
+
expect(last_response.status).to eq(200)
|
700
|
+
end
|
701
|
+
|
702
|
+
# When there's more than one sort parameter, we need a matching number
|
703
|
+
# of sort and direction keys. Use valid sort keys and directions so we
|
704
|
+
# know that the "platform.malformed" the test expects is actually
|
705
|
+
# coming from the count mismatch, not because the parameters are not
|
706
|
+
# recognised sort keys or dierctions.
|
707
|
+
#
|
708
|
+
it 'should complain about too many direction query parameters' do
|
709
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
710
|
+
get '/v2/rspec_test_service_stub?sort=created_at&direction=desc,down', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
711
|
+
expect(last_response.status).to eq(422)
|
712
|
+
result = JSON.parse(last_response.body)
|
713
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
714
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
715
|
+
expect(result['errors'][0]['reference']).to eq('direction')
|
716
|
+
end
|
717
|
+
|
718
|
+
it 'should complain about too many sort query parameters' do
|
719
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
720
|
+
get '/v2/rspec_test_service_stub?sort=created_at,extra&direction=desc', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
721
|
+
expect(last_response.status).to eq(422)
|
722
|
+
result = JSON.parse(last_response.body)
|
723
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
724
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
725
|
+
expect(result['errors'][0]['reference']).to eq('direction')
|
726
|
+
end
|
727
|
+
|
728
|
+
it 'should complain about bad direction query parameter' do
|
729
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
730
|
+
get '/v2/rspec_test_service_stub?sort=created_at&direction=foo', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
731
|
+
expect(last_response.status).to eq(422)
|
732
|
+
result = JSON.parse(last_response.body)
|
733
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
734
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
735
|
+
expect(result['errors'][0]['reference']).to eq('direction')
|
736
|
+
end
|
737
|
+
|
738
|
+
it 'should respond to search query parameter (form 1)' do
|
739
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
740
|
+
expect(context.request.list.search_data).to eq({'foo' => 'val', 'bar' => 'more'})
|
741
|
+
end
|
742
|
+
|
743
|
+
get '/v2/rspec_test_service_stub?search=foo%3Dval%26bar%3Dmore', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
744
|
+
expect(last_response.status).to eq(200)
|
745
|
+
end
|
746
|
+
|
747
|
+
it 'should respond to search query parameter (form 2)' do
|
748
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
749
|
+
expect(context.request.list.search_data).to eq({'foo' => 'val', 'bar' => 'more'})
|
750
|
+
end
|
751
|
+
|
752
|
+
get '/v2/rspec_test_service_stub?search=foo%3Dval&search=bar%3Dmore', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
753
|
+
expect(last_response.status).to eq(200)
|
754
|
+
end
|
755
|
+
|
756
|
+
it 'should respond to search query parameter, resolving duplicates' do
|
757
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
758
|
+
expect(context.request.list.search_data).to eq({'foo' => 'override', 'bar' => 'more'})
|
759
|
+
end
|
760
|
+
|
761
|
+
get '/v2/rspec_test_service_stub?search=foo%3Dval&search=bar%3Dmore%26foo%3Doverride', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
762
|
+
expect(last_response.status).to eq(200)
|
763
|
+
end
|
764
|
+
|
765
|
+
it 'should complain about bad search query parameter (form 1)' do
|
766
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
767
|
+
get '/v2/rspec_test_service_stub?search=thing%3Dval%26thang%3Dval', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
768
|
+
expect(last_response.status).to eq(422)
|
769
|
+
result = JSON.parse(last_response.body)
|
770
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
771
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
772
|
+
expect(result['errors'][0]['reference']).to eq('search: thing\\, thang')
|
773
|
+
end
|
774
|
+
|
775
|
+
it 'should complain about bad search query parameter (form 2)' do
|
776
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
777
|
+
get '/v2/rspec_test_service_stub?search=thing%3Dval&search=thang%3Dval', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
778
|
+
expect(last_response.status).to eq(422)
|
779
|
+
result = JSON.parse(last_response.body)
|
780
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
781
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
782
|
+
expect(result['errors'][0]['reference']).to eq('search: thing\\, thang')
|
783
|
+
end
|
784
|
+
|
785
|
+
it 'should respond to filter query parameter (form 1)' do
|
786
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
787
|
+
expect(context.request.list.filter_data).to eq({'baz' => 'more', 'boo' => 'val'})
|
788
|
+
end
|
789
|
+
|
790
|
+
get '/v2/rspec_test_service_stub?filter=boo%3Dval%26baz%3Dmore', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
791
|
+
expect(last_response.status).to eq(200)
|
792
|
+
end
|
793
|
+
|
794
|
+
it 'should respond to filter query parameter (form 2)' do
|
795
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
796
|
+
expect(context.request.list.filter_data).to eq({'baz' => 'more', 'boo' => 'val'})
|
797
|
+
end
|
798
|
+
|
799
|
+
get '/v2/rspec_test_service_stub?filter=boo%3Dval&filter=baz%3Dmore', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
800
|
+
expect(last_response.status).to eq(200)
|
801
|
+
end
|
802
|
+
|
803
|
+
it 'should respond to filter query parameter, resolving duplicates' do
|
804
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
805
|
+
expect(context.request.list.filter_data).to eq({'boo' => 'override1', 'baz' => 'override2'})
|
806
|
+
end
|
807
|
+
|
808
|
+
get '/v2/rspec_test_service_stub?filter=boo%3Dval&filter=baz%3Dmore&filter=baz%3Doverride2%26boo%3Doverride1', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
809
|
+
expect(last_response.status).to eq(200)
|
810
|
+
end
|
811
|
+
|
812
|
+
it 'should complain about bad filter query parameter (form 1)' do
|
813
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
814
|
+
get '/v2/rspec_test_service_stub?filter=thung%3Dval%26theng%3Dval', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
815
|
+
expect(last_response.status).to eq(422)
|
816
|
+
result = JSON.parse(last_response.body)
|
817
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
818
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
819
|
+
expect(result['errors'][0]['reference']).to eq('filter: thung\\, theng')
|
820
|
+
end
|
821
|
+
|
822
|
+
it 'should complain about bad search and filter query parameter' do
|
823
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
824
|
+
get '/v2/rspec_test_service_stub?search=thung%3Dval&filter=theng%3Dval', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
825
|
+
expect(last_response.status).to eq(422)
|
826
|
+
result = JSON.parse(last_response.body)
|
827
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
828
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
829
|
+
expect(result['errors'][0]['reference']).to eq('search: thung\\, filter: theng')
|
830
|
+
end
|
831
|
+
|
832
|
+
it 'should complain about bad filter query parameter (form 2)' do
|
833
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
834
|
+
get '/v2/rspec_test_service_stub?filter=thung%3Dval&filter=theng%3Dval', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
835
|
+
expect(last_response.status).to eq(422)
|
836
|
+
result = JSON.parse(last_response.body)
|
837
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
838
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
839
|
+
expect(result['errors'][0]['reference']).to eq('filter: thung\\, theng')
|
840
|
+
end
|
841
|
+
|
842
|
+
it 'should respond to embed query parameter' do
|
843
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
844
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
845
|
+
end
|
846
|
+
|
847
|
+
get '/v2/rspec_test_service_stub?_embed=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
848
|
+
expect(last_response.status).to eq(200)
|
849
|
+
end
|
850
|
+
|
851
|
+
it 'should filter out duplicates in embed query parameter' do
|
852
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
853
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
854
|
+
end
|
855
|
+
|
856
|
+
get '/v2/rspec_test_service_stub?_embed=embs,emb,embs,embs,emb,emb,embs', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
857
|
+
expect(last_response.status).to eq(200)
|
858
|
+
end
|
859
|
+
|
860
|
+
it 'should complain about bad embed query parameter' do
|
861
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
862
|
+
get '/v2/rspec_test_service_stub?_embed=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
863
|
+
expect(last_response.status).to eq(422)
|
864
|
+
result = JSON.parse(last_response.body)
|
865
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
866
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
867
|
+
expect(result['errors'][0]['reference']).to eq('_embed: one\\, two')
|
868
|
+
end
|
869
|
+
|
870
|
+
it 'should respond to reference query parameter' do
|
871
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
872
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
873
|
+
end
|
874
|
+
|
875
|
+
get '/v2/rspec_test_service_stub?_reference=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
876
|
+
expect(last_response.status).to eq(200)
|
877
|
+
end
|
878
|
+
|
879
|
+
it 'should filter out duplicates in reference query parameter' do
|
880
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
881
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
882
|
+
end
|
883
|
+
|
884
|
+
get '/v2/rspec_test_service_stub?_reference=embs,emb,embs,embs,emb,emb,embs', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
885
|
+
expect(last_response.status).to eq(200)
|
886
|
+
end
|
887
|
+
|
888
|
+
it 'should complain about bad reference query parameter' do
|
889
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
890
|
+
get '/v2/rspec_test_service_stub?_reference=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
891
|
+
expect(last_response.status).to eq(422)
|
892
|
+
result = JSON.parse(last_response.body)
|
893
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
894
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
895
|
+
expect(result['errors'][0]['reference']).to eq('_reference: one\\, two')
|
896
|
+
end
|
897
|
+
|
898
|
+
it 'should complain about several bad query parameters' do
|
899
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
900
|
+
get '/v2/rspec_test_service_stub?_reference=one,emb,two&direction=asc&sort=foo', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
901
|
+
expect(last_response.status).to eq(422)
|
902
|
+
result = JSON.parse(last_response.body)
|
903
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
904
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
905
|
+
expect(result['errors'][0]['reference']).to eq('sort\\, _reference: one\\, two')
|
906
|
+
end
|
907
|
+
|
908
|
+
end
|
909
|
+
|
910
|
+
# -------------------------------------------------------------------------
|
911
|
+
|
912
|
+
describe 'service implementation #show' do
|
913
|
+
it 'should get called with correct path data (1)' do
|
914
|
+
|
915
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once do | ignored_rspec_mock_instance, context |
|
916
|
+
expect(context.request.uri_path_components).to eq(['12345'])
|
917
|
+
expect(context.request.ident).to eq('12345')
|
918
|
+
expect(context.request.uri_path_extension).to eq('tar.gz')
|
919
|
+
end
|
920
|
+
|
921
|
+
get '/v2/rspec_test_service_stub/12345.tar.gz', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
922
|
+
expect(last_response.status).to eq(200)
|
923
|
+
end
|
924
|
+
|
925
|
+
it 'should get called with correct path data (2)' do
|
926
|
+
|
927
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once do | ignored_rspec_mock_instance, context |
|
928
|
+
expect(context.request.uri_path_components).to eq(['12345', '67890'])
|
929
|
+
expect(context.request.ident).to eq('12345')
|
930
|
+
expect(context.request.uri_path_extension).to eq('json')
|
931
|
+
end
|
932
|
+
|
933
|
+
get '/v2/rspec_test_service_stub/12345/67890.json', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
934
|
+
expect(last_response.status).to eq(200)
|
935
|
+
end
|
936
|
+
|
937
|
+
it 'should get called with correct path data (3)' do
|
938
|
+
|
939
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once do | ignored_rspec_mock_instance, context |
|
940
|
+
expect(context.request.uri_path_components).to eq(['12345abc'])
|
941
|
+
expect(context.request.ident).to eq('12345abc')
|
942
|
+
expect(context.request.uri_path_extension).to eq('')
|
943
|
+
end
|
944
|
+
|
945
|
+
get '/v2/rspec_test_service_stub/12345abc/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
946
|
+
expect(last_response.status).to eq(200)
|
947
|
+
end
|
948
|
+
|
949
|
+
it 'should complain if the subclass omits the implementation' do
|
950
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).and_call_original
|
951
|
+
get '/v2/rspec_test_service_stub/12345.tar.gz', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
952
|
+
expect(last_response.status).to eq(500)
|
953
|
+
result = JSON.parse(last_response.body)
|
954
|
+
expect(result['errors'][0]['message']).to eq("Hoodoo::Services::Implementation subclasses must implement 'show'")
|
955
|
+
end
|
956
|
+
|
957
|
+
it 'should complain if any body data is given' do
|
958
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:show)
|
959
|
+
get '/v2/rspec_test_service_stub/12345.tar.gz', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
960
|
+
expect(last_response.status).to eq(422)
|
961
|
+
result = JSON.parse(last_response.body)
|
962
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
963
|
+
end
|
964
|
+
|
965
|
+
it 'should complain about prohibited query entries (1)' do
|
966
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:show)
|
967
|
+
get '/v2/rspec_test_service_stub/12345?limit=25', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
968
|
+
expect(last_response.status).to eq(422)
|
969
|
+
result = JSON.parse(last_response.body)
|
970
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
971
|
+
end
|
972
|
+
|
973
|
+
it 'should complain about prohibited query entries (2)' do
|
974
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:show)
|
975
|
+
get '/v2/rspec_test_service_stub/12345?imaginary=25', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
976
|
+
expect(last_response.status).to eq(422)
|
977
|
+
result = JSON.parse(last_response.body)
|
978
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
979
|
+
end
|
980
|
+
|
981
|
+
it 'should respond to embed query parameter' do
|
982
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once do | ignored_rspec_mock_instance, context |
|
983
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
984
|
+
end
|
985
|
+
|
986
|
+
get '/v2/rspec_test_service_stub/12345?_embed=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
987
|
+
expect(last_response.status).to eq(200)
|
988
|
+
end
|
989
|
+
|
990
|
+
it 'should complain about bad embed query parameter' do
|
991
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:show)
|
992
|
+
get '/v2/rspec_test_service_stub/12345?_embed=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
993
|
+
expect(last_response.status).to eq(422)
|
994
|
+
result = JSON.parse(last_response.body)
|
995
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
996
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
997
|
+
expect(result['errors'][0]['reference']).to eq('_embed: one\\, two')
|
998
|
+
end
|
999
|
+
|
1000
|
+
it 'should respond to reference query parameter' do
|
1001
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:show).once do | ignored_rspec_mock_instance, context |
|
1002
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
get '/v2/rspec_test_service_stub/12345?_reference=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1006
|
+
expect(last_response.status).to eq(200)
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
it 'should complain about bad reference query parameter' do
|
1010
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:show)
|
1011
|
+
get '/v2/rspec_test_service_stub/12345?_reference=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1012
|
+
expect(last_response.status).to eq(422)
|
1013
|
+
result = JSON.parse(last_response.body)
|
1014
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1015
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1016
|
+
expect(result['errors'][0]['reference']).to eq('_reference: one\\, two')
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
1020
|
+
# -------------------------------------------------------------------------
|
1021
|
+
|
1022
|
+
describe 'service implementation #create' do
|
1023
|
+
it 'should complain if the payload is missing' do
|
1024
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1025
|
+
post '/v2/rspec_test_service_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1026
|
+
expect(last_response.status).to eq(422)
|
1027
|
+
result = JSON.parse(last_response.body)
|
1028
|
+
expect(result['errors'][0]['code']).to eq('generic.malformed')
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
it 'should complain if the payload is invalid JSON' do
|
1032
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1033
|
+
post '/v2/rspec_test_service_stub', "oiushdfoisuhdf", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1034
|
+
expect(last_response.status).to eq(422)
|
1035
|
+
result = JSON.parse(last_response.body)
|
1036
|
+
expect(result['errors'][0]['code']).to eq('generic.malformed')
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
it 'should complain if the payload is too large' do
|
1040
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1041
|
+
post '/v2/rspec_test_service_stub', "{\"foo\": \"#{'*' * Hoodoo::Services::Middleware::MAXIMUM_PAYLOAD_SIZE }\"}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1042
|
+
expect(last_response.status).to eq(422)
|
1043
|
+
result = JSON.parse(last_response.body)
|
1044
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
it 'should complain about incorrect to-create data' do
|
1048
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1049
|
+
post '/v2/rspec_test_service_stub', '{ "bar": "not-an-int" }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1050
|
+
expect(last_response.status).to eq(422)
|
1051
|
+
result = JSON.parse(last_response.body)
|
1052
|
+
expect(result['errors'].size).to eq(2)
|
1053
|
+
expect(result['errors'][0]['message']).to eq('Field `foo` is required')
|
1054
|
+
expect(result['errors'][1]['message']).to eq('Field `bar` is an invalid integer')
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
it 'should be happy with valid JSON' do
|
1058
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create)
|
1059
|
+
post '/v2/rspec_test_service_stub', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1060
|
+
expect(last_response.status).to eq(200)
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
it 'should be happy with no JSON and no to-create verification' do
|
1064
|
+
old = RSpecTestServiceStubInterface.to_create
|
1065
|
+
RSpecTestServiceStubInterface.send(:to_create=, nil)
|
1066
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create)
|
1067
|
+
post '/v2/rspec_test_service_stub', '{}', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1068
|
+
expect(last_response.status).to eq(200)
|
1069
|
+
RSpecTestServiceStubInterface.send(:to_create=, old)
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
it 'should pass the JSON through' do
|
1073
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create).once do | ignored_rspec_mock_instance, context |
|
1074
|
+
expect(context.request.body).to eq({'foo' => 'present', 'bar' => 42})
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
post '/v2/rspec_test_service_stub', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1078
|
+
expect(last_response.status).to eq(200)
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
it 'should complain if there is irrelevant path data' do
|
1082
|
+
post '/v2/rspec_test_service_stub/12345', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1083
|
+
expect(last_response.status).to eq(422)
|
1084
|
+
end
|
1085
|
+
|
1086
|
+
it 'should complain if the subclass omits the implementation' do
|
1087
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create).once.and_call_original
|
1088
|
+
post '/v2/rspec_test_service_stub/', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1089
|
+
expect(last_response.status).to eq(500)
|
1090
|
+
result = JSON.parse(last_response.body)
|
1091
|
+
expect(result['errors'][0]['message']).to eq("Hoodoo::Services::Implementation subclasses must implement 'create'")
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
it 'should complain about prohibited query entries (1)' do
|
1095
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1096
|
+
post '/v2/rspec_test_service_stub?limit=25', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1097
|
+
expect(last_response.status).to eq(422)
|
1098
|
+
result = JSON.parse(last_response.body)
|
1099
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
it 'should complain about prohibited query entries (2)' do
|
1103
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1104
|
+
post '/v2/rspec_test_service_stub?imaginary=25', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1105
|
+
expect(last_response.status).to eq(422)
|
1106
|
+
result = JSON.parse(last_response.body)
|
1107
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1108
|
+
end
|
1109
|
+
|
1110
|
+
it 'should respond to embed query parameter' do
|
1111
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create).once do | ignored_rspec_mock_instance, context |
|
1112
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
post '/v2/rspec_test_service_stub?_embed=embs,emb', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1116
|
+
expect(last_response.status).to eq(200)
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
it 'should complain about bad embed query parameter' do
|
1120
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1121
|
+
post '/v2/rspec_test_service_stub?_embed=one,emb,two', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1122
|
+
expect(last_response.status).to eq(422)
|
1123
|
+
result = JSON.parse(last_response.body)
|
1124
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1125
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1126
|
+
expect(result['errors'][0]['reference']).to eq('_embed: one\\, two')
|
1127
|
+
end
|
1128
|
+
|
1129
|
+
it 'should respond to reference query parameter' do
|
1130
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create).once do | ignored_rspec_mock_instance, context |
|
1131
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
post '/v2/rspec_test_service_stub?_reference=embs,emb', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1135
|
+
expect(last_response.status).to eq(200)
|
1136
|
+
end
|
1137
|
+
|
1138
|
+
it 'should complain about bad reference query parameter' do
|
1139
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:create)
|
1140
|
+
post '/v2/rspec_test_service_stub?_reference=one,emb,two', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1141
|
+
expect(last_response.status).to eq(422)
|
1142
|
+
result = JSON.parse(last_response.body)
|
1143
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1144
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1145
|
+
expect(result['errors'][0]['reference']).to eq('_reference: one\\, two')
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
context 'with X-Deja-Vu' do
|
1149
|
+
before(:each) do
|
1150
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:create).once do | ignored_rspec_mock_instance, context |
|
1151
|
+
context.response.add_error(
|
1152
|
+
'generic.invalid_duplication',
|
1153
|
+
{
|
1154
|
+
:message => 'testing duplication',
|
1155
|
+
:reference => { :field_name => 'test_field' }
|
1156
|
+
}
|
1157
|
+
)
|
1158
|
+
end
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
it 'handles "yes"' do
|
1162
|
+
post '/v2/rspec_test_service_stub', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8',
|
1163
|
+
'HTTP_X_DEJA_VU' => 'yes' }
|
1164
|
+
|
1165
|
+
expect(last_response.status).to eq(204)
|
1166
|
+
expect(last_response.body).to be_empty
|
1167
|
+
expect(last_response.headers['X-Deja-Vu']).to eq('confirmed')
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
['No', 'no', 'foo', 'bar', 'true', 'yes '].each do | invalid_value |
|
1171
|
+
it "ignores invalid value #{invalid_value}" do
|
1172
|
+
post '/v2/rspec_test_service_stub', '{ "foo": "present", "bar": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8',
|
1173
|
+
'HTTP_X_DEJA_VU' => invalid_value }
|
1174
|
+
|
1175
|
+
expect(last_response.status).to eq(422)
|
1176
|
+
expect(last_response.headers).to_not include('X-Deja-Vu')
|
1177
|
+
end
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
# -------------------------------------------------------------------------
|
1184
|
+
|
1185
|
+
describe 'service implementation #update' do
|
1186
|
+
it 'should complain if the payload is missing' do
|
1187
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1188
|
+
patch '/v2/rspec_test_service_stub/1234', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1189
|
+
expect(last_response.status).to eq(422)
|
1190
|
+
result = JSON.parse(last_response.body)
|
1191
|
+
expect(result['errors'][0]['code']).to eq('generic.malformed')
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
it 'should complain if the payload is invalid JSON' do
|
1195
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1196
|
+
patch '/v2/rspec_test_service_stub/1234', "oiushdfoisuhdf", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1197
|
+
expect(last_response.status).to eq(422)
|
1198
|
+
result = JSON.parse(last_response.body)
|
1199
|
+
expect(result['errors'][0]['code']).to eq('generic.malformed')
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
it 'should complain about incorrect to-update data' do
|
1203
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1204
|
+
patch '/v2/rspec_test_service_stub/1234', '{ "baz": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1205
|
+
expect(last_response.status).to eq(422)
|
1206
|
+
result = JSON.parse(last_response.body)
|
1207
|
+
expect(result['errors'].size).to eq(1)
|
1208
|
+
expect(result['errors'][0]['message']).to eq('Field `baz` is an invalid string')
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
it 'should be happy with valid JSON' do
|
1212
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update)
|
1213
|
+
patch '/v2/rspec_test_service_stub/1234', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1214
|
+
expect(last_response.status).to eq(200)
|
1215
|
+
end
|
1216
|
+
|
1217
|
+
it 'should be happy with no JSON and no to-update verification' do
|
1218
|
+
old = RSpecTestServiceStubInterface.to_update
|
1219
|
+
RSpecTestServiceStubInterface.send(:to_update=, nil)
|
1220
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update)
|
1221
|
+
patch '/v2/rspec_test_service_stub/1234', '{}', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1222
|
+
expect(last_response.status).to eq(200)
|
1223
|
+
RSpecTestServiceStubInterface.send(:to_update=, old)
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
it 'should complain about missing path components' do
|
1227
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1228
|
+
patch '/v2/rspec_test_service_stub/', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1229
|
+
expect(last_response.status).to eq(422)
|
1230
|
+
result = JSON.parse(last_response.body)
|
1231
|
+
expect(result['errors'][0]['message']).to eq('Expected path components identifying target resource instance for this action')
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
it 'should get called with correct path data' do
|
1235
|
+
|
1236
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update).once do | ignored_rspec_mock_instance, context |
|
1237
|
+
expect(context.request.uri_path_components).to eq(['12345'])
|
1238
|
+
expect(context.request.ident).to eq('12345')
|
1239
|
+
expect(context.request.uri_path_extension).to eq('tar.gz')
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
patch '/v2/rspec_test_service_stub/12345.tar.gz', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1243
|
+
expect(last_response.status).to eq(200)
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
it 'should complain if the subclass omits the implementation' do
|
1247
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update).and_call_original
|
1248
|
+
patch '/v2/rspec_test_service_stub/12345.tar.gz', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1249
|
+
expect(last_response.status).to eq(500)
|
1250
|
+
result = JSON.parse(last_response.body)
|
1251
|
+
expect(result['errors'][0]['message']).to eq("Hoodoo::Services::Implementation subclasses must implement 'update'")
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
it 'should complain about prohibited query entries (1)' do
|
1255
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1256
|
+
patch '/v2/rspec_test_service_stub/12345?limit=25', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1257
|
+
expect(last_response.status).to eq(422)
|
1258
|
+
result = JSON.parse(last_response.body)
|
1259
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
it 'should complain about prohibited query entries (2)' do
|
1263
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1264
|
+
patch '/v2/rspec_test_service_stub/12345?imaginary=25', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1265
|
+
expect(last_response.status).to eq(422)
|
1266
|
+
result = JSON.parse(last_response.body)
|
1267
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1268
|
+
end
|
1269
|
+
|
1270
|
+
it 'should respond to embed query parameter' do
|
1271
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update).once do | ignored_rspec_mock_instance, context |
|
1272
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
patch '/v2/rspec_test_service_stub/12345?_embed=embs,emb', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1276
|
+
expect(last_response.status).to eq(200)
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
it 'should complain about bad embed query parameter' do
|
1280
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1281
|
+
patch '/v2/rspec_test_service_stub/12345?_embed=one,emb,two', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1282
|
+
expect(last_response.status).to eq(422)
|
1283
|
+
result = JSON.parse(last_response.body)
|
1284
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1285
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1286
|
+
expect(result['errors'][0]['reference']).to eq('_embed: one\\, two')
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
it 'should respond to reference query parameter' do
|
1290
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:update).once do | ignored_rspec_mock_instance, context |
|
1291
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
patch '/v2/rspec_test_service_stub/12345?_reference=embs,emb', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1295
|
+
expect(last_response.status).to eq(200)
|
1296
|
+
end
|
1297
|
+
|
1298
|
+
it 'should complain about bad reference query parameter' do
|
1299
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:update)
|
1300
|
+
patch '/v2/rspec_test_service_stub/12345?_reference=one,emb,two', '{ "baz": "string", "foo": 42 }', { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1301
|
+
expect(last_response.status).to eq(422)
|
1302
|
+
result = JSON.parse(last_response.body)
|
1303
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1304
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1305
|
+
expect(result['errors'][0]['reference']).to eq('_reference: one\\, two')
|
1306
|
+
end
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
# -------------------------------------------------------------------------
|
1310
|
+
|
1311
|
+
describe 'service implementation #delete' do
|
1312
|
+
it 'should get called with correct path data' do
|
1313
|
+
|
1314
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:delete).once do | ignored_rspec_mock_instance, context |
|
1315
|
+
expect(context.request.uri_path_components).to eq(['12345'])
|
1316
|
+
expect(context.request.ident).to eq('12345')
|
1317
|
+
expect(context.request.uri_path_extension).to eq('tar.gz')
|
1318
|
+
end
|
1319
|
+
|
1320
|
+
delete '/v2/rspec_test_service_stub/12345.tar.gz', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1321
|
+
expect(last_response.status).to eq(200)
|
1322
|
+
end
|
1323
|
+
|
1324
|
+
it 'should complain if the subclass omits the implementation' do
|
1325
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:delete).and_call_original
|
1326
|
+
delete '/v2/rspec_test_service_stub/12345.tar.gz', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1327
|
+
expect(last_response.status).to eq(500)
|
1328
|
+
result = JSON.parse(last_response.body)
|
1329
|
+
expect(result['errors'][0]['message']).to eq("Hoodoo::Services::Implementation subclasses must implement 'delete'")
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
it 'should complain if any body data is given' do
|
1333
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:delete)
|
1334
|
+
delete '/v2/rspec_test_service_stub/12345.tar.gz', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1335
|
+
expect(last_response.status).to eq(422)
|
1336
|
+
result = JSON.parse(last_response.body)
|
1337
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
it 'should complain about prohibited query entries (1)' do
|
1341
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:delete)
|
1342
|
+
delete '/v2/rspec_test_service_stub/12345?limit=25', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1343
|
+
expect(last_response.status).to eq(422)
|
1344
|
+
result = JSON.parse(last_response.body)
|
1345
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
it 'should complain about prohibited query entries (2)' do
|
1349
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:delete)
|
1350
|
+
delete '/v2/rspec_test_service_stub/12345?imaginary=25', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1351
|
+
expect(last_response.status).to eq(422)
|
1352
|
+
result = JSON.parse(last_response.body)
|
1353
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
it 'should respond to embed query parameter' do
|
1357
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:delete).once do | ignored_rspec_mock_instance, context |
|
1358
|
+
expect(context.request.embeds).to eq(['embs', 'emb'])
|
1359
|
+
end
|
1360
|
+
|
1361
|
+
delete '/v2/rspec_test_service_stub/12345?_embed=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1362
|
+
expect(last_response.status).to eq(200)
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
it 'should complain about bad embed query parameter' do
|
1366
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:delete)
|
1367
|
+
delete '/v2/rspec_test_service_stub/12345?_embed=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1368
|
+
expect(last_response.status).to eq(422)
|
1369
|
+
result = JSON.parse(last_response.body)
|
1370
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1371
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1372
|
+
expect(result['errors'][0]['reference']).to eq('_embed: one\\, two')
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
it 'should respond to reference query parameter' do
|
1376
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:delete).once do | ignored_rspec_mock_instance, context |
|
1377
|
+
expect(context.request.references).to eq(['embs', 'emb'])
|
1378
|
+
end
|
1379
|
+
|
1380
|
+
delete '/v2/rspec_test_service_stub/12345?_reference=embs,emb', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1381
|
+
expect(last_response.status).to eq(200)
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
it 'should complain about bad reference query parameter' do
|
1385
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:delete)
|
1386
|
+
delete '/v2/rspec_test_service_stub/12345?_reference=one,emb,two', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1387
|
+
expect(last_response.status).to eq(422)
|
1388
|
+
result = JSON.parse(last_response.body)
|
1389
|
+
expect(result['errors'][0]['code']).to eq('platform.malformed')
|
1390
|
+
expect(result['errors'][0]['message']).to eq('One or more malformed or invalid query string parameters')
|
1391
|
+
expect(result['errors'][0]['reference']).to eq('_reference: one\\, two')
|
1392
|
+
end
|
1393
|
+
end
|
1394
|
+
end
|
1395
|
+
end
|
1396
|
+
|
1397
|
+
|
1398
|
+
###############################################################################
|
1399
|
+
# Multiple incorrectly configured endpoints
|
1400
|
+
###############################################################################
|
1401
|
+
|
1402
|
+
|
1403
|
+
class RSpecTestBrokenServiceStub < Hoodoo::Services::Service
|
1404
|
+
comprised_of RSpecTestServiceStubInterface,
|
1405
|
+
RSpecTestMatchingServiceStubInterface # I.e. same endpoint twice
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
describe Hoodoo::Services::Middleware do
|
1409
|
+
context 'bad endpoint configuration' do
|
1410
|
+
|
1411
|
+
def app
|
1412
|
+
Rack::Builder.new do
|
1413
|
+
use Hoodoo::Services::Middleware
|
1414
|
+
run RSpecTestBrokenServiceStub.new
|
1415
|
+
end
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
it 'should cause a routing exception' do
|
1419
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to_not receive(:list)
|
1420
|
+
get '/v2/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1421
|
+
expect(last_response.status).to eq(500)
|
1422
|
+
result = JSON.parse(last_response.body)
|
1423
|
+
expect(result['errors'][0]['code']).to eq('platform.fault')
|
1424
|
+
expect(result['errors'][0]['message']).to eq('Multiple service endpoint matches - internal server configuration fault')
|
1425
|
+
end
|
1426
|
+
end
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
|
1430
|
+
###############################################################################
|
1431
|
+
# Multiple correctly configured endpoints
|
1432
|
+
###############################################################################
|
1433
|
+
|
1434
|
+
|
1435
|
+
class RSpecTestServiceV1StubImplementation < Hoodoo::Services::Implementation
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
class RSpecTestServiceV1StubInterface < Hoodoo::Services::Interface
|
1439
|
+
interface :RSpecTestResource do
|
1440
|
+
endpoint :rspec_test_service_stub, RSpecTestServiceV1StubImplementation
|
1441
|
+
actions :list, :create, :update
|
1442
|
+
end
|
1443
|
+
end
|
1444
|
+
|
1445
|
+
class RSpecTestServiceAltStubImplementation < Hoodoo::Services::Implementation
|
1446
|
+
end
|
1447
|
+
|
1448
|
+
class RSpecTestServiceAltStubInterface < Hoodoo::Services::Interface
|
1449
|
+
interface :RSpecTestResource do
|
1450
|
+
version 2
|
1451
|
+
endpoint :rspec_test_service_alt_stub, RSpecTestServiceAltStubImplementation
|
1452
|
+
end
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
class RSpecTestMultipleEndpointServiceStub < Hoodoo::Services::Service
|
1456
|
+
comprised_of RSpecTestServiceStubInterface,
|
1457
|
+
RSpecTestServiceV1StubInterface,
|
1458
|
+
RSpecTestServiceAltStubInterface
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
describe Hoodoo::Services::Middleware do
|
1462
|
+
|
1463
|
+
def app
|
1464
|
+
Rack::Builder.new do
|
1465
|
+
use Hoodoo::Services::Middleware
|
1466
|
+
run RSpecTestMultipleEndpointServiceStub.new
|
1467
|
+
end
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
context 'multiple endpoints and versions' do
|
1471
|
+
it 'should return 404 with no matching route' do
|
1472
|
+
get '/v1/nowhere/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1473
|
+
expect(last_response.status).to eq(404)
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
it 'should route to the V1 endpoint' do
|
1477
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to receive(:list)
|
1478
|
+
get '/v1/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1479
|
+
expect(last_response.status).to eq(200)
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
it 'should route to the V2 endpoint' do
|
1483
|
+
expect_any_instance_of(RSpecTestServiceStubImplementation).to receive(:list)
|
1484
|
+
get '/v2/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1485
|
+
expect(last_response.status).to eq(200)
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
it 'should route to the V2 alternative endpoint' do
|
1489
|
+
expect_any_instance_of(RSpecTestServiceAltStubImplementation).to receive(:list)
|
1490
|
+
get '/v2/rspec_test_service_alt_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1491
|
+
expect(last_response.status).to eq(200)
|
1492
|
+
end
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
context 'with limited supported actions' do
|
1496
|
+
it 'should accept supported actions' do
|
1497
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to receive(:list)
|
1498
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to receive(:create)
|
1499
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to receive(:update)
|
1500
|
+
|
1501
|
+
get '/v1/rspec_test_service_stub/', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1502
|
+
expect(last_response.status).to eq(200)
|
1503
|
+
|
1504
|
+
post '/v1/rspec_test_service_stub/', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1505
|
+
expect(last_response.status).to eq(200)
|
1506
|
+
|
1507
|
+
patch '/v1/rspec_test_service_stub/1234', "{}", { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1508
|
+
expect(last_response.status).to eq(200)
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
it 'should reject unsupported actions' do
|
1512
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to_not receive(:show)
|
1513
|
+
expect_any_instance_of(RSpecTestServiceV1StubImplementation).to_not receive(:delete)
|
1514
|
+
|
1515
|
+
get '/v1/rspec_test_service_stub/1234', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1516
|
+
expect(last_response.status).to eq(405)
|
1517
|
+
result = JSON.parse(last_response.body)
|
1518
|
+
expect(result['errors'][0]['code']).to eq('platform.method_not_allowed')
|
1519
|
+
expect(result['errors'][0]['message']).to eq("Service endpoint '/v1/rspec_test_service_stub' does not support HTTP method 'GET' yielding action 'show'")
|
1520
|
+
|
1521
|
+
delete '/v1/rspec_test_service_stub/1234', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1522
|
+
expect(last_response.status).to eq(405)
|
1523
|
+
result = JSON.parse(last_response.body)
|
1524
|
+
expect(result['errors'][0]['code']).to eq('platform.method_not_allowed')
|
1525
|
+
expect(result['errors'][0]['message']).to eq("Service endpoint '/v1/rspec_test_service_stub' does not support HTTP method 'DELETE' yielding action 'delete'")
|
1526
|
+
end
|
1527
|
+
end
|
1528
|
+
end
|
1529
|
+
|
1530
|
+
|
1531
|
+
###############################################################################
|
1532
|
+
# Custom service error descriptions
|
1533
|
+
###############################################################################
|
1534
|
+
|
1535
|
+
|
1536
|
+
class RSpecTestServiceWithErrorsStubImplementation < Hoodoo::Services::Implementation
|
1537
|
+
end
|
1538
|
+
|
1539
|
+
class RSpecTestServiceWithErrorsStubInterface < Hoodoo::Services::Interface
|
1540
|
+
interface :RSpecTestResource do
|
1541
|
+
version 42
|
1542
|
+
endpoint :rspec_test_service_with_errors_stub, RSpecTestServiceWithErrorsStubImplementation
|
1543
|
+
errors_for :rspec do
|
1544
|
+
error 'hello', :status => 418, 'message' => "I'm a teapot", 'reference' => { :rfc => '2324' }
|
1545
|
+
end
|
1546
|
+
end
|
1547
|
+
end
|
1548
|
+
|
1549
|
+
class RSpecTestServiceWithErrorsStub < Hoodoo::Services::Service
|
1550
|
+
comprised_of RSpecTestServiceWithErrorsStubInterface
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
describe Hoodoo::Services::Middleware do
|
1554
|
+
def app
|
1555
|
+
Rack::Builder.new do
|
1556
|
+
use Hoodoo::Services::Middleware
|
1557
|
+
run RSpecTestServiceWithErrorsStub.new
|
1558
|
+
end
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
it 'should define custom errors' do
|
1562
|
+
expect_any_instance_of(RSpecTestServiceWithErrorsStubImplementation).to receive(:list).once do | ignored_rspec_mock_instance, context |
|
1563
|
+
expect(context.response.errors.instance_variable_get('@descriptions').describe('rspec.hello')).to eq({ 'status' => 418, 'message' => "I'm a teapot", 'reference' => { 'rfc' => '2324' } })
|
1564
|
+
end
|
1565
|
+
|
1566
|
+
get '/v42/rspec_test_service_with_errors_stub', nil, { 'CONTENT_TYPE' => 'application/json; charset=utf-8' }
|
1567
|
+
expect(last_response.status).to eq(200)
|
1568
|
+
end
|
1569
|
+
end
|