smooth_operator 0.4.4 → 1.2.0
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 +9 -9
- data/.gitignore +2 -1
- data/.rspec +4 -0
- data/Gemfile +13 -0
- data/README.md +258 -10
- data/console.rb +44 -0
- data/lib/smooth_operator/array_with_meta_data.rb +31 -0
- data/lib/smooth_operator/attribute_assignment.rb +102 -0
- data/lib/smooth_operator/attribute_methods.rb +87 -0
- data/lib/smooth_operator/attributes/base.rb +107 -0
- data/lib/smooth_operator/attributes/dirty.rb +29 -0
- data/lib/smooth_operator/attributes/normal.rb +15 -0
- data/lib/smooth_operator/delegation.rb +60 -0
- data/lib/smooth_operator/finder_methods.rb +43 -0
- data/lib/smooth_operator/helpers.rb +79 -0
- data/lib/smooth_operator/model_schema.rb +81 -0
- data/lib/smooth_operator/open_struct.rb +37 -0
- data/lib/smooth_operator/operator.rb +145 -0
- data/lib/smooth_operator/operators/faraday.rb +75 -0
- data/lib/smooth_operator/operators/typhoeus.rb +77 -0
- data/lib/smooth_operator/persistence.rb +144 -0
- data/lib/smooth_operator/relation/array_relation.rb +13 -0
- data/lib/smooth_operator/relation/association_reflection.rb +75 -0
- data/lib/smooth_operator/relation/associations.rb +75 -0
- data/lib/smooth_operator/relation/reflection.rb +41 -0
- data/lib/smooth_operator/relation/single_relation.rb +14 -0
- data/lib/smooth_operator/remote_call/base.rb +80 -0
- data/lib/smooth_operator/remote_call/errors/connection_failed.rb +20 -0
- data/lib/smooth_operator/remote_call/errors/timeout.rb +20 -0
- data/lib/smooth_operator/remote_call/faraday.rb +19 -0
- data/lib/smooth_operator/remote_call/typhoeus.rb +19 -0
- data/lib/smooth_operator/serialization.rb +79 -0
- data/lib/smooth_operator/translation.rb +27 -0
- data/lib/smooth_operator/validations.rb +15 -0
- data/lib/smooth_operator/version.rb +1 -1
- data/lib/smooth_operator.rb +26 -5
- data/smooth_operator.gemspec +12 -3
- data/spec/factories/user_factory.rb +34 -0
- data/spec/require_helper.rb +11 -0
- data/spec/smooth_operator/attribute_assignment_spec.rb +351 -0
- data/spec/smooth_operator/attributes_dirty_spec.rb +53 -0
- data/spec/smooth_operator/delegation_spec.rb +139 -0
- data/spec/smooth_operator/finder_methods_spec.rb +105 -0
- data/spec/smooth_operator/model_schema_spec.rb +31 -0
- data/spec/smooth_operator/operator_spec.rb +46 -0
- data/spec/smooth_operator/persistence_spec.rb +424 -0
- data/spec/smooth_operator/remote_call_spec.rb +320 -0
- data/spec/smooth_operator/serialization_spec.rb +80 -0
- data/spec/smooth_operator/validations_spec.rb +42 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/support/helpers/persistence_helper.rb +38 -0
- data/spec/support/localhost_server.rb +97 -0
- data/spec/support/models/address.rb +14 -0
- data/spec/support/models/comment.rb +3 -0
- data/spec/support/models/post.rb +13 -0
- data/spec/support/models/user.rb +41 -0
- data/spec/support/models/user_with_address_and_posts.rb +89 -0
- data/spec/support/test_server.rb +165 -0
- metadata +108 -18
- data/lib/smooth_operator/base.rb +0 -30
- data/lib/smooth_operator/core.rb +0 -218
- data/lib/smooth_operator/http_handlers/typhoeus/base.rb +0 -58
- data/lib/smooth_operator/http_handlers/typhoeus/orm.rb +0 -34
- data/lib/smooth_operator/http_handlers/typhoeus/remote_call.rb +0 -28
- data/lib/smooth_operator/operator/base.rb +0 -43
- data/lib/smooth_operator/operator/exceptions.rb +0 -64
- data/lib/smooth_operator/operator/orm.rb +0 -118
- data/lib/smooth_operator/operator/remote_call.rb +0 -84
@@ -0,0 +1,320 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SmoothOperator::RemoteCall do
|
4
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
5
|
+
|
6
|
+
context "when the server response has a http code in the 200 range" do
|
7
|
+
before { subject.save(nil, { status: 200 }) }
|
8
|
+
|
9
|
+
it "#ok? should return true" do
|
10
|
+
expect(subject.last_remote_call.ok?).to be true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#not_processed? should return false" do
|
14
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#client_error? should return false" do
|
18
|
+
expect(subject.last_remote_call.client_error?).to be false
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#server_error? should return false" do
|
22
|
+
expect(subject.last_remote_call.server_error?).to be false
|
23
|
+
end
|
24
|
+
|
25
|
+
it "#error? should return false" do
|
26
|
+
expect(subject.last_remote_call.error?).to be false
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#not_found? should return false" do
|
30
|
+
expect(subject.last_remote_call.not_found?).to be false
|
31
|
+
end
|
32
|
+
|
33
|
+
it "#timeout? should return false" do
|
34
|
+
expect(subject.last_remote_call.timeout?).to be false
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#connection_failed? should return false" do
|
38
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
39
|
+
end
|
40
|
+
|
41
|
+
it "#status should return true" do
|
42
|
+
expect(subject.last_remote_call.status).to be true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when the server response has a http code in the 400 range (not 422, 404)" do
|
47
|
+
before { subject.save(nil, { status: 400 }) }
|
48
|
+
|
49
|
+
it "#ok? should return false" do
|
50
|
+
expect(subject.last_remote_call.ok?).to be false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "#not_processed? should return false" do
|
54
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
55
|
+
end
|
56
|
+
|
57
|
+
it "#client_error? should return true" do
|
58
|
+
expect(subject.last_remote_call.client_error?).to be true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "#server_error? should return false" do
|
62
|
+
expect(subject.last_remote_call.server_error?).to be false
|
63
|
+
end
|
64
|
+
|
65
|
+
it "#error? should return true" do
|
66
|
+
expect(subject.last_remote_call.error?).to be true
|
67
|
+
end
|
68
|
+
|
69
|
+
it "#not_found? should return false" do
|
70
|
+
expect(subject.last_remote_call.not_found?).to be false
|
71
|
+
end
|
72
|
+
|
73
|
+
it "#timeout? should return false" do
|
74
|
+
expect(subject.last_remote_call.timeout?).to be false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#connection_failed? should return false" do
|
78
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
79
|
+
end
|
80
|
+
|
81
|
+
it "#status should return nil" do
|
82
|
+
expect(subject.last_remote_call.status).to be nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when the server response has a http is 404" do
|
87
|
+
before { subject.save(nil, { status: 404 }) }
|
88
|
+
|
89
|
+
it "#ok? should return false" do
|
90
|
+
expect(subject.last_remote_call.ok?).to be false
|
91
|
+
end
|
92
|
+
|
93
|
+
it "#not_processed? should return false" do
|
94
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
95
|
+
end
|
96
|
+
|
97
|
+
it "#client_error? should return true" do
|
98
|
+
expect(subject.last_remote_call.client_error?).to be true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "#server_error? should return false" do
|
102
|
+
expect(subject.last_remote_call.server_error?).to be false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "#error? should return true" do
|
106
|
+
expect(subject.last_remote_call.error?).to be true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "#not_found? should return true" do
|
110
|
+
expect(subject.last_remote_call.not_found?).to be true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "#timeout? should return false" do
|
114
|
+
expect(subject.last_remote_call.timeout?).to be false
|
115
|
+
end
|
116
|
+
|
117
|
+
it "#connection_failed? should return false" do
|
118
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
119
|
+
end
|
120
|
+
|
121
|
+
it "#status should return nil" do
|
122
|
+
expect(subject.last_remote_call.status).to be nil
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when the server response has a http is 422" do
|
127
|
+
before { subject.save(nil, { status: 422 }) }
|
128
|
+
|
129
|
+
it "#ok? should return false" do
|
130
|
+
expect(subject.last_remote_call.ok?).to be false
|
131
|
+
end
|
132
|
+
|
133
|
+
it "#not_processed? should return true" do
|
134
|
+
expect(subject.last_remote_call.not_processed?).to be true
|
135
|
+
end
|
136
|
+
|
137
|
+
it "#client_error? should return true" do
|
138
|
+
expect(subject.last_remote_call.client_error?).to be true
|
139
|
+
end
|
140
|
+
|
141
|
+
it "#server_error? should return false" do
|
142
|
+
expect(subject.last_remote_call.server_error?).to be false
|
143
|
+
end
|
144
|
+
|
145
|
+
it "#error? should return false" do
|
146
|
+
expect(subject.last_remote_call.error?).to be false
|
147
|
+
end
|
148
|
+
|
149
|
+
it "#not_found? should return false" do
|
150
|
+
expect(subject.last_remote_call.not_found?).to be false
|
151
|
+
end
|
152
|
+
|
153
|
+
it "#timeout? should return false" do
|
154
|
+
expect(subject.last_remote_call.timeout?).to be false
|
155
|
+
end
|
156
|
+
|
157
|
+
it "#connection_failed? should return false" do
|
158
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
159
|
+
end
|
160
|
+
|
161
|
+
it "#status should return false" do
|
162
|
+
expect(subject.last_remote_call.status).to be false
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
context "when the server response has a http code in the 500 range" do
|
167
|
+
before { subject.save(nil, { status: 500 }) }
|
168
|
+
|
169
|
+
it "#ok? should return false" do
|
170
|
+
expect(subject.last_remote_call.ok?).to be false
|
171
|
+
end
|
172
|
+
|
173
|
+
it "#not_processed? should return false" do
|
174
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
175
|
+
end
|
176
|
+
|
177
|
+
it "#client_error? should return false" do
|
178
|
+
expect(subject.last_remote_call.client_error?).to be false
|
179
|
+
end
|
180
|
+
|
181
|
+
it "#server_error? should return true" do
|
182
|
+
expect(subject.last_remote_call.server_error?).to be true
|
183
|
+
end
|
184
|
+
|
185
|
+
it "#error? should return true" do
|
186
|
+
expect(subject.last_remote_call.error?).to be true
|
187
|
+
end
|
188
|
+
|
189
|
+
it "#not_found? should return false" do
|
190
|
+
expect(subject.last_remote_call.not_found?).to be false
|
191
|
+
end
|
192
|
+
|
193
|
+
it "#timeout? should return false" do
|
194
|
+
expect(subject.last_remote_call.timeout?).to be false
|
195
|
+
end
|
196
|
+
|
197
|
+
it "#connection_failed? should return false" do
|
198
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
199
|
+
end
|
200
|
+
|
201
|
+
it "#status should return nil" do
|
202
|
+
expect(subject.last_remote_call.status).to be nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "when the connection is broken" do
|
207
|
+
subject { User::BrokenConnection.new }
|
208
|
+
|
209
|
+
before { subject.save }
|
210
|
+
|
211
|
+
it "#ok? should return false" do
|
212
|
+
expect(subject.last_remote_call.ok?).to be false
|
213
|
+
end
|
214
|
+
|
215
|
+
it "#not_processed? should return false" do
|
216
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
217
|
+
end
|
218
|
+
|
219
|
+
it "#client_error? should return false" do
|
220
|
+
expect(subject.last_remote_call.client_error?).to be false
|
221
|
+
end
|
222
|
+
|
223
|
+
it "#server_error? should return true" do
|
224
|
+
expect(subject.last_remote_call.server_error?).to be true
|
225
|
+
end
|
226
|
+
|
227
|
+
it "#error? should return true" do
|
228
|
+
expect(subject.last_remote_call.error?).to be true
|
229
|
+
end
|
230
|
+
|
231
|
+
it "#not_found? should return false" do
|
232
|
+
expect(subject.last_remote_call.not_found?).to be false
|
233
|
+
end
|
234
|
+
|
235
|
+
it "#timeout? should return false" do
|
236
|
+
expect(subject.last_remote_call.timeout?).to be false
|
237
|
+
end
|
238
|
+
|
239
|
+
it "#connection_failed? should return true" do
|
240
|
+
expect(subject.last_remote_call.connection_failed?).to be true
|
241
|
+
end
|
242
|
+
|
243
|
+
it "#status should return nil" do
|
244
|
+
expect(subject.last_remote_call.status).to be nil
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context "when the connection exceeds the timeout" do
|
249
|
+
subject { User::TimeoutConnection.new }
|
250
|
+
|
251
|
+
before { subject.save('/timeout') }
|
252
|
+
|
253
|
+
it "#ok? should return false" do
|
254
|
+
expect(subject.last_remote_call.ok?).to be false
|
255
|
+
end
|
256
|
+
|
257
|
+
it "#not_processed? should return false" do
|
258
|
+
expect(subject.last_remote_call.not_processed?).to be false
|
259
|
+
end
|
260
|
+
|
261
|
+
it "#client_error? should return false" do
|
262
|
+
expect(subject.last_remote_call.client_error?).to be false
|
263
|
+
end
|
264
|
+
|
265
|
+
it "#server_error? should return true" do
|
266
|
+
expect(subject.last_remote_call.server_error?).to be true
|
267
|
+
end
|
268
|
+
|
269
|
+
it "#error? should return true" do
|
270
|
+
expect(subject.last_remote_call.error?).to be true
|
271
|
+
end
|
272
|
+
|
273
|
+
it "#not_found? should return false" do
|
274
|
+
expect(subject.last_remote_call.not_found?).to be false
|
275
|
+
end
|
276
|
+
|
277
|
+
it "#timeout? should return true" do
|
278
|
+
expect(subject.last_remote_call.timeout?).to be true
|
279
|
+
end
|
280
|
+
|
281
|
+
it "#connection_failed? should return false" do
|
282
|
+
expect(subject.last_remote_call.connection_failed?).to be false
|
283
|
+
end
|
284
|
+
|
285
|
+
it "#status should return nil" do
|
286
|
+
expect(subject.last_remote_call.status).to be nil
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe "#parsed_response" do
|
291
|
+
context "when the server response's body does not contains valid json data" do
|
292
|
+
let(:remote_call) { User::Base.find('bad_json') }
|
293
|
+
|
294
|
+
it "should return nil" do
|
295
|
+
expect(remote_call.data).to be nil
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe "#http_status" do
|
301
|
+
context "when a server connection is established" do
|
302
|
+
before { subject.save(nil, { status: 422 }) }
|
303
|
+
|
304
|
+
it "it should return the server's http response code" do
|
305
|
+
expect(subject.last_remote_call.http_status).to be 422
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
context "when a server connection fails" do
|
310
|
+
subject { User::TimeoutConnection.new }
|
311
|
+
|
312
|
+
before { subject.save('/timeout') }
|
313
|
+
|
314
|
+
it "should return 0" do
|
315
|
+
expect(subject.last_remote_call.http_status).to be 0
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SmoothOperator::Serialization do
|
4
|
+
|
5
|
+
describe "#attributes" do
|
6
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
7
|
+
|
8
|
+
context "when there are changes to nested objects" do
|
9
|
+
before { subject.address.street = 'new street' }
|
10
|
+
|
11
|
+
it "should refect those changes" do
|
12
|
+
new_attributes = attributes_for(:user_with_address_and_posts)
|
13
|
+
new_attributes[:address][:street] = 'new street'
|
14
|
+
|
15
|
+
expect(subject.attributes).to eq(new_attributes)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#to_hash" do
|
21
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
22
|
+
|
23
|
+
it 'it should call #serializable_hash with the same arguments' do
|
24
|
+
options = { option1: 'option1', option2: 'option2' }
|
25
|
+
|
26
|
+
expect(subject).to receive(:serializable_hash).with(options)
|
27
|
+
|
28
|
+
subject.to_hash(options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#to_json" do
|
33
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
34
|
+
|
35
|
+
it 'it should call #serializable_hash with the same arguments' do
|
36
|
+
options = { option1: 'option1', option2: 'option2' }
|
37
|
+
|
38
|
+
expect(subject).to receive(:serializable_hash).with(options)
|
39
|
+
|
40
|
+
subject.to_json(options)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#serializable_hash" do
|
45
|
+
subject { UserWithAddressAndPosts::Son.new(attributes_for(:user_with_address_and_posts)) }
|
46
|
+
|
47
|
+
context "when no options are given" do
|
48
|
+
it 'it should return all attributes' do
|
49
|
+
expect(subject.serializable_hash).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(:user_with_address_and_posts)))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "when option 'only' is introduced" do
|
54
|
+
let(:options_with_only) { { only: [:id, :first_name] } }
|
55
|
+
|
56
|
+
it 'it should only return the filtered options' do
|
57
|
+
expect(subject.serializable_hash(options_with_only)).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(:white_list)))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "when option 'except' is introduced" do
|
62
|
+
let(:options_with_except) { { except: [:last_name, :admin] } }
|
63
|
+
|
64
|
+
it 'it should return all fields except for the filtered options' do
|
65
|
+
expect(subject.serializable_hash(options_with_except)).not_to include(attributes_for(:black_list))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when option 'methods' is introduced" do
|
70
|
+
let(:options_with_method) { { methods: :my_method } }
|
71
|
+
subject(:user_with_my_method) { UserWithAddressAndPosts::UserWithMyMethod.new(attributes_for(:user_with_address_and_posts)) }
|
72
|
+
|
73
|
+
it 'it should return all fields including the expected method and its returning value' do
|
74
|
+
expect(user_with_my_method.serializable_hash(options_with_method)).to eq(SmoothOperator::Helpers.stringify_keys(attributes_for(:user_with_my_method)))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe SmoothOperator::Validations do
|
4
|
+
subject { User::Base.new(attributes_for(:user)) }
|
5
|
+
|
6
|
+
describe "#valid?" do
|
7
|
+
context "when executing a persistence method, and the server response has a hash with the key 'errors'" do
|
8
|
+
before { subject.save('send_error') }
|
9
|
+
|
10
|
+
it "it should return false" do
|
11
|
+
expect(subject.valid?).to be false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "when executing a persistence method, and the server response does NOT have a hash with the key 'errors'" do
|
16
|
+
before { subject.save }
|
17
|
+
|
18
|
+
it "it should return true" do
|
19
|
+
expect(subject.valid?).to be true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#invalid?" do
|
25
|
+
context "when executing a persistence method, and the server response has a hash with the key 'errors'" do
|
26
|
+
before { subject.save('send_error') }
|
27
|
+
|
28
|
+
it "it should return true" do
|
29
|
+
expect(subject.invalid?).to be true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when executing a persistence method, and the server response does NOT have a hash with the key 'errors'" do
|
34
|
+
before { subject.save }
|
35
|
+
|
36
|
+
it "it should return false" do
|
37
|
+
expect(subject.invalid?).to be false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
SimpleCov.start do
|
4
|
+
root('lib/')
|
5
|
+
project_name('SmoothOperator')
|
6
|
+
coverage_dir('../tmp/coverage/')
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'require_helper'
|
10
|
+
|
11
|
+
FactoryGirl.find_definitions
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
config.include FactoryGirl::Syntax::Methods
|
16
|
+
|
17
|
+
config.include PersistenceHelper, helpers: :persistence
|
18
|
+
|
19
|
+
config.expect_with :rspec do |c|
|
20
|
+
c.syntax = :expect
|
21
|
+
end
|
22
|
+
|
23
|
+
LocalhostServer.new(TestServer.new, 4567)
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module PersistenceHelper
|
2
|
+
|
3
|
+
def subject_class
|
4
|
+
UserWithAddressAndPosts::Son
|
5
|
+
end
|
6
|
+
|
7
|
+
def new_user
|
8
|
+
attributes = attributes_for(:user_with_address_and_posts)
|
9
|
+
attributes.delete(:id)
|
10
|
+
|
11
|
+
subject_class.new attributes
|
12
|
+
end
|
13
|
+
|
14
|
+
def existing_user
|
15
|
+
subject_class.new(attributes_for(:user_with_address_and_posts))
|
16
|
+
end
|
17
|
+
|
18
|
+
def existing_user_with_patch
|
19
|
+
UserWithAddressAndPosts::WithPatch.new(attributes_for(:user_with_address_and_posts))
|
20
|
+
end
|
21
|
+
|
22
|
+
def created_subject
|
23
|
+
@created_subject
|
24
|
+
end
|
25
|
+
|
26
|
+
def execute_method
|
27
|
+
if method_to_execute.to_s =~ /create/
|
28
|
+
attributes = attributes_for(:user_with_address_and_posts)
|
29
|
+
|
30
|
+
attributes.delete(:id) if method_to_execute == :create_without_id
|
31
|
+
|
32
|
+
@created_subject = subject_class.create(attributes, *method_arguments)
|
33
|
+
else
|
34
|
+
subject.send(method_to_execute, *method_arguments)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# THIS FILE CODE BELONGS TO "typhoeus gem"
|
2
|
+
# https://github.com/typhoeus/typhoeus/blob/master/spec/support/localhost_server.rb
|
3
|
+
|
4
|
+
require 'rack'
|
5
|
+
require 'rack/handler/webrick'
|
6
|
+
require 'net/http'
|
7
|
+
|
8
|
+
# The code for this is inspired by Capybara's server:
|
9
|
+
# http://github.com/jnicklas/capybara/blob/0.3.9/lib/capybara/server.rb
|
10
|
+
class LocalhostServer
|
11
|
+
READY_MESSAGE = "Server ready"
|
12
|
+
|
13
|
+
class Identify
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
if env["PATH_INFO"] == "/__identify__"
|
20
|
+
[200, {}, [LocalhostServer::READY_MESSAGE]]
|
21
|
+
else
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
attr_reader :port
|
28
|
+
|
29
|
+
def initialize(rack_app, port = nil)
|
30
|
+
@port = port || find_available_port
|
31
|
+
@rack_app = rack_app
|
32
|
+
concurrently { boot }
|
33
|
+
wait_until(10, "Boot failed.") { booted? }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def find_available_port
|
39
|
+
server = TCPServer.new('127.0.0.1', 0)
|
40
|
+
server.addr[1]
|
41
|
+
ensure
|
42
|
+
server.close if server
|
43
|
+
end
|
44
|
+
|
45
|
+
def boot
|
46
|
+
# Use WEBrick since it's part of the ruby standard library and is available on all ruby interpreters.
|
47
|
+
options = { :Port => port }
|
48
|
+
options.merge!(:AccessLog => [], :Logger => WEBrick::BasicLog.new(StringIO.new)) unless ENV['VERBOSE_SERVER']
|
49
|
+
Rack::Handler::WEBrick.run(Identify.new(@rack_app), options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def booted?
|
53
|
+
res = ::Net::HTTP.get_response("localhost", '/__identify__', port)
|
54
|
+
if res.is_a?(::Net::HTTPSuccess) or res.is_a?(::Net::HTTPRedirection)
|
55
|
+
return res.body == READY_MESSAGE
|
56
|
+
end
|
57
|
+
rescue Errno::ECONNREFUSED, Errno::EBADF
|
58
|
+
return false
|
59
|
+
end
|
60
|
+
|
61
|
+
def concurrently
|
62
|
+
if should_use_subprocess?
|
63
|
+
pid = Process.fork do
|
64
|
+
trap(:INT) { ::Rack::Handler::WEBrick.shutdown }
|
65
|
+
yield
|
66
|
+
exit # manually exit; otherwise this sub-process will re-run the specs that haven't run yet.
|
67
|
+
end
|
68
|
+
|
69
|
+
at_exit do
|
70
|
+
Process.kill('INT', pid)
|
71
|
+
begin
|
72
|
+
Process.wait(pid)
|
73
|
+
rescue Errno::ECHILD
|
74
|
+
# ignore this error...I think it means the child process has already exited.
|
75
|
+
end
|
76
|
+
end
|
77
|
+
else
|
78
|
+
Thread.new { yield }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def should_use_subprocess?
|
83
|
+
# !ENV['THREADED']
|
84
|
+
false
|
85
|
+
end
|
86
|
+
|
87
|
+
def wait_until(timeout, error_message, &block)
|
88
|
+
start_time = Time.now
|
89
|
+
|
90
|
+
while true
|
91
|
+
return if yield
|
92
|
+
raise TimeoutError.new(error_message) if (Time.now - start_time) > timeout
|
93
|
+
sleep(0.05)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Address < SmoothOperator::Base
|
2
|
+
|
3
|
+
self.dirty_attributes
|
4
|
+
|
5
|
+
self.resource_name = ''
|
6
|
+
|
7
|
+
self.endpoint_user = 'admin'
|
8
|
+
self.endpoint_pass = 'admin'
|
9
|
+
|
10
|
+
self.endpoint = 'http://localhost:4567/'
|
11
|
+
|
12
|
+
self.headers = { "X-APPTOKEN" => "joaquim_app_token", "X-LAYERTOKEN" => "joaquim_layer_token" }
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module User
|
2
|
+
|
3
|
+
class Base < SmoothOperator::Base
|
4
|
+
|
5
|
+
self.resource_name = 'user'
|
6
|
+
|
7
|
+
self.endpoint_user = 'admin'
|
8
|
+
|
9
|
+
self.endpoint_pass = 'admin'
|
10
|
+
|
11
|
+
self.endpoint = 'http://localhost:4567/'
|
12
|
+
|
13
|
+
def self.query_string(params)
|
14
|
+
params['query_string_param'] = true
|
15
|
+
|
16
|
+
params
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
module UnknownHashClass
|
22
|
+
|
23
|
+
class OpenStructBase < User::Base
|
24
|
+
self.unknown_hash_class = SmoothOperator::OpenStruct::Base
|
25
|
+
end
|
26
|
+
|
27
|
+
class None < User::Base
|
28
|
+
self.unknown_hash_class = :none
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class BrokenConnection < SmoothOperator::Base
|
34
|
+
self.endpoint = 'http://localhost:1234/'
|
35
|
+
end
|
36
|
+
|
37
|
+
class TimeoutConnection < Base
|
38
|
+
self.timeout = 1
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|