Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Rails Edge ruby 3.1 #2405

Merged
merged 7 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/edge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ jobs:
fail-fast: false
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2', '3.3', ruby-head, truffleruby-head, jruby-head]
gemfile: [rails_edge, rack_edge, rack_3_0]
gemfile: [rails_edge, rack_edge]
exclude:
- ruby: '2.7'
gemfile: rails_edge
- ruby: '3.0'
gemfile: rails_edge
runs-on: ubuntu-latest
continue-on-error: true
env:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* [#2373](https://github.com/ruby-grape/grape/pull/2373): Fix markdown files for following 1-line format - [@jcagarcia](https://github.com/jcagarcia).
* [#2382](https://github.com/ruby-grape/grape/pull/2382): Fix values validator for params wrapped in `with` block - [@numbata](https://github.com/numbata).
* [#2387](https://github.com/ruby-grape/grape/pull/2387): Fix rubygems version within workflows - [@ericproulx](https://github.com/ericproulx).
* [#2405](https://github.com/ruby-grape/grape/pull/2405): Fix edge workflow - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

### 2.0.0 (2023/11/11)
Expand Down
38 changes: 19 additions & 19 deletions spec/grape/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ class DummyFormatClass
'example'
end
put '/example'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'text/plain'
expect(last_response.content_type).to eql 'text/plain'
end

describe 'adds an OPTIONS route that' do
Expand Down Expand Up @@ -1195,7 +1195,7 @@ class DummyFormatClass

it 'sets content type for txt format' do
get '/foo'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('text/plain')
expect(last_response.content_type).to eq('text/plain')
end

it 'does not set Cache-Control' do
Expand All @@ -1205,22 +1205,22 @@ class DummyFormatClass

it 'sets content type for xml' do
get '/foo.xml'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('application/xml')
expect(last_response.content_type).to eq('application/xml')
end

it 'sets content type for json' do
get '/foo.json'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('application/json')
expect(last_response.content_type).to eq('application/json')
end

it 'sets content type for serializable hash format' do
get '/foo.serializable_hash'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('application/json')
expect(last_response.content_type).to eq('application/json')
end

it 'sets content type for binary format' do
get '/foo.binary'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('application/octet-stream')
expect(last_response.content_type).to eq('application/octet-stream')
end

it 'returns raw data when content type binary' do
Expand All @@ -1229,7 +1229,7 @@ class DummyFormatClass
subject.format :binary
subject.get('/binary_file') { File.binread(image_filename) }
get '/binary_file'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('application/octet-stream')
expect(last_response.content_type).to eq('application/octet-stream')
expect(last_response.body).to eq(file)
end

Expand All @@ -1241,8 +1241,8 @@ class DummyFormatClass

subject.get('/file') { stream test_file }
get '/file'
expect(last_response.headers[Rack::CONTENT_LENGTH]).to eq('25')
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('text/plain')
expect(last_response.content_length).to eq(25)
expect(last_response.content_type).to eq('text/plain')
expect(last_response.body).to eq(file_content)
end

Expand All @@ -1252,12 +1252,12 @@ class DummyFormatClass
blk.yield ' file content'
end

subject.use Rack::Chunked
subject.use Gem::Version.new(Rack.release) < Gem::Version.new('3') ? Rack::Chunked : ChunkedResponse
subject.get('/stream') { stream test_stream }
get '/stream', {}, 'HTTP_VERSION' => 'HTTP/1.1', 'SERVER_PROTOCOL' => 'HTTP/1.1'

expect(last_response.headers[Rack::CONTENT_TYPE]).to eq('text/plain')
expect(last_response.headers[Rack::CONTENT_LENGTH]).to be_nil
expect(last_response.content_type).to eq('text/plain')
expect(last_response.content_length).to be_nil
expect(last_response.headers[Rack::CACHE_CONTROL]).to eq('no-cache')
expect(last_response.headers[Grape::Http::Headers::TRANSFER_ENCODING]).to eq('chunked')

Expand All @@ -1267,23 +1267,23 @@ class DummyFormatClass
it 'sets content type for error' do
subject.get('/error') { error!('error in plain text', 500) }
get '/error'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'text/plain'
expect(last_response.content_type).to eql 'text/plain'
end

it 'sets content type for json error' do
subject.format :json
subject.get('/error') { error!('error in json', 500) }
get '/error.json'
expect(last_response.status).to be 500
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'application/json'
expect(last_response.content_type).to eql 'application/json'
end

it 'sets content type for xml error' do
subject.format :xml
subject.get('/error') { error!('error in xml', 500) }
get '/error'
expect(last_response.status).to be 500
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'application/xml'
expect(last_response.content_type).to eql 'application/xml'
end

it 'includes extension in format' do
Expand Down Expand Up @@ -1313,12 +1313,12 @@ class DummyFormatClass

it 'sets content type' do
get '/custom.custom'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'application/custom'
expect(last_response.content_type).to eql 'application/custom'
end

it 'sets content type for error' do
get '/error.custom'
expect(last_response.headers[Rack::CONTENT_TYPE]).to eql 'application/custom'
expect(last_response.content_type).to eql 'application/custom'
end
end

Expand All @@ -1342,7 +1342,7 @@ class DummyFormatClass
image_filename = 'grape.png'
post url, file: Rack::Test::UploadedFile.new(image_filename, content_type, true)
expect(last_response.status).to eq(201)
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq(content_type)
expect(last_response.content_type).to eq(content_type)
expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''grape.png")
File.open(image_filename, 'rb') do |io|
expect(last_response.body).to eq io.read
Expand All @@ -1358,7 +1358,7 @@ class DummyFormatClass
filename = __FILE__
post '/attachment.rb', file: Rack::Test::UploadedFile.new(filename, content_type, true)
expect(last_response.status).to eq(201)
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq(content_type)
expect(last_response.content_type).to eq(content_type)
expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''api_spec.rb")
File.open(filename, 'rb') do |io|
expect(last_response.body).to eq io.read
Expand Down
8 changes: 4 additions & 4 deletions spec/grape/endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def app
end

it 'responses with given content type in headers' do
expect(last_response.headers[Rack::CONTENT_TYPE]).to eq 'application/json; charset=utf-8'
expect(last_response.content_type).to eq 'application/json; charset=utf-8'
end
end

Expand Down Expand Up @@ -650,7 +650,7 @@ def app
end
get '/hey'
expect(last_response.status).to eq 302
expect(last_response.headers['Location']).to eq '/ha'
expect(last_response.location).to eq '/ha'
expect(last_response.body).to eq 'This resource has been moved temporarily to /ha.'
end

Expand All @@ -660,7 +660,7 @@ def app
end
post '/hey', {}, 'HTTP_VERSION' => 'HTTP/1.1'
expect(last_response.status).to eq 303
expect(last_response.headers['Location']).to eq '/ha'
expect(last_response.location).to eq '/ha'
expect(last_response.body).to eq 'An alternate resource is located at /ha.'
end

Expand All @@ -670,7 +670,7 @@ def app
end
get '/hey'
expect(last_response.status).to eq 301
expect(last_response.headers['Location']).to eq '/ha'
expect(last_response.location).to eq '/ha'
expect(last_response.body).to eq 'This resource has been moved permanently to /ha.'
end

Expand Down
6 changes: 3 additions & 3 deletions spec/grape/entity_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ def initialize(args)
end
get '/example'
expect(last_response.status).to eq(200)
expect(last_response.headers['Content-type']).to eq('application/xml')
expect(last_response.content_type).to eq('application/xml')
expect(last_response.body).to eq <<~XML
<?xml version="1.0" encoding="UTF-8"?>
<hash>
Expand Down Expand Up @@ -266,7 +266,7 @@ def initialize(args)
end
get '/example'
expect(last_response.status).to eq(200)
expect(last_response.headers['Content-type']).to eq('application/json')
expect(last_response.content_type).to eq('application/json')
expect(last_response.body).to eq('{"example":{"name":"johnnyiller"}}')
end

Expand Down Expand Up @@ -298,7 +298,7 @@ def initialize(args)

get '/example?callback=abcDef'
expect(last_response.status).to eq(200)
expect(last_response.headers['Content-type']).to eq('application/javascript')
expect(last_response.content_type).to eq('application/javascript')
expect(last_response.body).to include 'abcDef({"example":{"name":"johnnyiller"}})'
end

Expand Down
4 changes: 2 additions & 2 deletions spec/grape/middleware/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
end

it 'header' do
expect(subject.response.header).to have_key(:abc)
expect(subject.response.headers).to have_key(:abc)
end

it 'returns the memoized Rack::Response instance' do
Expand All @@ -115,7 +115,7 @@
end

it 'header' do
expect(subject.response.header).to have_key(:abc)
expect(subject.response.headers).to have_key(:abc)
end

it 'returns the memoized Rack::Response instance' do
Expand Down
2 changes: 2 additions & 0 deletions spec/support/basic_auth_encode_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'base64'

module Spec
module Support
module Helpers
Expand Down
73 changes: 73 additions & 0 deletions spec/support/chunked_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# frozen_string_literal: true

# this is a copy of Rack::Chunked which has been removed in rack > 3.0

class ChunkedResponse
class Body
TERM = "\r\n"
TAIL = "0#{TERM}"

# Store the response body to be chunked.
def initialize(body)
@body = body
end

# For each element yielded by the response body, yield
# the element in chunked encoding.
def each(&block)
term = TERM
@body.each do |chunk|
size = chunk.bytesize
next if size == 0

yield [size.to_s(16), term, chunk.b, term].join
end
yield TAIL
yield_trailers(&block)
yield term
end

# Close the response body if the response body supports it.
def close
@body.close if @body.respond_to?(:close)
end

private

# Do nothing as this class does not support trailer headers.
def yield_trailers; end
end

class TrailerBody < Body
private

# Yield strings for each trailer header.
def yield_trailers
@body.trailers.each_pair do |k, v|
yield "#{k}: #{v}\r\n"
end
end
end

def initialize(app)
@app = app
end

def call(env)
status, headers, body = response = @app.call(env)

if !Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
!headers[Rack::CONTENT_LENGTH] &&
!headers[Rack::TRANSFER_ENCODING]

headers[Rack::TRANSFER_ENCODING] = 'chunked'
response[2] = if headers['trailer']
TrailerBody.new(body)
else
Body.new(body)
end
end

response
end
end