Skip to content

Commit

Permalink
Migrate tests from rspec -> sus.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Sep 11, 2023
1 parent f9450cb commit 579778e
Show file tree
Hide file tree
Showing 15 changed files with 332 additions and 387 deletions.
113 changes: 113 additions & 0 deletions fixtures/sus/fixtures/async/http/body/a_writable_body.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# frozen_string_literal: true

# Released under the MIT License.
# Copyright, 2023, by Samuel Williams.

require 'protocol/http/body/deflate'
require 'sus/fixtures'

module Sus::Fixtures
module Async
module HTTP
module Body
AWritableBody = Sus::Shared("a writable body") do
it "can write and read data" do
3.times do |i|
body.write("Hello World #{i}")
expect(body.read).to be == "Hello World #{i}"
end
end

it "can buffer data in order" do
3.times do |i|
body.write("Hello World #{i}")
end

3.times do |i|
expect(body.read).to be == "Hello World #{i}"
end
end

with '#join' do
it "can join chunks" do
3.times do |i|
body.write("#{i}")
end

body.close

expect(body.join).to be == "012"
end
end

with '#each' do
it "can read all data in order" do
3.times do |i|
body.write("Hello World #{i}")
end

body.close

3.times do |i|
chunk = body.read
expect(chunk).to be == "Hello World #{i}"
end
end

it "can propagate failures" do
reactor.async do
expect do
body.each do |chunk|
raise RuntimeError.new("It was too big!")
end
end.to raise_exception(RuntimeError, message: be =~ /big/)
end

expect{
body.write("Beep boop") # This will cause a failure.
::Async::Task.current.yield
body.write("Beep boop") # This will fail.
}.to raise_exception(RuntimeError, message: be =~ /big/)
end

it "can propagate failures in nested bodies" do
nested = Protocol::HTTP::Body::Deflate.for(body)

reactor.async do
expect do
nested.each do |chunk|
raise RuntimeError.new("It was too big!")
end
end.to raise_exception(RuntimeError, message: be =~ /big/)
end

expect{
body.write("Beep boop") # This will cause a failure.
::Async::Task.current.yield
body.write("Beep boop") # This will fail.
}.to raise_exception(RuntimeError, message: be =~ /big/)
end

it "will stop after finishing" do
output_task = reactor.async do
body.each do |chunk|
expect(chunk).to be == "Hello World!"
end
end

body.write("Hello World!")
body.close

expect(body).not.to be(:empty?)

::Async::Task.current.yield

expect(output_task).to be(:finished?)
expect(body).to be(:empty?)
end
end
end
end
end
end
end
2 changes: 2 additions & 0 deletions gems.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
gem "covered"
gem "sus"
gem "sus-fixtures-async"
gem "sus-fixtures-async-http", "~> 0.5"
gem "sus-fixtures-openssl"

gem "bake"
gem "bake-test"
Expand Down
54 changes: 26 additions & 28 deletions test/async/http/body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,15 @@

require 'async/http/body'

require 'async/http/server'
require 'async/http/client'
require 'async/http/endpoint'

require 'async/io/ssl_socket'

require_relative 'server_context'

require 'sus/fixtures/async'
require 'sus/fixtures/openssl'
require 'sus/fixtures/async/http'
require 'localhost/authority'

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

context 'with echo server' do
let(:server) do
Async::HTTP::Server.for(@bound_endpoint, protocol: described_class) do |request|
ABody = Sus::Shared("a body") do
with 'echo server' do
let(:app) do
Protocol::HTTP::Middleware.for do |request|
input = request.body
output = Async::HTTP::Body::Writable.new

Expand All @@ -46,16 +39,16 @@

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

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

context "with streaming server" do
with "streaming server" do
let(:notification) {Async::Notification.new}

let(:server) do
Async::HTTP::Server.for(@bound_endpoint, protocol: described_class) do |request|
let(:app) do
Protocol::HTTP::Middleware.for do |request|
body = Async::HTTP::Body::Writable.new

Async::Task.current.async do |task|
Expand All @@ -74,7 +67,7 @@
it "can stream response" do
response = client.get("/")

expect(response).to be_success
expect(response).to be(:success?)

j = 0
# This validates interleaving
Expand All @@ -88,23 +81,28 @@
end
end

RSpec.describe Async::HTTP::Protocol::HTTP1 do
include_context Async::HTTP::Server
describe Async::HTTP::Protocol::HTTP1 do
include Sus::Fixtures::Async::HTTP::ServerContext

it_should_behave_like Async::HTTP::Body
it_behaves_like ABody
end

RSpec.describe Async::HTTP::Protocol::HTTPS do
include_context Async::HTTP::Server
describe Async::HTTP::Protocol::HTTPS do
include Sus::Fixtures::Async::HTTP::ServerContext
include Sus::Fixtures::OpenSSL::ValidCertificateContext

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: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)}
def make_server_endpoint(bound_endpoint)
Async::IO::SSLEndpoint.new(super, ssl_context: server_context)
end

def make_client_endpoint(bound_endpoint)
Async::IO::SSLEndpoint.new(super, ssl_context: client_context)
end

it_should_behave_like Async::HTTP::Body
it_behaves_like ABody
end
36 changes: 19 additions & 17 deletions test/async/http/body/hijack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,44 @@

require 'async/http/body/hijack'

RSpec.describe Async::HTTP::Body::Hijack do
include_context Async::RSpec::Reactor
require 'sus/fixtures/async'

describe Async::HTTP::Body::Hijack do
include Sus::Fixtures::Async::ReactorContext

let(:body) do
subject.wrap do |stream|
3.times do
stream.write(content)
end
stream.close
end
end

let(:content) {"Hello World!"}

describe '#call' do
with '#call' do
let(:stream) {Async::HTTP::Body::Writable.new}

subject do
described_class.wrap do |stream|
3.times do
stream.write(content)
end
stream.close
end
end

it "should generate body using direct invocation" do
subject.call(stream)
body.call(stream)

3.times do
expect(stream.read).to be == content
end

expect(stream.read).to be_nil
expect(stream).to be_empty
expect(stream).to be(:empty?)
end

it "should generate body using stream" do
3.times do
expect(subject.read).to be == content
expect(body.read).to be == content
end

expect(subject.read).to be_nil
expect(body.read).to be_nil

expect(subject).to be_empty
expect(body).to be(:empty?)
end
end
end
63 changes: 33 additions & 30 deletions test/async/http/body/pipe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@
require 'async/http/body/pipe'
require 'async/http/body/writable'

RSpec.describe Async::HTTP::Body::Pipe do
let(:input) { Async::HTTP::Body::Writable.new }
let(:pipe) { described_class.new(input) }
require 'sus/fixtures/async'

describe Async::HTTP::Body::Pipe do
let(:input) {Async::HTTP::Body::Writable.new}
let(:pipe) {subject.new(input)}

let(:data) { 'Hello World!' }
let(:data) {'Hello World!'}

describe '#to_io' do
include_context Async::RSpec::Reactor
with '#to_io' do
include Sus::Fixtures::Async::ReactorContext

let(:input_write_duration) {0}
let(:io) { pipe.to_io }

before do
Async::Task.current.async do |task| # input writer task
def before
super

# input writer task
Async do |task|
first, second = data.split(' ')
input.write("#{first} ")
task.sleep(input_write_duration) if input_write_duration > 0
Expand All @@ -29,38 +35,35 @@
end
end

after { io.close }

shared_examples :returns_io_socket do
it 'returns an io socket' do
expect(io).to be_a(Async::IO::Socket)
expect(io.read).to eq data
end
def aftrer
io.close

super
end

context 'when reading blocks' do
let(:input_write_duration) { 0.01 }

include_examples :returns_io_socket
it "returns an io socket" do
expect(io).to be_a(Async::IO::Socket)
expect(io.read).to be == data
end

context 'when reading does not block' do
let(:input_write_duration) { 0 }
with 'blocking reads' do
let(:input_write_duration) {0.01}

include_examples :returns_io_socket
it 'returns an io socket' do
expect(io.read).to be == data
end
end
end

describe 'going out of reactor scope' do
context 'when pipe is closed' do
it 'finishes' do
Async { pipe.close }
end
with 'reactor going out of scope' do
it 'finishes' do
# ensures pipe background tasks are transient
Async{pipe}
end

context 'when pipe is not closed' do
it 'finishes' do # ensures pipe background tasks are transient
Async { pipe }
with 'closed pipe' do
it 'finishes' do
Async{pipe.close}
end
end
end
Expand Down
Loading

0 comments on commit 579778e

Please sign in to comment.