quicsilver 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -1
  3. data/.github/workflows/cibuildgem.yaml +93 -0
  4. data/.gitignore +3 -1
  5. data/CHANGELOG.md +32 -0
  6. data/Gemfile.lock +20 -2
  7. data/README.md +92 -29
  8. data/Rakefile +67 -2
  9. data/benchmarks/concurrent.rb +2 -2
  10. data/benchmarks/rails.rb +3 -3
  11. data/benchmarks/throughput.rb +2 -2
  12. data/examples/README.md +44 -91
  13. data/examples/benchmark.rb +111 -0
  14. data/examples/connection_pool_demo.rb +47 -0
  15. data/examples/example_helper.rb +18 -0
  16. data/examples/falcon_middleware.rb +44 -0
  17. data/examples/feature_demo.rb +125 -0
  18. data/examples/grpc_style.rb +97 -0
  19. data/examples/minimal_http3_server.rb +6 -18
  20. data/examples/priorities.rb +60 -0
  21. data/examples/protocol_http_server.rb +31 -0
  22. data/examples/rack_http3_server.rb +8 -20
  23. data/examples/rails_feature_test.rb +260 -0
  24. data/examples/simple_client_test.rb +2 -2
  25. data/examples/streaming_sse.rb +33 -0
  26. data/examples/trailers.rb +69 -0
  27. data/ext/quicsilver/extconf.rb +14 -0
  28. data/ext/quicsilver/quicsilver.c +39 -0
  29. data/lib/quicsilver/client/client.rb +138 -39
  30. data/lib/quicsilver/client/connection_pool.rb +106 -0
  31. data/lib/quicsilver/libmsquic.2.dylib +0 -0
  32. data/lib/quicsilver/protocol/adapter.rb +176 -0
  33. data/lib/quicsilver/protocol/control_stream_parser.rb +106 -0
  34. data/lib/quicsilver/protocol/frame_parser.rb +142 -0
  35. data/lib/quicsilver/protocol/frame_reader.rb +55 -0
  36. data/lib/quicsilver/protocol/frames.rb +18 -7
  37. data/lib/quicsilver/protocol/priority.rb +56 -0
  38. data/lib/quicsilver/protocol/qpack/encoder.rb +39 -1
  39. data/lib/quicsilver/protocol/qpack/header_block_decoder.rb +16 -1
  40. data/lib/quicsilver/protocol/request_parser.rb +28 -140
  41. data/lib/quicsilver/protocol/response_encoder.rb +27 -2
  42. data/lib/quicsilver/protocol/response_parser.rb +22 -130
  43. data/lib/quicsilver/protocol/stream_input.rb +98 -0
  44. data/lib/quicsilver/protocol/stream_output.rb +59 -0
  45. data/lib/quicsilver/quicsilver.bundle +0 -0
  46. data/lib/quicsilver/server/request_handler.rb +96 -44
  47. data/lib/quicsilver/server/server.rb +316 -42
  48. data/lib/quicsilver/transport/configuration.rb +10 -1
  49. data/lib/quicsilver/transport/connection.rb +92 -63
  50. data/lib/quicsilver/version.rb +1 -1
  51. data/lib/quicsilver.rb +26 -3
  52. data/quicsilver.gemspec +10 -2
  53. metadata +69 -5
  54. data/examples/setup_certs.sh +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36065332b2efe43090097b945882282ba770a6b6b5a54d16d7229bf8977dfb6e
4
- data.tar.gz: 22f94375fdaa43b465b6ff9b866985ca7dd06732ea5e0cbf98a94c7c92eb97df
3
+ metadata.gz: d4926d24fbce141791505bb14d59e543a30a6c5cbf8ca3c3fd36c9123b2941db
4
+ data.tar.gz: 45c128c6bf9fc48b8267ba2927414f8429607e8f99e4169235d12ebe26863ccc
5
5
  SHA512:
6
- metadata.gz: edcac1b797654202cf22ef471e3de5cd23a8409f0ded8d940652cb6194d14974f0c08f7118af1f76e1895dca0598ae646764687d0fabb0555317e67a3587f690
7
- data.tar.gz: a1521e2a828ba6bd394939a5c7b1034d1951f92329444f1adee5135db96df9703128b731c673c10c6309d104f238aa95589a9c9cfb581c6e050bc5ef6a261c8f
6
+ metadata.gz: ad6f92657375909bac67ce88bfa64d47c53a2dd69bb424a36f297927778389247714c092b004287cc278c5ecdf94c0f186a4c15f4fa4cfff62dbef9fcfc155f6
7
+ data.tar.gz: 1f5d2812bfb18a15b1821c8afcb18f779663ec3066495ef69dfd9a1c79f8d83f13f7c6287b8ce56be318476ea69fd6c520c1dc4298ceb807c64f6de0747b3035
@@ -22,7 +22,7 @@ jobs:
22
22
  runs-on: ubuntu-24.04
23
23
  strategy:
24
24
  matrix:
25
- ruby-version: ["3.2"]
25
+ ruby-version: ["3.4"]
26
26
 
27
27
  steps:
28
28
  - uses: actions/checkout@v4
@@ -0,0 +1,93 @@
1
+ name: "Package and release gems with precompiled binaries"
2
+ on:
3
+ workflow_dispatch:
4
+ inputs:
5
+ release:
6
+ description: "If the whole build passes on all platforms, release the gems on RubyGems.org"
7
+ required: false
8
+ type: boolean
9
+ default: false
10
+ env:
11
+ CIBUILDGEM: 1
12
+ jobs:
13
+ compile:
14
+ timeout-minutes: 20
15
+ name: "Cross compile the gem on different ruby versions"
16
+ strategy:
17
+ matrix:
18
+ os: ["macos-latest", "ubuntu-22.04"]
19
+ runs-on: "${{ matrix.os }}"
20
+ steps:
21
+ - name: "Checkout code"
22
+ uses: "actions/checkout@v5"
23
+ with:
24
+ submodules: recursive
25
+ - name: "Setup Ruby"
26
+ uses: "ruby/setup-ruby@v1"
27
+ with:
28
+ ruby-version: "3.4"
29
+ bundler-cache: true
30
+ - name: "Build MsQuic"
31
+ run: bundle exec rake build_msquic
32
+ - name: "Run cibuildgem"
33
+ uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
34
+ with:
35
+ step: "compile"
36
+ test:
37
+ timeout-minutes: 20
38
+ name: "Run the test suite"
39
+ needs: compile
40
+ strategy:
41
+ matrix:
42
+ os: ["macos-latest", "ubuntu-22.04"]
43
+ rubies: ["3.4", "4.0"]
44
+ type: ["cross", "native"]
45
+ runs-on: "${{ matrix.os }}"
46
+ steps:
47
+ - name: "Checkout code"
48
+ uses: "actions/checkout@v5"
49
+ - name: "Setup Ruby"
50
+ uses: "ruby/setup-ruby@v1"
51
+ with:
52
+ ruby-version: "${{ matrix.rubies }}"
53
+ bundler-cache: true
54
+ - name: "Run cibuildgem"
55
+ uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
56
+ with:
57
+ step: "test_${{ matrix.type }}"
58
+ install:
59
+ timeout-minutes: 5
60
+ name: "Verify the gem can be installed"
61
+ needs: test
62
+ strategy:
63
+ matrix:
64
+ os: ["macos-latest", "ubuntu-22.04"]
65
+ runs-on: "${{ matrix.os }}"
66
+ steps:
67
+ - name: "Setup Ruby"
68
+ uses: "ruby/setup-ruby@v1"
69
+ with:
70
+ ruby-version: "4.0.0"
71
+ - name: "Run cibuildgem"
72
+ uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
73
+ with:
74
+ step: "install"
75
+ release:
76
+ environment: release
77
+ permissions:
78
+ id-token: write
79
+ contents: read
80
+ timeout-minutes: 5
81
+ if: ${{ inputs.release }}
82
+ name: "Release all gems with RubyGems"
83
+ needs: install
84
+ runs-on: "ubuntu-latest"
85
+ steps:
86
+ - name: "Setup Ruby"
87
+ uses: "ruby/setup-ruby@v1"
88
+ with:
89
+ ruby-version: "4.0.0"
90
+ - name: "Run cibuildgem"
91
+ uses: "shopify/cibuildgem/.github/actions/cibuildgem@main"
92
+ with:
93
+ step: "release"
data/.gitignore CHANGED
@@ -11,4 +11,6 @@
11
11
  /certificates/*
12
12
  *.bundle
13
13
  lib/quicsilver/quicsilver.bundle
14
- *.gem
14
+ *.gem
15
+ autoresearch.*
16
+ ext/quicsilver/Makefile
data/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.4.0] - 2026-04-25
9
+
10
+ ### Added
11
+ - Client connection pool with automatic reuse (`Quicsilver::Client.get/post` class-level API)
12
+ - GREASE support (RFC 9297) — settings, frames, and unidirectional streams
13
+ - GOAWAY validation (RFC 9114 §7.2.6) — monotonically decreasing IDs, stream ID validation
14
+ - Trailer support (RFC 9114 §4.1) — parse and send trailing HEADERS frames
15
+ - Extensible Priorities (RFC 9218) — parse `priority` header, PRIORITY_UPDATE frames on control stream, MsQuic stream priority mapping
16
+ - FrameParser base class — unified frame walking, ordering, body accumulation, size limits
17
+ - FrameReader module — shared byte-level frame extraction for request/response/control streams
18
+ - Trailer wiring in Adapter and StreamOutput for protocol-http integration
19
+ - Informational 1xx responses (§4.1) — 103 Early Hints with `rack.early_hints` support for Rails
20
+ - Two-phase GOAWAY shutdown (§5.2) — server sends decreasing GOAWAY IDs during graceful shutdown
21
+ - Client processes server SETTINGS (§7.2.4) — parses peer's SETTINGS including MAX_FIELD_SECTION_SIZE
22
+ - Client processes server GOAWAY (§5.2) — tracks peer_goaway_id, blocks new requests, connection pool evicts draining connections
23
+ - MIT license in gemspec
24
+
25
+ ### Fixed
26
+ - QPACK prefix decoding — decode Required Insert Count and Delta Base as varints instead of hardcoded `offset = 2`
27
+ - Default decoder rejects payloads referencing the dynamic table
28
+ - Response parser now enforces `max_frame_payload_size` (was missing)
29
+ - Duplicate `frames` method in FrameParser
30
+ - Consistent `@headers` and `@trailers` initialization (`{}` not `nil`)
31
+ - extconf.rb — force Apple clang on macOS (Homebrew clang produces broken MsQuic binaries)
32
+
33
+ ### Changed
34
+ - RequestParser and ResponseParser inherit from FrameParser (reduced ~230 lines of duplication)
35
+ - `store_header`, `body`, `DEFAULT_DECODER`, `EMPTY_BODY`, `parse!` moved to FrameParser base class
36
+ - `@body_io` renamed to `@body` in ResponseParser for consistency
37
+ - ResponseEncoder accepts optional `trailers:` hash
38
+ - StreamOutput accepts `send_fin:` parameter for trailer support
39
+
8
40
  ## [0.3.0] - 2026-03-23
9
41
 
10
42
  ### Added
data/Gemfile.lock CHANGED
@@ -1,9 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- quicsilver (0.2.0)
4
+ quicsilver (0.4.0)
5
+ console
5
6
  localhost (~> 1.6)
6
7
  logger
8
+ protocol-http (~> 0.49)
9
+ protocol-rack (~> 0.22)
7
10
  rack (~> 3.0)
8
11
  rackup (~> 2.0)
9
12
 
@@ -11,15 +14,30 @@ GEM
11
14
  remote: https://rubygems.org/
12
15
  specs:
13
16
  benchmark-ips (2.14.0)
17
+ console (1.34.3)
18
+ fiber-annotation
19
+ fiber-local (~> 1.1)
20
+ json
21
+ fiber-annotation (0.2.0)
22
+ fiber-local (1.1.0)
23
+ fiber-storage
24
+ fiber-storage (1.0.1)
25
+ io-stream (0.11.1)
26
+ json (2.15.2)
14
27
  localhost (1.6.0)
15
28
  logger (1.7.0)
16
29
  minitest (5.27.0)
17
30
  minitest-focus (1.4.0)
18
31
  minitest (>= 4, < 6)
32
+ protocol-http (0.60.0)
33
+ protocol-rack (0.22.1)
34
+ io-stream (>= 0.10)
35
+ protocol-http (~> 0.58)
36
+ rack (>= 1.0)
19
37
  rack (3.2.4)
20
38
  rackup (2.2.1)
21
39
  rack (>= 3)
22
- rake (13.3.1)
40
+ rake (13.4.2)
23
41
  rake-compiler (1.3.0)
24
42
  rake
25
43
  rake-compiler-dock (1.9.1)
data/README.md CHANGED
@@ -1,13 +1,25 @@
1
1
  # Quicsilver
2
2
 
3
- HTTP/3 server for Ruby with Rack support.
4
-
5
- **Status:** Experimental (v0.2.0)
3
+ HTTP/3 server and client for Ruby with Rack support.
4
+
5
+ ## Features
6
+
7
+ - **HTTP/3 server** — serve any Rack app over QUIC/HTTP/3
8
+ - **HTTP/3 client** — make requests with automatic connection pooling
9
+ - **Rack integration** — `rackup -s quicsilver` works with Rails, Sinatra, any Rack app
10
+ - **Streaming** — dispatch on HEADERS, stream body chunks as they arrive
11
+ - **Extensible Priorities** (RFC 9218) — CSS before images, server respects client priority hints
12
+ - **Trailers** (RFC 9114 §4.1) — send/receive trailing headers after the body
13
+ - **GREASE** (RFC 9297) — extensibility testing on settings, frames, and streams
14
+ - **GOAWAY** (RFC 9114 §7.2.6) — graceful connection draining with validation
15
+ - **0-RTT** — fast reconnection with replay protection
16
+ - **Connection pooling** — client reuses connections automatically
17
+ - **protocol-http integration** — works with Falcon and protocol-http ecosystem
6
18
 
7
19
  ## Installation
8
20
 
9
21
  ```bash
10
- git clone <repository>
22
+ git clone https://github.com/hahmed/quicsilver
11
23
  cd quicsilver
12
24
  bundle install
13
25
  rake compile
@@ -21,18 +33,11 @@ rake compile
21
33
  require "quicsilver"
22
34
 
23
35
  app = ->(env) {
24
- case env['PATH_INFO']
25
- when '/'
26
- [200, {'content-type' => 'text/plain'}, ["Hello HTTP/3!"]]
27
- when '/api/users'
28
- [200, {'content-type' => 'application/json'}, ['{"users": ["alice", "bob"]}']]
29
- else
30
- [404, {'content-type' => 'text/plain'}, ["Not Found"]]
31
- end
36
+ [200, {"content-type" => "text/plain"}, ["Hello HTTP/3!"]]
32
37
  }
33
38
 
34
39
  server = Quicsilver::Server.new(4433, app: app)
35
- server.start # Blocks until shutdown
40
+ server.start
36
41
  ```
37
42
 
38
43
  ### Client
@@ -40,44 +45,102 @@ server.start # Blocks until shutdown
40
45
  ```ruby
41
46
  require "quicsilver"
42
47
 
43
- client = Quicsilver::Client.new("127.0.0.1", 4433, unsecure: true)
44
- client.connect
45
-
46
- response = client.get("/api/users")
47
- puts response[:body]
48
+ # Class-level API with automatic connection pooling
49
+ response = Quicsilver::Client.get("127.0.0.1", 4433, "/")
50
+ puts response[:status] # => 200
51
+ puts response[:body] # => "Hello HTTP/3!"
48
52
 
49
- response = client.post("/api/users", body: '{"name": "charlie"}')
53
+ # POST with body
54
+ response = Quicsilver::Client.post("127.0.0.1", 4433, "/api/users",
55
+ body: '{"name": "alice"}',
56
+ headers: { "content-type" => "application/json" })
50
57
 
58
+ # Instance-level for more control
59
+ client = Quicsilver::Client.new("127.0.0.1", 4433, unsecure: true)
60
+ response = client.get("/")
51
61
  client.disconnect
52
62
  ```
53
63
 
54
- ## Usage with Rails
64
+ ### Rails
55
65
 
56
66
  ```bash
57
67
  rackup -s quicsilver -p 4433
58
68
  ```
59
69
 
70
+ ### curl
71
+
72
+ ```bash
73
+ curl --http3-only https://localhost:4433/
74
+ ```
75
+
60
76
  ## Configuration
61
77
 
62
78
  ```ruby
63
- config = Quicsilver::ServerConfiguration.new("/path/to/cert.pem", "/path/to/key.pem",
64
- idle_timeout_ms: 10_000, # Connection idle timeout (ms)
65
- max_concurrent_requests: 100 # Max concurrent requests per connection
79
+ config = Quicsilver::Transport::Configuration.new(
80
+ "certificates/server.crt",
81
+ "certificates/server.key",
82
+ idle_timeout_ms: 10_000,
83
+ max_concurrent_requests: 100,
84
+ max_body_size: 10 * 1024 * 1024, # 10MB body limit (optional)
85
+ max_header_size: 64 * 1024, # 64KB header limit (optional)
86
+ max_header_count: 128, # Header count limit (optional)
87
+ stream_receive_window: 262_144, # 256KB per stream
88
+ connection_flow_control_window: 16_777_216 # 16MB per connection
66
89
  )
67
90
 
68
- server = Quicsilver::Server.new(4433,
69
- app: app,
70
- address: "0.0.0.0",
71
- server_configuration: config
91
+ server = Quicsilver::Server.new(4433, app: app, server_configuration: config)
92
+ server.start
93
+ ```
94
+
95
+ ## Priorities
96
+
97
+ Browsers send priority hints on requests. Quicsilver parses them and tells MsQuic to schedule high-priority streams first.
98
+
99
+ ```
100
+ GET /style.css → priority: u=0 → sent first (highest urgency)
101
+ GET /app.js → priority: u=1 → sent second
102
+ GET /hero.png → priority: u=5 → sent later
103
+ ```
104
+
105
+ No configuration needed — it works automatically.
106
+
107
+ ## Trailers
108
+
109
+ Send headers after the body — useful for checksums, streaming status, and gRPC.
110
+
111
+ ```ruby
112
+ # Trailers work with protocol-http's Headers#trailer! API
113
+ headers = Protocol::HTTP::Headers.new
114
+ headers.add("content-type", "text/plain")
115
+ headers.trailer!
116
+ headers.add("x-checksum", "abc123")
117
+ ```
118
+
119
+ ## Protocol-HTTP Mode
120
+
121
+ For integration with [Falcon](https://github.com/socketry/falcon) and the protocol-http ecosystem:
122
+
123
+ ```ruby
124
+ config = Quicsilver::Transport::Configuration.new(
125
+ "certificates/server.crt",
126
+ "certificates/server.key",
127
+ mode: :protocol_http
72
128
  )
129
+
130
+ server = Quicsilver::Server.new(4433, app: app, server_configuration: config)
131
+ server.start
73
132
  ```
74
133
 
134
+ | Mode | Body Handling | Use Case |
135
+ |------|---------------|----------|
136
+ | `:rack` (default) | Buffered | Standard Rack apps |
137
+ | `:protocol_http` | Streaming | Falcon, protocol-http apps |
138
+
75
139
  ## Development
76
140
 
77
141
  ```bash
78
- rake compile # Build C extension
142
+ rake compile # Build C extension (macOS: uses Apple clang automatically)
79
143
  rake test # Run tests
80
- rake clean # Clean build artifacts
81
144
  ```
82
145
 
83
146
  ## License
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require "bundler/setup"
1
2
  require "bundler/gem_tasks"
2
3
  require "rake/testtask"
3
4
  require "rake/extensiontask"
@@ -6,6 +7,27 @@ Rake::ExtensionTask.new('quicsilver') do |ext|
6
7
  ext.lib_dir = 'lib/quicsilver'
7
8
  end
8
9
 
10
+ # Ensure MsQuic is built before compiling the C extension
11
+ task :compile => :build_msquic
12
+
13
+ # Copy MsQuic dylib next to the compiled extension for gem packaging
14
+ task :bundle_msquic do
15
+ lib_dir = 'lib/quicsilver'
16
+ if RUBY_PLATFORM =~ /darwin/
17
+ dylib = 'vendor/msquic/build/bin/Release/libmsquic.2.dylib'
18
+ if File.exist?(dylib)
19
+ cp dylib, "#{lib_dir}/libmsquic.2.dylib"
20
+ # Update rpath so the bundle finds the dylib in the same directory
21
+ sh "install_name_tool -add_rpath @loader_path #{lib_dir}/quicsilver.bundle 2>/dev/null || true"
22
+ end
23
+ elsif RUBY_PLATFORM =~ /linux/
24
+ so = 'vendor/msquic/build/bin/Release/libmsquic.so.2'
25
+ cp so, "#{lib_dir}/libmsquic.so.2" if File.exist?(so)
26
+ end
27
+ end
28
+
29
+ task :build => :bundle_msquic
30
+
9
31
  task :setup do
10
32
  # Initialize git submodule if it doesn't exist
11
33
  unless File.exist?('vendor/msquic')
@@ -19,9 +41,14 @@ task :build_msquic => :setup do
19
41
  if RUBY_PLATFORM =~ /darwin/
20
42
  cmake_args << '-DCMAKE_EXE_LINKER_FLAGS="-framework CoreServices"'
21
43
  cmake_args << '-DCMAKE_SHARED_LINKER_FLAGS="-framework CoreServices"'
44
+ # Ensure QuicTLS uses Xcode SDK, not Homebrew OpenSSL
45
+ sdk_path = `xcrun --show-sdk-path 2>/dev/null`.strip
46
+ cmake_args << "-DCMAKE_OSX_SYSROOT=#{sdk_path}" unless sdk_path.empty?
22
47
  end
23
- sh "cd vendor/msquic && cmake #{cmake_args.join(' ')}"
24
- sh 'cd vendor/msquic && cmake --build build --config Release'
48
+ # Override PATH so QuicTLS openssldir detection finds system openssl, not Homebrew
49
+ env = { 'PATH' => "/usr/bin:#{ENV['PATH']}" }
50
+ sh env, "cd vendor/msquic && cmake #{cmake_args.join(' ')}"
51
+ sh env, 'cd vendor/msquic && cmake --build build --config Release'
25
52
  end
26
53
 
27
54
  task :build => [:build_msquic, :compile]
@@ -32,6 +59,44 @@ Rake::TestTask.new(:test) do |t|
32
59
  t.test_files = FileList["test/**/*_test.rb"]
33
60
  end
34
61
 
62
+ Rake::TestTask.new(:test_unit) do |t|
63
+ t.libs << "test"
64
+ t.libs << "lib"
65
+ t.test_files = FileList["test/**/*_test.rb"].reject { |f|
66
+ f.include?("integration") || f.include?("stream_control") ||
67
+ f =~ /quicsilver_test|event_loop_test/
68
+ }
69
+ end
70
+
71
+ Rake::TestTask.new(:test_integration) do |t|
72
+ t.libs << "test"
73
+ t.libs << "lib"
74
+ t.test_files = FileList[
75
+ "test/stream_control_integration_test.rb",
76
+ "test/integration/**/*_test.rb",
77
+ "test/quicsilver_test.rb",
78
+ "test/event_loop_test.rb"
79
+ ]
80
+ end
81
+
82
+ desc "Run unit and integration tests in parallel"
83
+ task :test_parallel do
84
+ threads = []
85
+ results = {}
86
+
87
+ threads << Thread.new {
88
+ results[:unit] = system("bundle exec rake test_unit 2>&1 > /dev/null")
89
+ }
90
+ threads << Thread.new {
91
+ results[:integration] = system("bundle exec rake test_integration 2>&1 > /dev/null")
92
+ }
93
+
94
+ threads.each(&:join)
95
+ unless results.values.all?
96
+ abort "Tests failed: #{results.inspect}"
97
+ end
98
+ end
99
+
35
100
  namespace :benchmark do
36
101
  desc "Run throughput benchmark"
37
102
  task :throughput do
@@ -26,7 +26,7 @@ def test_multiplexing(host, port)
26
26
  mutex = Mutex.new
27
27
 
28
28
  client = Quicsilver::Client.new(host, port, unsecure: true)
29
- client.connect
29
+ client.open_connection
30
30
 
31
31
  elapsed = Benchmark.realtime do
32
32
  threads = MULTIPLEX_REQUESTS.times.map do |i|
@@ -65,7 +65,7 @@ def test_concurrent_clients(host, port)
65
65
  threads = NUM_CLIENTS.times.map do |i|
66
66
  Thread.new do
67
67
  client = Quicsilver::Client.new(host, port, unsecure: true)
68
- client.connect
68
+ client.open_connection
69
69
 
70
70
  REQUESTS_PER_CLIENT.times do |req|
71
71
  start = Time.now
data/benchmarks/rails.rb CHANGED
@@ -59,7 +59,7 @@ post_elapsed = Benchmark.realtime do
59
59
  conn_threads = CONNECTIONS.times.map do |conn_id|
60
60
  Thread.new do
61
61
  client = Quicsilver::Client.new(HOST, PORT, unsecure: true)
62
- client.connect
62
+ client.open_connection
63
63
 
64
64
  local_times = []
65
65
  local_ids = []
@@ -99,7 +99,7 @@ get_elapsed = Benchmark.realtime do
99
99
  conn_threads = CONNECTIONS.times.map do
100
100
  Thread.new do
101
101
  client = Quicsilver::Client.new(HOST, PORT, unsecure: true)
102
- client.connect
102
+ client.open_connection
103
103
 
104
104
  local_times = []
105
105
 
@@ -132,7 +132,7 @@ delete_elapsed = Benchmark.realtime do
132
132
  next if ids.empty?
133
133
 
134
134
  client = Quicsilver::Client.new(HOST, PORT, unsecure: true)
135
- client.connect
135
+ client.open_connection
136
136
 
137
137
  local_times = []
138
138
 
@@ -29,7 +29,7 @@ def run_benchmark(host, port)
29
29
  threads = CONNECTIONS.times.map do
30
30
  Thread.new do
31
31
  client = Quicsilver::Client.new(host, port, connection_timeout: 5000, request_timeout: 10)
32
- client.connect
32
+ client.open_connection
33
33
 
34
34
  local = []
35
35
  per_conn.times do
@@ -61,7 +61,7 @@ def run_benchmark(host, port)
61
61
  threads = CONNECTIONS.times.map do
62
62
  Thread.new do
63
63
  client = Quicsilver::Client.new(host, port, connection_timeout: 5000, request_timeout: 10)
64
- client.connect
64
+ client.open_connection
65
65
 
66
66
  local = []
67
67
  queue = Queue.new