Skip to content

Commit a3d3286

Browse files
committed
feat: Improve test infrastructure and HTTP2 spec compliance tests
1 parent bec2bcc commit a3d3286

19 files changed

Lines changed: 941 additions & 26 deletions

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
HTTPBIN_HTTP_PORT=8080
33
HTTPBIN_HTTPS_PORT=8443
44

5+
# HTTP/2 compliance test harness port
6+
H2_TEST_PORT=18080
7+
8+
# Optional: Specific test case to run (leave empty for server mode)
9+
# H2_TEST_CASE=3.5
10+
511
# Optional: Set to your username to avoid file permission issues (macOS/Linux)
612
# DOCKER_USER=$(whoami)
713
# Or use numeric UID:GID format

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
run: rebar3 dialyzer
7272

7373
- name: Start docker services
74-
run: docker compose up -d
74+
run: docker compose -f test/support/docker-compose.yml up -d
7575

7676
- name: Wait for services
7777
run: |
@@ -109,4 +109,4 @@ jobs:
109109

110110
- name: Stop docker services
111111
if: always()
112-
run: docker compose down
112+
run: docker compose -f test/support/docker-compose.yml down
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: HTTP/2 Compliance
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
# Allow manual trigger
9+
workflow_dispatch:
10+
11+
jobs:
12+
h2spec_compliance:
13+
name: HTTP/2 Compliance (h2-client-test-harness)
14+
runs-on: ubuntu-latest
15+
16+
env:
17+
OTP_VERSION: '28.1'
18+
REBAR3_VERSION: '3.24.0'
19+
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Setup Erlang/OTP
25+
uses: erlef/setup-beam@v1
26+
with:
27+
otp-version: ${{ env.OTP_VERSION }}
28+
rebar3-version: ${{ env.REBAR3_VERSION }}
29+
30+
- name: Cache dependencies
31+
uses: actions/cache@v4
32+
with:
33+
path: _build/default/lib
34+
key: deps-${{ runner.os }}-otp-${{ env.OTP_VERSION }}-${{ hashFiles('rebar.lock') }}
35+
restore-keys: |
36+
deps-${{ runner.os }}-otp-${{ env.OTP_VERSION }}-
37+
38+
- name: Compile
39+
run: rebar3 compile
40+
41+
- name: Build h2-test-harness-patched Docker image
42+
run: |
43+
docker build -t h2-test-harness-patched:latest -f test/support/Dockerfile.h2-harness-patched .
44+
45+
- name: Verify Docker image
46+
run: |
47+
docker images | grep h2-test-harness-patched
48+
echo "✓ Patched harness image built successfully"
49+
50+
- name: Run HTTP/2 compliance tests
51+
id: h2_compliance
52+
run: |
53+
# Tests will manage their own container lifecycle
54+
rebar3 ct --suite=h2_compliance_SUITE --verbose
55+
56+
- name: Generate test summary
57+
if: always()
58+
run: |
59+
chmod +x test/support/generate_compliance_summary.sh
60+
./test/support/generate_compliance_summary.sh _build/test/logs
61+
62+
- name: Upload compliance test logs
63+
if: always()
64+
uses: actions/upload-artifact@v4
65+
with:
66+
name: h2-compliance-logs-otp-${{ env.OTP_VERSION }}
67+
path: _build/test/logs
68+
69+
- name: Cleanup test containers
70+
if: always()
71+
run: |
72+
# Clean up any leftover test containers
73+
docker ps -a | grep gen_http_h2_test | awk '{print $1}' | xargs docker rm -f || true
74+
75+
- name: Check compliance test results
76+
if: ${{ steps.h2_compliance.outcome == 'failure' }}
77+
run: |
78+
echo "⚠️ HTTP/2 compliance tests failed"
79+
echo "Review logs to identify issues"
80+
exit 1

Makefile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,20 @@ xref: ## Run cross-reference analysis
2727
# Test server management
2828
server-start: ## Start test server (Docker Compose)
2929
@echo "Starting test server..."
30-
docker-compose up -d
30+
docker compose -f test/support/docker-compose.yml up -d
3131
@echo "Waiting for services to be healthy..."
32-
@timeout 30 sh -c 'until docker-compose ps | grep -q "(healthy)"; do sleep 1; done' || \
32+
@timeout 30 sh -c 'until docker compose -f test/support/docker-compose.yml ps | grep -q "(healthy)"; do sleep 1; done' || \
3333
(echo "Timeout waiting for services" && exit 1)
3434
@echo "✓ Test server ready at http://localhost:8080 and https://localhost:8443"
3535

3636
server-stop: ## Stop test server
37-
docker-compose down
37+
docker compose -f test/support/docker-compose.yml down
3838

3939
server-status: ## Show test server status
40-
docker-compose ps
40+
docker compose -f test/support/docker-compose.yml ps
4141

4242
server-logs: ## Show test server logs
43-
docker-compose logs -f
43+
docker compose -f test/support/docker-compose.yml logs -f
4444

4545
server-health: ## Check if test server is healthy
4646
@curl -sf http://localhost:8080/status/200 > /dev/null && \

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# gen_http
22

33
[![CI](https://github.com/codeadict/gen_http/actions/workflows/ci.yml/badge.svg)](https://github.com/codeadict/gen_http/actions/workflows/ci.yml)
4+
[![HTTP/2 Compliance](https://github.com/codeadict/gen_http/actions/workflows/h2-compliance.yml/badge.svg)](https://github.com/codeadict/gen_http/actions/workflows/h2-compliance.yml)
5+
[![RFC 7540](https://img.shields.io/badge/RFC%207540-compliant-brightgreen)](https://datatracker.ietf.org/doc/html/rfc7540)
6+
[![RFC 7541](https://img.shields.io/badge/RFC%207541-compliant-brightgreen)](https://datatracker.ietf.org/doc/html/rfc7541)
47

58
A minimal, low-level HTTP client for Erlang.
69

@@ -15,6 +18,18 @@ HTTP/1.1 and HTTP/2 support. Pure Erlang. Zero dependencies.
1518

1619
Built to replace `httpc` with better performance and cleaner code.
1720

21+
## HTTP/2 Compliance
22+
23+
**156 compliance tests** covering RFC 7540 (HTTP/2) and RFC 7541 (HPACK)
24+
25+
- Complete frame type validation (DATA, HEADERS, SETTINGS, PING, etc.)
26+
- Stream state machine verification
27+
- Flow control and priority handling
28+
- HPACK compression/decompression
29+
- All error conditions tested
30+
31+
Tested against [h2-client-test-harness](https://github.com/nomadlabsinc/h2-client-test-harness) with **100% pass rate**.
32+
1833
## Quick Start
1934

2035
```erlang
@@ -132,7 +147,7 @@ end.
132147

133148
```bash
134149
# Start test infrastructure
135-
docker-compose up -d
150+
docker compose -f test/support/docker-compose.yml up -d
136151

137152
# Run all tests
138153
rebar3 test
@@ -141,6 +156,9 @@ rebar3 test
141156
rebar3 eunit # Unit tests (fast, no docker)
142157
rebar3 ct # Integration tests (requires docker)
143158
rebar3 proper # Property-based tests
159+
160+
# HTTP/2 compliance tests (excluded by default - slow, requires special setup)
161+
rebar3 ct --suite=h2_compliance_SUITE
144162
```
145163

146164
## Project Status

rebar.config

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,16 @@
9999

100100
{ct_opts, [
101101
{sys_config, []},
102-
{logdir, "_build/test/logs"}
102+
{logdir, "_build/test/logs"},
103+
%% Exclude h2_compliance_SUITE by default (slow, requires special Docker setup)
104+
%% Run it explicitly with: rebar3 ct --suite=h2_compliance_SUITE
105+
{suites, [
106+
features_SUITE,
107+
http1_SUITE,
108+
http2_SUITE,
109+
ssl_SUITE,
110+
unified_SUITE
111+
]}
103112
]}.
104113

105114
{deps, []}.

test/README.md

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ The test infrastructure uses:
2424

2525
```bash
2626
# Start the test servers
27-
docker-compose up -d
27+
docker compose -f test/support/docker-compose.yml up -d
2828

2929
# Check servers are healthy
30-
docker-compose ps
30+
docker compose -f test/support/docker-compose.yml ps
3131

3232
# View logs if needed
33-
docker-compose logs -f
33+
docker compose -f test/support/docker-compose.yml logs -f
3434
```
3535

3636
### 2. Run Tests
@@ -39,21 +39,28 @@ docker-compose logs -f
3939
# Run all unit tests
4040
rebar3 eunit
4141

42+
# Run Common Test integration tests (requires docker servers)
43+
rebar3 ct
44+
4245
# Run property-based tests
43-
rebar3 as test proper
46+
rebar3 proper
4447

4548
# Run all tests
46-
rebar3 do eunit, as test proper
49+
rebar3 test
50+
51+
# Run HTTP/2 compliance tests (excluded by default - slow, requires special setup)
52+
# Note: This requires the h2-test-harness-patched Docker image to be built
53+
rebar3 ct --suite=h2_compliance_SUITE
4754
```
4855

4956
### 3. Stop Test Infrastructure
5057

5158
```bash
5259
# Stop and remove containers
53-
docker-compose down
60+
docker compose -f test/support/docker-compose.yml down
5461

5562
# Stop and remove containers + volumes
56-
docker-compose down -v
63+
docker compose -f test/support/docker-compose.yml down -v
5764
```
5865

5966
## Test Server Endpoints
@@ -88,8 +95,8 @@ HTTPBIN_HTTPS_PORT=8443
8895

8996
If tests are being skipped with "Test server not available", ensure:
9097

91-
1. Docker Compose is running: `docker-compose ps`
92-
2. Services are healthy: `docker-compose ps` (should show "healthy")
98+
1. Docker Compose is running: `docker compose -f test/support/docker-compose.yml ps`
99+
2. Services are healthy: `docker compose -f test/support/docker-compose.yml ps` (should show "healthy")
93100
3. Ports are accessible: `curl http://localhost:8080/get`
94101

95102
### Port conflicts
@@ -113,6 +120,11 @@ The Caddy server uses self-signed certificates for local testing. Tests should u
113120
## Test Structure
114121

115122
- `test_helper.erl` - Common test utilities and server configuration
116-
- `*_test.erl` - Unit tests for individual modules
117-
- `*_integration_test.erl` - Integration tests that use the test server
123+
- `*_SUITE.erl` - Common Test suites (integration tests)
124+
- `features_SUITE.erl` - Feature tests
125+
- `http1_SUITE.erl` - HTTP/1.1 protocol tests
126+
- `http2_SUITE.erl` - HTTP/2 protocol tests
127+
- `ssl_SUITE.erl` - SSL/TLS tests
128+
- `unified_SUITE.erl` - Unified API tests
129+
- `h2_compliance_SUITE.erl` - HTTP/2 RFC compliance (excluded by default)
118130
- `prop_*.erl` - Property-based tests using PropEr

test/features_SUITE.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ init_per_suite(Config) ->
7676
ct:pal("Docker services are available"),
7777
Config;
7878
false ->
79-
{skip, "Docker services not available. Run: docker-compose up -d"}
79+
{skip, "Docker services not available. Run: docker compose -f test/support/docker-compose.yml up -d"}
8080
end.
8181

8282
end_per_suite(_Config) ->

0 commit comments

Comments
 (0)