praxis 2.0.pre.38 → 2.0.pre.40

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2f139dbbe5f48ceddf013eb18a84dc43fcdf41af033b19a40f565f8606b961f
4
- data.tar.gz: 69b0200fd2ead2d713af52b7a0c56ca60a19bc4cb118ff0284017e7f1d19cda2
3
+ metadata.gz: 19745c4d9f6ebe88d95a2118df3b7a41343a2076b2a17d051793fed535575b9d
4
+ data.tar.gz: af9eb1d60cf4367f0ceb0e7aadc589b7f7d862fa161815ccc05c46eaa08f8881
5
5
  SHA512:
6
- metadata.gz: cdcaed25ce9a8735f76a77e8f805432579eb4afa8893d0abf39b8054cd09053dc9a0103c1ea64d2330baa4280dc9d8b9a522022afce009c90814f367e3295920
7
- data.tar.gz: 6a146584703308be70f70a54e3ebb53b10ff038578a5851e333cad95392729576e133c5079a85052487f3af023c831888e7cc2a8dd075b93b7aa8c7c30b5dc24
6
+ metadata.gz: 4a0a13bfeb6d1fd4512483fd4d341e1f606f1b391d0eda220019b5032f2593be4e79bd7061d375de2b97630eecd19feffa89db594d7c553c11163084b6bb00e1
7
+ data.tar.gz: e0ef5e1cc96d638496ef60f0ae4aaf82ccc2cecbf49cae5794642525283e201bfb600b4f02f4a85d1cd7b16988e6dc05a5a08162c7d9f894906017beba271de3
data/CHANGELOG.md CHANGED
@@ -1,8 +1,16 @@
1
1
  # Praxis Changelog
2
2
 
3
+ ## 2.0.pre40
4
+
5
+ - Prevent IRB from running console in a new Thread (#405)
6
+
7
+ ## 2.0.pre.39
8
+
9
+ - Revert JSON handler back to `json` gem, as `oj` was too unstable when used with ActiveSupport.
10
+
3
11
  ## 2.0.pre.38
4
12
 
5
- - Stoped calling ::Oj.mimic_JSON in Praxis::Handlers::JSON. It breaks ActiveSupport::JSON's html escaping when called.
13
+ - Stopped calling ::Oj.mimic_JSON in Praxis::Handlers::JSON. It breaks ActiveSupport::JSON's html escaping when called.
6
14
 
7
15
  ## 2.0.pre.37
8
16
 
@@ -0,0 +1,3 @@
1
+ /.bundle
2
+ /vendor
3
+ w
@@ -11,7 +11,6 @@ gem 'sequel', '~> 5'
11
11
  group :test do
12
12
  gem 'builder'
13
13
  gem 'link_header'
14
- gem 'oj'
15
14
  gem 'parslet'
16
15
  end
17
16
 
@@ -4,14 +4,16 @@
4
4
 
5
5
  source 'https://rubygems.org'
6
6
 
7
- gem 'activerecord', '>=7'
7
+ # TODO: figure out incompatibility between ActiveRecord 7.1 and SQLite
8
+ # @see https://github.com/praxis/praxis/pull/405#issuecomment-1780570599
9
+ # Until then, we're pinned to 7.0.x for purposes of testing.
10
+ gem 'activerecord', '~> 7.0.8'
8
11
  gem 'rubocop'
9
12
  gem 'sequel', '~> 5'
10
13
 
11
14
  group :test do
12
15
  gem 'builder'
13
16
  gem 'link_header'
14
- gem 'oj'
15
17
  gem 'parslet'
16
18
  end
17
19
 
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  module Praxis
4
2
  module Handlers
5
3
  class JSON
@@ -7,11 +5,11 @@ module Praxis
7
5
  #
8
6
  # @raise [Praxis::Exceptions::InvalidConfiguration] if the handler is unsupported
9
7
  def initialize
10
- require 'oj'
8
+ require 'json'
11
9
  rescue LoadError
12
10
  # Should never happen since JSON is a default gem; might as well be cautious!
13
11
  raise Praxis::Exceptions::InvalidConfiguration,
14
- 'JSON handler depends on oj ~> 3; please add it to your Gemfile'
12
+ "JSON handler depends on json ~> 1.0; please add it to your Gemfile"
15
13
  end
16
14
 
17
15
  # Parse a JSON document into structured data.
@@ -20,9 +18,8 @@ module Praxis
20
18
  # @return [Hash,Array] the structured-data representation of the document
21
19
  def parse(document)
22
20
  # Try to be nice and accept an empty string as an empty payload (seems nice to do for dumb http clients)
23
- return nil if document.nil? || document == ''
24
-
25
- ::Oj.load(document)
21
+ return nil if (document.nil? || document == '')
22
+ ::JSON.parse(document)
26
23
  end
27
24
 
28
25
  # Generate a pretty-printed JSON document from structured data.
@@ -30,7 +27,7 @@ module Praxis
30
27
  # @param [Hash,Array] structured_data
31
28
  # @return [String]
32
29
  def generate(structured_data)
33
- ::Oj.dump(structured_data, indent: 2)
30
+ ::JSON.pretty_generate(structured_data)
34
31
  end
35
32
  end
36
33
  end
@@ -5,38 +5,35 @@ namespace :praxis do
5
5
  task :console do
6
6
  # Use irb if available (which it almost always is).
7
7
  require 'irb'
8
+ # Ensure that we save history just like normal IRB
9
+ require 'irb/ext/save-history'
8
10
 
9
11
  Rake::Task['praxis:environment'].invoke
10
12
 
13
+ basedir = ::Praxis::Application.instance.root
14
+ nickname = File.basename(basedir)
15
+
11
16
  # Keep IRB.setup from complaining about bad ARGV options
12
17
  old_argv = ARGV.dup
13
18
  ARGV.clear
14
- IRB.setup nil
19
+ IRB.setup(basedir)
15
20
  ARGV.concat(old_argv)
16
21
 
17
- # Ensure that multi-irb has a context to work with (and, indirectly an instance of IRB::Irb).
18
- IRB.conf[:MAIN_CONTEXT] = IRB::Irb.new.context
19
-
20
- # Allow reentrant IRB
21
- require 'irb/ext/multi-irb'
22
-
23
- # Ensure that we save history just like normal IRB
24
- require 'irb/ext/save-history'
25
-
26
22
  # Remove main object from prompt (its stringify is not useful)
27
- nickname = File.basename(::Praxis::Application.instance.root)
28
23
  IRB.conf[:PROMPT][:DEFAULT] = {
29
24
  PROMPT_I: "%N(#{nickname}):%03n:%i> ",
30
25
  PROMPT_N: "%N(#{nickname}):%03n:%i> ",
31
26
  PROMPT_S: "%N(#{nickname}):%03n:%i%l ",
32
27
  PROMPT_C: "%N(#{nickname}):%03n:%i* ",
33
28
  }
34
-
35
29
  # Disable inefficient, distracting autocomplete
36
30
  IRB.conf[:USE_AUTOCOMPLETE] = false
37
31
 
38
- # Invoke the REPL, then cleanly shut down
39
- IRB.irb(nil, Praxis::Application.instance)
32
+ # Invoke the REPL, setting the workspace binding to the application object.
33
+ IRB::Irb.new(IRB::WorkSpace.new(::Praxis::Application.instance)).run(
34
+ IRB.conf,
35
+ )
36
+ # Cleanly shut down to ensure we save history
40
37
  IRB.irb_at_exit
41
38
  end
42
39
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Praxis
4
- VERSION = '2.0.pre.38'
4
+ VERSION = '2.0.pre.40'
5
5
  end
@@ -12,30 +12,39 @@ describe 'Functional specs' do
12
12
  context 'index' do
13
13
  context 'with a valid request' do
14
14
  it 'is successful' do
15
- get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session
15
+ get '/api/clouds/1/instances?api_version=1.0',
16
+ nil,
17
+ 'global_session' => session
16
18
  expect(last_response.headers['Content-Type']).to(
17
- eq('application/vnd.acme.instance;type=collection')
19
+ eq('application/vnd.acme.instance;type=collection'),
18
20
  )
19
21
  end
20
22
  end
21
23
 
22
24
  context 'with a path param that can not load' do
23
25
  it 'returns a useful error' do
24
- get '/api/clouds/invalid/instances?api_version=1.0', nil, 'global_session' => session
26
+ get '/api/clouds/invalid/instances?api_version=1.0',
27
+ nil,
28
+ 'global_session' => session
25
29
 
26
30
  expect(last_response.status).to eq 400
27
31
 
28
32
  response = JSON.parse(last_response.body)
29
33
  expect(response['name']).to eq 'ValidationError'
30
34
  expect(response['summary']).to eq 'Error loading params.'
31
- expect(response['errors']).to match_array([/Error loading attribute \$\.params\.cloud_id/])
35
+ expect(response['errors']).to match_array(
36
+ [/Error loading attribute \$\.params\.cloud_id/],
37
+ )
32
38
  expect(response['cause']['name']).to eq 'ArgumentError'
33
39
  end
34
40
  end
35
41
 
36
42
  context 'with a header that can not load' do
37
43
  it 'returns a useful error' do
38
- get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session, 'HTTP_ACCOUNT_ID' => 'invalid'
44
+ get '/api/clouds/1/instances?api_version=1.0',
45
+ nil,
46
+ 'global_session' => session,
47
+ 'HTTP_ACCOUNT_ID' => 'invalid'
39
48
 
40
49
  expect(last_response.status).to eq 400
41
50
 
@@ -43,14 +52,18 @@ describe 'Functional specs' do
43
52
 
44
53
  expect(response['name']).to eq 'ValidationError'
45
54
  expect(response['summary']).to eq 'Error loading headers.'
46
- expect(response['errors']).to match_array([/Error loading attribute .*Account-Id"/])
55
+ expect(response['errors']).to match_array(
56
+ [/Error loading attribute .*Account-Id"/],
57
+ )
47
58
  expect(response['cause']['name']).to eq 'ArgumentError'
48
59
  end
49
60
  end
50
61
 
51
62
  context 'with a param that is invalid' do
52
63
  it 'returns a useful error' do
53
- get '/api/clouds/-1/instances?api_version=1.0', nil, 'global_session' => session
64
+ get '/api/clouds/-1/instances?api_version=1.0',
65
+ nil,
66
+ 'global_session' => session
54
67
 
55
68
  expect(last_response.status).to eq 400
56
69
 
@@ -58,13 +71,18 @@ describe 'Functional specs' do
58
71
 
59
72
  expect(response['name']).to eq 'ValidationError'
60
73
  expect(response['summary']).to eq 'Error validating request data.'
61
- expect(response['errors']).to match_array([/.*cloud_id.*is smaller than the allowed min/])
74
+ expect(response['errors']).to match_array(
75
+ [/.*cloud_id.*is smaller than the allowed min/],
76
+ )
62
77
  end
63
78
  end
64
79
 
65
80
  context 'with a header that is invalid' do
66
81
  it 'returns a useful error' do
67
- get '/api/clouds/1/instances?api_version=1.0', nil, 'global_session' => session, 'HTTP_ACCOUNT_ID' => '-1'
82
+ get '/api/clouds/1/instances?api_version=1.0',
83
+ nil,
84
+ 'global_session' => session,
85
+ 'HTTP_ACCOUNT_ID' => '-1'
68
86
 
69
87
  expect(last_response.status).to eq 400
70
88
 
@@ -72,7 +90,9 @@ describe 'Functional specs' do
72
90
 
73
91
  expect(response['name']).to eq 'ValidationError'
74
92
  expect(response['summary']).to eq 'Error validating request data.'
75
- expect(response['errors']).to match_array([/.*headers.*Account-Id.*is smaller than the allowed min/])
93
+ expect(response['errors']).to match_array(
94
+ [/.*headers.*Account-Id.*is smaller than the allowed min/],
95
+ )
76
96
  end
77
97
  end
78
98
 
@@ -87,7 +107,10 @@ describe 'Functional specs' do
87
107
  end
88
108
 
89
109
  it 'fails to validate the response' do
90
- get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0', nil, 'HTTP_FOO' => 'bar', 'global_session' => session
110
+ get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0',
111
+ nil,
112
+ 'HTTP_FOO' => 'bar',
113
+ 'global_session' => session
91
114
  expect(last_response.status).to eq(500)
92
115
  response = JSON.parse(last_response.body)
93
116
 
@@ -97,16 +120,22 @@ describe 'Functional specs' do
97
120
  end
98
121
 
99
122
  context 'with response validation disabled' do
100
- let(:praxis_config) { double('praxis_config', validate_responses: false) }
123
+ let(:praxis_config) do
124
+ double('praxis_config', validate_responses: false)
125
+ end
101
126
  let(:config) { double('config', praxis: praxis_config) }
102
127
 
103
128
  before do
104
- expect(Praxis::Application.instance.config).to receive(:praxis).and_return(praxis_config)
129
+ expect(Praxis::Application.instance.config).to receive(
130
+ :praxis,
131
+ ).and_return(praxis_config)
105
132
  end
106
133
 
107
134
  it 'does not validate the response and succeeds' do
108
135
  expect do
109
- get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0', nil, 'global_session' => session
136
+ get '/api/clouds/1/instances?response_content_type=somejunk&api_version=1.0',
137
+ nil,
138
+ 'global_session' => session
110
139
  end.to_not raise_error
111
140
  end
112
141
  end
@@ -114,10 +143,14 @@ describe 'Functional specs' do
114
143
  context 'with a valid request but misusing request content-type' do
115
144
  it 'is still successful and does not get confused about the sister post action' do
116
145
  the_body = StringIO.new('') # This is a GET request passing a body
117
- get '/api/clouds/1/instances?api_version=1.0', nil, 'rack.input' => the_body, 'CONTENT_TYPE' => 'application/json', 'global_session' => session
146
+ get '/api/clouds/1/instances?api_version=1.0',
147
+ nil,
148
+ 'rack.input' => the_body,
149
+ 'CONTENT_TYPE' => 'application/json',
150
+ 'global_session' => session
118
151
  expect(last_response.status).to eq(200)
119
152
  expect(last_response.headers['Content-Type']).to(
120
- eq('application/vnd.acme.instance;type=collection')
153
+ eq('application/vnd.acme.instance;type=collection'),
121
154
  )
122
155
  end
123
156
  end
@@ -126,30 +159,40 @@ describe 'Functional specs' do
126
159
  context 'index using POST sister action' do
127
160
  context 'with a valid request' do
128
161
  it 'is successful and round trips the content type we pass in the body' do
129
- payload = { response_content_type: 'application/vnd.acme.instance; type=collection; other=thing' }
130
- post '/api/clouds/1/instances/actions/index_using_post?api_version=1.0', JSON.dump(payload), 'CONTENT_TYPE' => 'application/json', 'global_session' => session
162
+ payload = {
163
+ response_content_type:
164
+ 'application/vnd.acme.instance; type=collection; other=thing',
165
+ }
166
+ post '/api/clouds/1/instances/actions/index_using_post?api_version=1.0',
167
+ JSON.dump(payload),
168
+ 'CONTENT_TYPE' => 'application/json',
169
+ 'global_session' => session
131
170
  expect(last_response.status).to eq(200)
132
171
  expect(last_response.headers['Content-Type']).to(
133
- eq(payload[:response_content_type])
172
+ eq(payload[:response_content_type]),
134
173
  )
135
174
  end
136
175
  end
137
176
  end
138
177
  it 'works' do
139
178
  the_body = StringIO.new('{}') # This is a funny, GET request expecting a body
140
- get '/api/clouds/1/instances/2?junk=foo&api_version=1.0', nil, 'rack.input' => the_body, 'CONTENT_TYPE' => 'application/json', 'global_session' => session
179
+ get '/api/clouds/1/instances/2?junk=foo&api_version=1.0',
180
+ nil,
181
+ 'rack.input' => the_body,
182
+ 'CONTENT_TYPE' => 'application/json',
183
+ 'global_session' => session
141
184
  expect(last_response.status).to eq(200)
142
185
  expected = {
143
186
  'cloud_id' => 1,
144
187
  'id' => 2,
145
188
  'junk' => 'foo',
146
189
  'other_params' => {
147
- 'some_date' => '2012-12-21T00:00:00.000+00:00',
148
- 'fail_filter' => false
190
+ 'some_date' => '2012-12-21T00:00:00+00:00',
191
+ 'fail_filter' => false,
149
192
  },
150
193
  'payload' => {
151
- 'optional' => 'not given'
152
- }
194
+ 'optional' => 'not given',
195
+ },
153
196
  }
154
197
 
155
198
  expect(JSON.parse(last_response.body)).to eq(expected)
@@ -160,13 +203,17 @@ describe 'Functional specs' do
160
203
  end
161
204
 
162
205
  it 'returns early when making the before filter break' do
163
- get '/api/clouds/1/instances/2?junk=foo&api_version=1.0&fail_filter=true', nil, 'global_session' => session
206
+ get '/api/clouds/1/instances/2?junk=foo&api_version=1.0&fail_filter=true',
207
+ nil,
208
+ 'global_session' => session
164
209
  expect(last_response.status).to eq(401)
165
210
  end
166
211
 
167
212
  context 'bulk_create multipart' do
168
213
  let(:instance) { Instance.example }
169
- let(:instance_json) { JSON.pretty_generate(instance.render(fields: { id: true, name: true })) }
214
+ let(:instance_json) do
215
+ JSON.pretty_generate(instance.render(fields: { id: true, name: true }))
216
+ end
170
217
 
171
218
  let(:form) do
172
219
  form_data = MIME::Multipart::FormData.new
@@ -179,9 +226,13 @@ describe 'Functional specs' do
179
226
  let(:body) { form.body.to_s }
180
227
 
181
228
  it 'works' do
182
- post '/api/clouds/1/instances?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
229
+ post '/api/clouds/1/instances?api_version=1.0',
230
+ body,
231
+ 'CONTENT_TYPE' => content_type,
232
+ 'global_session' => session
183
233
 
184
- _reponse_preamble, response = Praxis::MultipartParser.parse(last_response.headers, last_response.body)
234
+ _reponse_preamble, response =
235
+ Praxis::MultipartParser.parse(last_response.headers, last_response.body)
185
236
  expect(response).to have(1).item
186
237
 
187
238
  instance_part = response.first
@@ -194,7 +245,9 @@ describe 'Functional specs' do
194
245
 
195
246
  response_instance = JSON.parse(instance_part.body)
196
247
  expect(response_instance['key']).to eq(instance.id)
197
- expect(response_instance['value'].values).to eq(instance.render(fields: { id: true, name: true }).values)
248
+ expect(response_instance['value'].values).to eq(
249
+ instance.render(fields: { id: true, name: true }).values,
250
+ )
198
251
  end
199
252
  end
200
253
 
@@ -216,7 +269,10 @@ describe 'Functional specs' do
216
269
 
217
270
  context 'with a valid payload' do
218
271
  before do
219
- post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
272
+ post '/api/clouds/1/instances/2/files?api_version=1.0',
273
+ body,
274
+ 'CONTENT_TYPE' => content_type,
275
+ 'global_session' => session
220
276
  end
221
277
 
222
278
  subject(:response) { JSON.parse(last_response.body) }
@@ -244,11 +300,16 @@ describe 'Functional specs' do
244
300
  let(:body) { form.body.to_s }
245
301
 
246
302
  it 'returns an error' do
247
- post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
303
+ post '/api/clouds/1/instances/2/files?api_version=1.0',
304
+ body,
305
+ 'CONTENT_TYPE' => content_type,
306
+ 'global_session' => session
248
307
  response = JSON.parse(last_response.body)
249
308
 
250
309
  expect(response['name']).to eq('ValidationError')
251
- expect(response['errors']).to eq(['Attribute $.payload.destination_path is required'])
310
+ expect(response['errors']).to eq(
311
+ ['Attribute $.payload.destination_path is required'],
312
+ )
252
313
  end
253
314
  end
254
315
 
@@ -273,9 +334,14 @@ describe 'Functional specs' do
273
334
  subject(:response) { JSON.parse(last_response.body) }
274
335
 
275
336
  before do
276
- post '/api/clouds/1/instances/2/files?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
337
+ post '/api/clouds/1/instances/2/files?api_version=1.0',
338
+ body,
339
+ 'CONTENT_TYPE' => content_type,
340
+ 'global_session' => session
341
+ end
342
+ its(:keys) do
343
+ should eq(%w[destination_path name filename type contents options])
277
344
  end
278
- its(:keys) { should eq(%w[destination_path name filename type contents options]) }
279
345
  its(['options']) { should eq({ 'extra_thing' => 'I am extra' }) }
280
346
  end
281
347
  end
@@ -283,11 +349,15 @@ describe 'Functional specs' do
283
349
  context 'not found and API versions' do
284
350
  context 'when no version is specified' do
285
351
  it 'it tells you which available api versions would match' do
286
- get '/api/clouds/1/instances/2?junk=foo', nil, 'global_session' => session
352
+ get '/api/clouds/1/instances/2?junk=foo',
353
+ nil,
354
+ 'global_session' => session
287
355
 
288
356
  expect(last_response.status).to eq(404)
289
357
  expect(last_response.headers['Content-Type']).to eq('text/plain')
290
- expect(last_response.body).to eq('NotFound. Your request did not specify an API version. Available versions = "1.0".')
358
+ expect(last_response.body).to eq(
359
+ 'NotFound. Your request did not specify an API version. Available versions = "1.0".',
360
+ )
291
361
  end
292
362
  it 'it just gives you a simple not found when nothing would have matched' do
293
363
  get '/foobar?junk=foo', nil, 'global_session' => session
@@ -300,43 +370,58 @@ describe 'Functional specs' do
300
370
 
301
371
  context 'when some version is specified, but wrong' do
302
372
  it 'it tells you which possible correcte api versions exist' do
303
- get '/api/clouds/1/instances/2?junk=foo&api_version=50.0', nil, 'global_session' => session
373
+ get '/api/clouds/1/instances/2?junk=foo&api_version=50.0',
374
+ nil,
375
+ 'global_session' => session
304
376
 
305
377
  expect(last_response.status).to eq(404)
306
378
  expect(last_response.headers['Content-Type']).to eq('text/plain')
307
- expect(last_response.body).to eq('NotFound. Your request specified API version = "50.0". Available versions = "1.0".')
379
+ expect(last_response.body).to eq(
380
+ 'NotFound. Your request specified API version = "50.0". Available versions = "1.0".',
381
+ )
308
382
  end
309
383
  end
310
384
  end
311
385
 
312
386
  context 'volumes' do
313
- before do
314
- header 'X-Api-Version', '1.0'
315
- end
387
+ before { header 'X-Api-Version', '1.0' }
316
388
 
317
389
  context 'when no authorization header is passed' do
318
390
  it 'works as expected' do
319
- get '/api/clouds/1/volumes/123?junk=stuff', nil, 'global_session' => session
391
+ get '/api/clouds/1/volumes/123?junk=stuff',
392
+ nil,
393
+ 'global_session' => session
320
394
  expect(last_response.status).to eq(200)
321
395
  expect(Volume.load(last_response.body).validate).to be_empty
322
- expect(last_response.headers['Content-Type']).to eq('application/vnd.acme.volume')
396
+ expect(last_response.headers['Content-Type']).to eq(
397
+ 'application/vnd.acme.volume',
398
+ )
323
399
  end
324
400
  end
325
401
  context 'when an authorization header is passed' do
326
402
  it 'returns 401 when it does not match "secret" ' do
327
- get '/api/clouds/1/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'foobar', 'global_session' => session
403
+ get '/api/clouds/1/volumes/123?junk=stuff',
404
+ nil,
405
+ 'HTTP_AUTHORIZATION' => 'foobar',
406
+ 'global_session' => session
328
407
  expect(last_response.status).to eq(401)
329
408
  expect(last_response.body).to match(/Authentication info is invalid/)
330
409
  end
331
410
  it 'succeeds as expected when it matches "secret" ' do
332
- get '/api/clouds/1/volumes/123?junk=stuff', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
411
+ get '/api/clouds/1/volumes/123?junk=stuff',
412
+ nil,
413
+ 'HTTP_AUTHORIZATION' => 'the secret',
414
+ 'global_session' => session
333
415
  expect(last_response.status).to eq(200)
334
416
  end
335
417
  end
336
418
 
337
419
  context 'index action with no args defined' do
338
420
  it 'dispatches successfully' do
339
- get '/api/clouds/1/volumes', nil, 'HTTP_AUTHORIZATION' => 'the secret', 'global_session' => session
421
+ get '/api/clouds/1/volumes',
422
+ nil,
423
+ 'HTTP_AUTHORIZATION' => 'the secret',
424
+ 'global_session' => session
340
425
  expect(last_response.status).to eq(200)
341
426
  end
342
427
  end
@@ -345,22 +430,32 @@ describe 'Functional specs' do
345
430
  context 'wildcard verb routing' do
346
431
  let(:content_type) { 'application/json' }
347
432
  it 'can terminate instances with POST' do
348
- post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'CONTENT_TYPE' => content_type, 'global_session' => session
433
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0',
434
+ nil,
435
+ 'CONTENT_TYPE' => content_type,
436
+ 'global_session' => session
349
437
  expect(last_response.status).to eq(200)
350
438
  end
351
439
  it 'can terminate instances with DELETE' do
352
- post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'CONTENT_TYPE' => content_type, 'global_session' => session
440
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0',
441
+ nil,
442
+ 'CONTENT_TYPE' => content_type,
443
+ 'global_session' => session
353
444
  expect(last_response.status).to eq(200)
354
445
  end
355
446
  end
356
447
 
357
448
  context 'route options' do
358
449
  it 'reach the endpoint that does not match the except clause' do
359
- get '/api/clouds/23/otherinstances/_action/test?api_version=1.0', nil, 'global_session' => session
450
+ get '/api/clouds/23/otherinstances/_action/test?api_version=1.0',
451
+ nil,
452
+ 'global_session' => session
360
453
  expect(last_response.status).to eq(200)
361
454
  end
362
455
  it 'does NOT reach the endpoint that matches the except clause' do
363
- get '/api/clouds/23/otherinstances/_action/exceptional?api_version=1.0', nil, 'global_session' => session
456
+ get '/api/clouds/23/otherinstances/_action/exceptional?api_version=1.0',
457
+ nil,
458
+ 'global_session' => session
364
459
  expect(last_response.status).to eq(404)
365
460
  end
366
461
  end
@@ -369,12 +464,17 @@ describe 'Functional specs' do
369
464
  let(:content_type) { 'application/json' }
370
465
 
371
466
  it 'can terminate' do
372
- post '/api/clouds/23/instances/1/terminate?api_version=1.0', nil, 'global_session' => session, 'CONTENT_TYPE' => content_type
467
+ post '/api/clouds/23/instances/1/terminate?api_version=1.0',
468
+ nil,
469
+ 'global_session' => session,
470
+ 'CONTENT_TYPE' => content_type
373
471
  expect(last_response.status).to eq(200)
374
472
  end
375
473
 
376
474
  it 'can not stop' do
377
- post '/api/clouds/23/instances/1/stop?api_version=1.0', '', 'global_session' => session
475
+ post '/api/clouds/23/instances/1/stop?api_version=1.0',
476
+ '',
477
+ 'global_session' => session
378
478
  expect(last_response.status).to eq(403)
379
479
  end
380
480
  end
@@ -384,13 +484,18 @@ describe 'Functional specs' do
384
484
  let(:content_type) { 'application/json' }
385
485
 
386
486
  before do
387
- post '/api/clouds/1/instances/2/terminate?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
487
+ post '/api/clouds/1/instances/2/terminate?api_version=1.0',
488
+ body,
489
+ 'CONTENT_TYPE' => content_type,
490
+ 'global_session' => session
388
491
  end
389
492
 
390
493
  it 'returns a useful error message' do
391
494
  body = JSON.parse(last_response.body)
392
495
  expect(body['name']).to eq('ValidationError')
393
- expect(body['summary']).to match("Error loading payload. Used Content-Type: 'application/json'")
496
+ expect(body['summary']).to match(
497
+ "Error loading payload. Used Content-Type: 'application/json'",
498
+ )
394
499
  expect(body['errors']).to_not be_empty
395
500
  end
396
501
  end
@@ -400,7 +505,10 @@ describe 'Functional specs' do
400
505
  let(:content_type) { 'application/json' }
401
506
 
402
507
  before do
403
- patch '/api/clouds/1/instances/3?api_version=1.0', body, 'CONTENT_TYPE' => content_type, 'global_session' => session
508
+ patch '/api/clouds/1/instances/3?api_version=1.0',
509
+ body,
510
+ 'CONTENT_TYPE' => content_type,
511
+ 'global_session' => session
404
512
  end
405
513
 
406
514
  subject(:response_body) { JSON.parse(last_response.body) }
@@ -429,7 +537,11 @@ describe 'Functional specs' do
429
537
 
430
538
  its(['name']) { should eq 'ValidationError' }
431
539
  its(['summary']) { should eq 'Error validating response' }
432
- its(['errors']) { should match_array [/\$\.name value \(Invalid Name\) does not match regexp/] }
540
+ its(['errors']) do
541
+ should match_array [
542
+ /\$\.name value \(Invalid Name\) does not match regexp/,
543
+ ]
544
+ end
433
545
 
434
546
  it 'returns a validation error' do
435
547
  expect(last_response.status).to eq(500)
data/spec/spec_helper.rb CHANGED
@@ -25,17 +25,13 @@ require 'rack/test'
25
25
  require 'rspec/its'
26
26
  require 'rspec/collection_matchers'
27
27
 
28
- require 'oj'
29
28
  require 'json'
30
- Oj.mimic_JSON
31
29
 
32
30
  Dir["#{File.dirname(__FILE__)}/../lib/praxis/plugins/*.rb"].sort.each do |file|
33
31
  require file
34
32
  end
35
33
 
36
- Dir["#{File.dirname(__FILE__)}/support/*.rb"].sort.each do |file|
37
- require file
38
- end
34
+ Dir["#{File.dirname(__FILE__)}/support/*.rb"].sort.each { |file| require file }
39
35
 
40
36
  def suppress_output
41
37
  original_stdout = $stdout.clone
@@ -57,9 +53,7 @@ RSpec.configure do |config|
57
53
  end
58
54
 
59
55
  config.before(:each) do
60
- Praxis::Blueprint.cache = Hash.new do |hash, key|
61
- hash[key] = {}
62
- end
56
+ Praxis::Blueprint.cache = Hash.new { |hash, key| hash[key] = {} }
63
57
  end
64
58
 
65
59
  config.before(:all) do
@@ -4,7 +4,6 @@ source 'https://rubygems.org'
4
4
 
5
5
  gem 'activerecord'
6
6
  gem 'link_header' # For pagination extensions
7
- gem 'oj' # For fast JSON de/serialization handlers
8
7
  gem 'parslet' # For field selection extension
9
8
  gem 'praxis'
10
9
  gem 'puma' # A much better web server than the default webrick
@@ -20,4 +19,4 @@ group :development, :test do
20
19
 
21
20
  gem 'pry'
22
21
  gem 'pry-byebug'
23
- end
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: praxis
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.pre.38
4
+ version: 2.0.pre.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep M. Blanquer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-05 00:00:00.000000000 Z
12
+ date: 2023-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -387,6 +387,7 @@ files:
387
387
  - Rakefile
388
388
  - SELECTOR_NOTES.txt
389
389
  - bin/praxis
390
+ - gemfiles/.gitignore
390
391
  - gemfiles/active_6.gemfile
391
392
  - gemfiles/active_7.gemfile
392
393
  - lib/praxis.rb