8000 100% coverage. · zarqman/async-websocket@475f300 · GitHub
[go: up one dir, main page]

Skip to content

Commit 475f300

Browse files
committed
100% coverage.
1 parent fb81e83 commit 475f300

File tree

10 files changed

+113
-30
lines changed

10 files changed

+113
-30
lines changed

lib/async/websocket/client.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ def connect(authority, path, headers: nil, handler: Connection, extensions: ::Pr
103103
response = request.call(connection)
104104

105105
unless response.stream?
106+
response.close
107+
106108
raise ProtocolError, "Failed to negotiate connection: #{response.status}"
107109
end
108110

lib/async/websocket/connect_request.rb

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ class ConnectRequest < ::Protocol::HTTP::Request
2020
class Wrapper
2121
def initialize(stream, response)
2222
@response = response
23-
@body = @response.body
2423
@stream = stream
2524
end
2625

27-
attr_accessor :response
26+
def close
27+
@response.close
28+
end
2829

29-
attr_accessor :body
30+
attr_accessor :response
3031
attr_accessor :stream
3132

3233
def stream?
@@ -40,14 +41,6 @@ def status
4041
def headers
4142
@response.headers
4243
end
43-
44-
def body?
45-
true
46-
end
47-
48-
def protocol
49-
@response.protocol
50-
end
5144
end
5245

5346
class Hijack < Protocol::HTTP::Body::Readable

lib/async/websocket/error.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,11 @@ module Async
99
module WebSocket
1010
class ProtocolError < ::Protocol::WebSocket::ProtocolError
1111
end
12+
13+
class Error < ::Protocol::WebSocket::Error
14+
end
15+
16+
class UnsupportedVersionError < Error
17+
end
1218
end
1319
end

lib/async/websocket/request.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
require_relative 'connect_request'
77
require_relative 'upgrade_request'
8+
require_relative 'error'
89

910
module Async
1011
module WebSocket
@@ -26,6 +27,10 @@ def initialize(scheme = nil, authority = nil, path = nil, headers = nil, **optio
2627
@body = nil
2728
end
2829

30+
def protocol
31+
PROTOCOL
32+
end
33+
2934
attr_accessor :scheme
3035
attr_accessor :authority
3136
attr_accessor :path
@@ -41,15 +46,16 @@ def call(connection)
4146
return ConnectRequest.new(self, **@options).call(connection)
4247
end
4348

44-
raise HTTP::Error, "Unsupported HTTP version: #{connection.version}!"
49+
raise UnsupportedVersionError, "Unsupported HTTP version: #{connection.version}!"
4550
end
4651

4752
def idempotent?
4853
true
4954
end
5055

5156
def to_s
52-
"\#<#{self.class} #{@scheme}://#{@authority}: #{@path}>"
57+
uri = "#{@scheme}://#{@authority}#{@path}"
58+
"\#<#{self.class} uri=#{uri.inspect}>"
5359
end
5460
end
5561
end

lib/async/websocket/response.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def self.for(request, headers = nil, **options, &body)
1919
return ConnectResponse.new(request, headers, **options, &body)
2020
end
2121

22-
raise ProtocolError, "Unsupported HTTP version: #{request.version}!"
22+
raise UnsupportedVersionError, "Unsupported HTTP version: #{request.version}!"
2323
end
2424
end
2525
end

lib/async/websocket/upgrade_request.rb

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ def initialize(response)
2525
@stream = nil
2626
end
2727

28+
def close
29+
@response.close
30+
end
31+
2832
attr_accessor :response
2933

3034
def stream?
@@ -39,18 +43,6 @@ def headers
3943
@response.headers
4044
end
4145

42-
def body?
43-
false
44-
end
45-
46-
def body
47-
nil
48-
end
49-
50-
def protocol
51-
@response.protocol
52-
end
53-
5446
def stream
5547
@stream ||= @response.hijack!
5648
end

test/async/websocket/client.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1+
# frozen_string_literal: true
12

3+
# Released under the MIT License.
4+
# Copyright, 2023, by Samuel Williams.
5+
6+
require 'async/websocket/client'
7+
8+
require 'sus/fixtures/async/http/server_context'
29

310
ClientExamples = Sus::Shared("a websocket client") do
411
let(:app) do
@@ -24,6 +31,20 @@
2431
expect(task.children).to be(:empty?)
2532
end.wait
2633
end
34+
35+
with 'missing support for websockets' do
36+
let(:app) do
37+
Protocol::HTTP::Middleware.for do |request|
38+
Protocol::HTTP::Response[404, {}, []]
39+
end
40+
end
41+
42+
it "raises an error when the server doesn't support websockets" do
43+
expect do
44+
Async::WebSocket::Client.connect(client_endpoint) {}
45+
end.to raise_exception(Async::WebSocket::ProtocolError, message: be =~ /Failed to negotiate connection/)
46+
end
47+
end
2748
end
2849

2950
describe Async::WebSocket::Client do

test/async/websocket/request.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2022, by Samuel Williams.
5+
6+
require 'async/websocket/request'
7+
8+
describe Async::WebSocket::Request do
9+
let(:request) {subject.new("https", "localhost", "/")}
10+
let(:connection) {Async::WebSocket::Connection.new(nil)}
11+
12+
it "can detect websocket requests" do
13+
expect(subject).to be(:websocket?, request)
14+
end
15+
16+
it "should be idempotent" do
17+
expect(request).to be(:idempotent?)
18+
end
19+
20+
it "fails if the version is not supported" do
21+
expect(connection).to receive(:http1?).and_return(false)
22+
expect(connection).to receive(:http2?).and_return(false)
23+
expect(connection).to receive(:version).and_return("frob/2.0")
24+
25+
expect do
26+
request.call(connection)
27+
end.to raise_exception(Async::WebSocket::UnsupportedVersionError, message: be =~ /Unsupported HTTP version/)
28+
end
29+
30+
with '#to_s' do
31+
it "should generate string representation" do
32+
expect(request.to_s).to be =~ %r{https://localhost/}
33+
end
34+
end
35+
end

test/async/websocket/response.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111

1212
expect do
1313
subject.for(request)
14-
end.to raise_exception(Async::WebSocket::ProtocolError, message: be =~ /Unsupported HTTP version/)
14+
end.to raise_exception(Async::WebSocket::UnsupportedVersionError, message: be =~ /Unsupported HTTP version/)
1515
end
1616
end

test/async/websocket/server.rb

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
require 'sus/fixtures/async/http/server_context'
1414

1515
ServerExamples = Sus::Shared('a websocket server') do
16-
let(:websocket_client) {Async::WebSocket::Client.open(client_endpoint)}
17-
1816
it "can establish connection" do
1917
connection = websocket_client.connect(endpoint.authority, "/server")
2018

@@ -102,6 +100,8 @@
102100
describe Async::WebSocket::Server do
103101
include Sus::Fixtures::Async::HTTP::ServerContext
104102

103+
let(:websocket_client) {Async::WebSocket::Client.open(client_endpoint)}
104+
105105
let(:app) do
106106
Protocol::HTTP::Middleware.for do |request|
107107
Async::WebSocket::Adapters::HTTP.open(request) do |connection|
@@ -114,7 +114,7 @@
114114

115115
with 'http/1' do
116116
let(:protocol) {Async::HTTP::Protocol::HTTP1}
117-
it_behaves_like ServerExamples
117+
it_behaves_like ServerExamples
118118

119119
it "fails with bad request if missing nounce" do
120120
request = Protocol::HTTP::Request["GET", "/", {
@@ -126,6 +126,34 @@
126126

127127
expect(response).to be(:bad_request?)
128128
end
129+
130+
let(:timeout) {nil}
131+
132+
with 'broken server' do
133+
let(:app) do
134+
Protocol::HTTP::Middleware.for do |request|
135+
response = Async::WebSocket::Adapters::HTTP.open(request) do |connection|
136+
while message = connection.read
137+
connection.write(message)
138+
end
139+
end
140+
141+
if response
142+
response.tap do
143+
response.headers.set('sec-websocket-accept', '2badsheep')
144+
end
145+
else
146+
Protocol::HTTP::Response[404, {}, []]
147+
end
148+
end
149+
end
150+
151+
it "fails with protocol error if nounce doesn't match" do
152+
expect do
153+
websocket_client.connect(endpoint.authority, "/server") {}
154+
end.to raise_exception(Protocol::WebSocket::ProtocolError)
155+
end
156+
end
129157
end
130158

131159
with 'http/2' do

0 commit comments

Comments
 (0)
0