Skip to content

Update body spec to use server context. #123

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

Merged
merged 2 commits into from
Jun 5, 2023
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
4 changes: 4 additions & 0 deletions lib/async/http/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ def endpoint
@endpoint ||= build_endpoint
end

def endpoint=(endpoint)
@endpoint = build_endpoint(endpoint)
end

def bind(*arguments, &block)
endpoint.bind(*arguments, &block)
end
Expand Down
125 changes: 58 additions & 67 deletions spec/async/http/body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,109 +11,100 @@

require 'async/io/ssl_socket'

require 'async/rspec/reactor'
require_relative 'server_context'

require 'localhost/authority'

RSpec.shared_examples Async::HTTP::Body do
let(:client) {Async::HTTP::Client.new(client_endpoint, protocol: described_class)}

it "can stream requests" do
server = Async::HTTP::Server.for(server_endpoint, protocol: described_class) do |request|
input = request.body
output = Async::HTTP::Body::Writable.new

Async::Task.current.async do |task|
input.each do |chunk|
output.write(chunk.reverse)
context 'with echo server' do
let(:server) do
Async::HTTP::Server.for(@bound_endpoint, protocol: described_class) do |request|
input = request.body
output = Async::HTTP::Body::Writable.new

Async::Task.current.async do |task|
input.each do |chunk|
output.write(chunk.reverse)
end

output.close
end

Protocol::HTTP::Response[200, [], output]
end
end

it "can stream requests" do
output = Async::HTTP::Body::Writable.new

reactor.async do |task|
output.write("Hello World!")
output.close
end

Protocol::HTTP::Response[200, [], output]
end

server_task = reactor.async do
server.run
end

output = Async::HTTP::Body::Writable.new

reactor.async do |task|
output.write("Hello World!")
output.close
response = client.post("/", {}, output)

expect(response).to be_success
expect(response.read).to be == "!dlroW olleH"
end

response = client.post("/", {}, output)

expect(response).to be_success
expect(response.read).to be == "!dlroW olleH"

server_task.stop
client.close
end

it "can stream response" do
notification = Async::Notification.new
context "with streaming server" do
let(:notification) {Async::Notification.new}

server = Async::HTTP::Server.for(server_endpoint, protocol: described_class) do |request|
body = Async::HTTP::Body::Writable.new

Async::Task.current.async do |task|
10.times do |i|
body.write("#{i}")
notification.wait
let(:server) do
Async::HTTP::Server.for(@bound_endpoint, protocol: described_class) do |request|
body = Async::HTTP::Body::Writable.new

Async::Task.current.async do |task|
10.times do |i|
body.write("#{i}")
notification.wait
end

body.close
end

body.close
Protocol::HTTP::Response[200, {}, body]
end

Protocol::HTTP::Response[200, {}, body]
end

server_task = reactor.async do
server.run
end

response = client.get("/")

expect(response).to be_success

j = 0
# This validates interleaving
response.body.each do |line|
expect(line.to_i).to be == j
j += 1
it "can stream response" do
response = client.get("/")

notification.signal
end

server_task.stop
client.close
expect(response).to be_success

j = 0
# This validates interleaving
response.body.each do |line|
expect(line.to_i).to be == j
j += 1

notification.signal
end
end
end
end

RSpec.describe Async::HTTP::Protocol::HTTP1 do
include_context Async::RSpec::Reactor

let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:9296', reuse_port: true)}
let(:client_endpoint) {endpoint}
let(:server_endpoint) {endpoint}
include_context Async::HTTP::Server

it_should_behave_like Async::HTTP::Body
end

RSpec.describe Async::HTTP::Protocol::HTTPS do
include_context Async::RSpec::Reactor
include_context Async::HTTP::Server

let(:authority) {Localhost::Authority.new}

let(:server_context) {authority.server_context}
let(:client_context) {authority.client_context}

# Shared port for localhost network tests.
let(:server_endpoint) {Async::HTTP::Endpoint.parse("https://localhost:9296", ssl_context: server_context)}
let(:client_endpoint) {Async::HTTP::Endpoint.parse("https://localhost:9296", ssl_context: client_context)}
let(:server_endpoint) {Async::HTTP::Endpoint.parse("https://localhost:0", ssl_context: server_context, reuse_port: true)}
let(:client_endpoint) {Async::HTTP::Endpoint.parse("https://localhost:0", ssl_context: client_context, reuse_port: true)}

it_should_behave_like Async::HTTP::Body
end
2 changes: 1 addition & 1 deletion spec/async/http/protocol/shared_examples.rb
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@
end

context 'slow server' do
let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:9294', reuse_port: true, timeout: 0.1)}
let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:0', reuse_port: true, timeout: 0.1)}

let(:server) do
Async::HTTP::Server.for(@bound_endpoint) do |request|
Expand Down
22 changes: 17 additions & 5 deletions spec/async/http/server_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
include_context Async::RSpec::Reactor

let(:protocol) {described_class}
let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:9294', timeout: 0.8, reuse_port: true, protocol: protocol)}
let(:endpoint) {Async::HTTP::Endpoint.parse('http://127.0.0.1:0', timeout: 0.8, reuse_port: true, protocol: protocol)}

let(:server_endpoint) {endpoint}
let(:client_endpoint) {endpoint}

let(:retries) {1}

Expand All @@ -24,17 +27,26 @@

before do
# We bind the endpoint before running the server so that we know incoming connections will be accepted:
@bound_endpoint = Async::IO::SharedEndpoint.bound(endpoint)
@bound_endpoint = Async::IO::SharedEndpoint.bound(server_endpoint)

# I feel a dedicated class might be better than this hack:
allow(@bound_endpoint).to receive(:protocol).and_return(endpoint.protocol)
allow(@bound_endpoint).to receive(:scheme).and_return(endpoint.scheme)
allow(@bound_endpoint).to receive(:protocol).and_return(server_endpoint.protocol)
allow(@bound_endpoint).to receive(:scheme).and_return(server_endpoint.scheme)

@server_task = Async do
server.run
end

@client = Async::HTTP::Client.new(endpoint, protocol: endpoint.protocol, retries: retries)
local_address_endpoint = @bound_endpoint.local_address_endpoint

if timeout = client_endpoint.timeout
local_address_endpoint.each do |endpoint|
endpoint.options = {timeout: timeout}
end
end

client_endpoint.endpoint = local_address_endpoint
@client = Async::HTTP::Client.new(client_endpoint, protocol: client_endpoint.protocol, retries: retries)
end

after do
Expand Down