From dd8a5f66aa4644eeccdd9f317442d2f4a745f80f Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Jan 2020 20:30:56 +1300 Subject: [PATCH 1/5] Enable support for `rspec --next-failure`. --- spec/spec_helper.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 269958695e..2c63c57269 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -25,6 +25,9 @@ config.filter_run_when_matching :focus config.before(:each) { Grape::Util::InheritableSetting.reset_global! } + + # Enable flags like --only-failures and --next-failure + config.example_status_persistence_file_path = ".rspec_status" end require 'coveralls' From 3f99242c1b2252e3bbec52689b890b22e830a3d0 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Jan 2020 20:31:09 +1300 Subject: [PATCH 2/5] Ensure the response is an array. --- lib/grape/middleware/base.rb | 2 +- spec/grape/api_spec.rb | 6 +++--- spec/grape/endpoint_spec.rb | 2 +- spec/grape/integration/rack_spec.rb | 2 +- spec/grape/middleware/formatter_spec.rb | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/grape/middleware/base.rb b/lib/grape/middleware/base.rb index bc96feebf3..f3b18a92d3 100644 --- a/lib/grape/middleware/base.rb +++ b/lib/grape/middleware/base.rb @@ -25,7 +25,7 @@ def default_options end def call(env) - dup.call!(env) + dup.call!(env).to_a end def call!(env) diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index b506ac0eee..22d2050aa7 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -1903,9 +1903,9 @@ def foo it 'avoids polluting global namespace' do env = Rack::MockRequest.env_for('/') - expect(a.call(env)[2].body).to eq(['foo']) - expect(b.call(env)[2].body).to eq(['bar']) - expect(a.call(env)[2].body).to eq(['foo']) + expect(a.call(env)[2]).to eq(['foo']) + expect(b.call(env)[2]).to eq(['bar']) + expect(a.call(env)[2]).to eq(['foo']) end end diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 13bc92a898..26faf22934 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -151,7 +151,7 @@ def app it 'includes headers passed as symbols' do env = Rack::MockRequest.env_for('/headers') env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols' - body = subject.call(env)[2].body.first + body = subject.call(env)[2].first expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols') end end diff --git a/spec/grape/integration/rack_spec.rb b/spec/grape/integration/rack_spec.rb index cc339ddec1..c66e0f2639 100644 --- a/spec/grape/integration/rack_spec.rb +++ b/spec/grape/integration/rack_spec.rb @@ -21,7 +21,7 @@ } env = Rack::MockRequest.env_for('/', options) - expect(JSON.parse(app.call(env)[2].body.first)['params_keys']).to match_array('test') + expect(JSON.parse(app.call(env)[2].first)['params_keys']).to match_array('test') ensure input.close input.unlink diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb index e26ba43f54..41ef3d4dff 100644 --- a/spec/grape/middleware/formatter_spec.rb +++ b/spec/grape/middleware/formatter_spec.rb @@ -196,19 +196,19 @@ def to_xml subject.options[:content_types][:custom] = "don't care" subject.options[:formatters][:custom] = ->(_obj, _env) { 'CUSTOM FORMAT' } _, _, body = subject.call('PATH_INFO' => '/info.custom') - expect(body.body).to eq(['CUSTOM FORMAT']) + expect(body).to eq(['CUSTOM FORMAT']) end context 'default' do let(:body) { ['blah'] } it 'uses default json formatter' do _, _, body = subject.call('PATH_INFO' => '/info.json') - expect(body.body).to eq(['["blah"]']) + expect(body).to eq(['["blah"]']) end end it 'uses custom json formatter' do subject.options[:formatters][:json] = ->(_obj, _env) { 'CUSTOM JSON FORMAT' } _, _, body = subject.call('PATH_INFO' => '/info.json') - expect(body.body).to eq(['CUSTOM JSON FORMAT']) + expect(body).to eq(['CUSTOM JSON FORMAT']) end end @@ -384,7 +384,7 @@ def to_xml it 'returns Grape::Uril::SendFileReponse' do env = { 'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json' } - expect(subject.call(env)).to be_a(Grape::ServeFile::SendfileResponse) + expect(subject.call(env)).to be_a(Array) end end @@ -407,7 +407,7 @@ def self.call(_, _) it 'returns response by invalid formatter' do env = { 'PATH_INFO' => '/hello.invalid', 'HTTP_ACCEPT' => 'application/x-invalid' } _, _, bodies = *subject.call(env) - expect(bodies.body.first).to eq({ message: 'invalid' }.to_json) + expect(bodies.first).to eq({ message: 'invalid' }.to_json) end end From 6a447bb94d22dac2edb10b3265af84912cf2e407 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Jan 2020 22:15:32 +1300 Subject: [PATCH 3/5] Fix specs and test on rack ~> 1.0 and rack ~> 2.0.0. --- .travis.yml | 4 ++++ gemfiles/rack1.gemfile | 4 ++++ gemfiles/rack2-0.gemfile | 4 ++++ spec/grape/middleware/formatter_spec.rb | 12 ++++++++---- 4 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 gemfiles/rack1.gemfile create mode 100644 gemfiles/rack2-0.gemfile diff --git a/.travis.yml b/.travis.yml index ac4a84eb53..491fe4464e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,6 +13,10 @@ matrix: - bundle exec danger - rvm: 2.7.0 gemfile: Gemfile + - rvm: 2.7.0 + gemfile: gemfiles/rack1.gemfile + - rvm: 2.7.0 + gemfile: gemfiles/rack2-0.gemfile - rvm: 2.7.0 gemfile: gemfiles/rack_edge.gemfile - rvm: 2.7.0 diff --git a/gemfiles/rack1.gemfile b/gemfiles/rack1.gemfile new file mode 100644 index 0000000000..c25fcb2eff --- /dev/null +++ b/gemfiles/rack1.gemfile @@ -0,0 +1,4 @@ + +eval_gemfile("../Gemfile") + +gem 'rack', '~> 1.0' diff --git a/gemfiles/rack2-0.gemfile b/gemfiles/rack2-0.gemfile new file mode 100644 index 0000000000..c25fcb2eff --- /dev/null +++ b/gemfiles/rack2-0.gemfile @@ -0,0 +1,4 @@ + +eval_gemfile("../Gemfile") + +gem 'rack', '~> 1.0' diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb index 41ef3d4dff..fb0a17b09b 100644 --- a/spec/grape/middleware/formatter_spec.rb +++ b/spec/grape/middleware/formatter_spec.rb @@ -379,12 +379,16 @@ def to_xml end context 'send file' do - let(:body) { Grape::ServeFile::FileResponse.new('file') } - let(:app) { ->(_env) { [200, {}, body] } } + let(:file) {double(File)} + let(:file_body) { Grape::ServeFile::FileResponse.new(file) } + let(:app) { ->(_env) { [200, {}, file_body] } } - it 'returns Grape::Uril::SendFileReponse' do + it 'returns a file response' do env = { 'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json' } - expect(subject.call(env)).to be_a(Array) + status, headers, body = subject.call(env) + expect(status).to be == 200 + expect(headers).to be == {"Content-Type"=>"application/json"} + expect(body).to be file end end From 9cbb48c42afc44727b71ae3efd3251fdd01f7ac8 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Jan 2020 22:29:03 +1300 Subject: [PATCH 4/5] Oh RuboCop... --- gemfiles/rack1.gemfile | 3 ++- gemfiles/rack2-0.gemfile | 3 ++- spec/grape/middleware/formatter_spec.rb | 4 ++-- spec/spec_helper.rb | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/gemfiles/rack1.gemfile b/gemfiles/rack1.gemfile index c25fcb2eff..362af946f9 100644 --- a/gemfiles/rack1.gemfile +++ b/gemfiles/rack1.gemfile @@ -1,4 +1,5 @@ +# frozen_string_literal: true -eval_gemfile("../Gemfile") +eval_gemfile('../Gemfile') gem 'rack', '~> 1.0' diff --git a/gemfiles/rack2-0.gemfile b/gemfiles/rack2-0.gemfile index c25fcb2eff..362af946f9 100644 --- a/gemfiles/rack2-0.gemfile +++ b/gemfiles/rack2-0.gemfile @@ -1,4 +1,5 @@ +# frozen_string_literal: true -eval_gemfile("../Gemfile") +eval_gemfile('../Gemfile') gem 'rack', '~> 1.0' diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb index fb0a17b09b..ae4519c925 100644 --- a/spec/grape/middleware/formatter_spec.rb +++ b/spec/grape/middleware/formatter_spec.rb @@ -379,7 +379,7 @@ def to_xml end context 'send file' do - let(:file) {double(File)} + let(:file) { double(File) } let(:file_body) { Grape::ServeFile::FileResponse.new(file) } let(:app) { ->(_env) { [200, {}, file_body] } } @@ -387,7 +387,7 @@ def to_xml env = { 'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json' } status, headers, body = subject.call(env) expect(status).to be == 200 - expect(headers).to be == {"Content-Type"=>"application/json"} + expect(headers).to be == { 'Content-Type' => 'application/json' } expect(body).to be file end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 2c63c57269..7745de7dc4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -27,7 +27,7 @@ config.before(:each) { Grape::Util::InheritableSetting.reset_global! } # Enable flags like --only-failures and --next-failure - config.example_status_persistence_file_path = ".rspec_status" + config.example_status_persistence_file_path = '.rspec_status' end require 'coveralls' From 5dd9913412bc19607c4dcfebc16d7f62b621c353 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 8 Jan 2020 23:16:01 +1300 Subject: [PATCH 5/5] Correctly read chunks of the response body according to the Rack SPEC. --- spec/grape/api_spec.rb | 6 +++--- spec/grape/endpoint_spec.rb | 2 +- spec/grape/integration/rack_spec.rb | 2 +- spec/grape/middleware/formatter_spec.rb | 13 +++++++------ spec/spec_helper.rb | 10 ++++++++++ 5 files changed, 22 insertions(+), 11 deletions(-) diff --git a/spec/grape/api_spec.rb b/spec/grape/api_spec.rb index 22d2050aa7..a199e33d05 100644 --- a/spec/grape/api_spec.rb +++ b/spec/grape/api_spec.rb @@ -1903,9 +1903,9 @@ def foo it 'avoids polluting global namespace' do env = Rack::MockRequest.env_for('/') - expect(a.call(env)[2]).to eq(['foo']) - expect(b.call(env)[2]).to eq(['bar']) - expect(a.call(env)[2]).to eq(['foo']) + expect(read_chunks(a.call(env)[2])).to eq(['foo']) + expect(read_chunks(b.call(env)[2])).to eq(['bar']) + expect(read_chunks(a.call(env)[2])).to eq(['foo']) end end diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 26faf22934..37aea84bc4 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -151,7 +151,7 @@ def app it 'includes headers passed as symbols' do env = Rack::MockRequest.env_for('/headers') env['HTTP_SYMBOL_HEADER'.to_sym] = 'Goliath passes symbols' - body = subject.call(env)[2].first + body = read_chunks(subject.call(env)[2]).join expect(JSON.parse(body)['Symbol-Header']).to eq('Goliath passes symbols') end end diff --git a/spec/grape/integration/rack_spec.rb b/spec/grape/integration/rack_spec.rb index c66e0f2639..e1c46762f9 100644 --- a/spec/grape/integration/rack_spec.rb +++ b/spec/grape/integration/rack_spec.rb @@ -21,7 +21,7 @@ } env = Rack::MockRequest.env_for('/', options) - expect(JSON.parse(app.call(env)[2].first)['params_keys']).to match_array('test') + expect(JSON.parse(read_chunks(app.call(env)[2]).join)['params_keys']).to match_array('test') ensure input.close input.unlink diff --git a/spec/grape/middleware/formatter_spec.rb b/spec/grape/middleware/formatter_spec.rb index ae4519c925..102bca8f15 100644 --- a/spec/grape/middleware/formatter_spec.rb +++ b/spec/grape/middleware/formatter_spec.rb @@ -196,19 +196,19 @@ def to_xml subject.options[:content_types][:custom] = "don't care" subject.options[:formatters][:custom] = ->(_obj, _env) { 'CUSTOM FORMAT' } _, _, body = subject.call('PATH_INFO' => '/info.custom') - expect(body).to eq(['CUSTOM FORMAT']) + expect(read_chunks(body)).to eq(['CUSTOM FORMAT']) end context 'default' do let(:body) { ['blah'] } it 'uses default json formatter' do _, _, body = subject.call('PATH_INFO' => '/info.json') - expect(body).to eq(['["blah"]']) + expect(read_chunks(body)).to eq(['["blah"]']) end end it 'uses custom json formatter' do subject.options[:formatters][:json] = ->(_obj, _env) { 'CUSTOM JSON FORMAT' } _, _, body = subject.call('PATH_INFO' => '/info.json') - expect(body).to eq(['CUSTOM JSON FORMAT']) + expect(read_chunks(body)).to eq(['CUSTOM JSON FORMAT']) end end @@ -384,11 +384,12 @@ def to_xml let(:app) { ->(_env) { [200, {}, file_body] } } it 'returns a file response' do + expect(file).to receive(:each).and_yield('data') env = { 'PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json' } status, headers, body = subject.call(env) expect(status).to be == 200 expect(headers).to be == { 'Content-Type' => 'application/json' } - expect(body).to be file + expect(read_chunks(body)).to be == ['data'] end end @@ -410,8 +411,8 @@ def self.call(_, _) it 'returns response by invalid formatter' do env = { 'PATH_INFO' => '/hello.invalid', 'HTTP_ACCEPT' => 'application/x-invalid' } - _, _, bodies = *subject.call(env) - expect(bodies.first).to eq({ message: 'invalid' }.to_json) + _, _, body = *subject.call(env) + expect(read_chunks(body).join).to eq({ message: 'invalid' }.to_json) end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 7745de7dc4..fa4f8bf00f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,7 +18,17 @@ # so it should be set to true here as well to reflect that. I18n.enforce_available_locales = true +module Chunks + def read_chunks(body) + buffer = [] + body.each { |chunk| buffer << chunk } + + buffer + end +end + RSpec.configure do |config| + config.include Chunks config.include Rack::Test::Methods config.include Spec::Support::Helpers config.raise_errors_for_deprecations!