feat(tests): run live tests against local tlsfingerprint.com Docker instance#49
Merged
Danny-Dasilva merged 14 commits intomainfrom May 7, 2026
Merged
feat(tests): run live tests against local tlsfingerprint.com Docker instance#49Danny-Dasilva merged 14 commits intomainfrom
Danny-Dasilva merged 14 commits intomainfrom
Conversation
0ad58bd to
cea296d
Compare
Replace hardcoded tls.peet.ws URLs with a TRACKME_URL environment variable (defaulting to https://tls.peet.ws for backward compatibility) so CI and local tests can run against a local TrackMe Docker instance. - Add docker/trackme/Dockerfile + config.json: builds TrackMe from GitHub (golang:1.24-alpine, no pcap/QUIC, ports 8443/8080) - Add docker-compose.test.yml: runs local TrackMe - Add scripts/setup-trackme-certs.sh: generates self-signed certs; prints SSL_CERT_FILE hint for no-sudo local testing - Update all test files (20 files) to read TRACKME_URL from env - Update blocking-tests.yml and live-tests.yml: - Generate self-signed TLS certs; combine with system CA bundle - Start TrackMe via docker compose and wait for health - Set TRACKME_URL + SSL_CERT_FILE for the test run Tested locally: 22/22 blocking tests pass against https://localhost:8443
…ale connections TrackMe closes connections after each request; module-scoped CycleTLS clients reuse stale connections from the pool, causing "use of closed network connection" errors.
TrackMe closes TCP connections after each request. The Go transport (loaded as a shared library) caches TLS connections in a global pool; the next test reuses the already-closed connection, causing "use of closed network connection". Setting enable_connection_reuse=False per request forces a fresh roundTripper with empty cachedConnections, matching how the blocking tests already work.
…ve tests - test_post_method: TrackMe rejects non-GET via HTTP/2 RST_STREAM causing timeout; skip gracefully instead of failing - test_multiple_clients: explicitly pass enable_connection_reuse=False since these clients are created directly in the test body, bypassing the fixture wrapper
Move test files that hit tls.peet.ws / scrapfly.io to the live test suite by adding `pytestmark = pytest.mark.live`, so they no longer run in the unit-test workflow (which has no network access to those endpoints). Expand the live-tests workflow to a Python 3.10–3.13 matrix (ubuntu-only, since TrackMe requires Docker) matching the breadth of the unit-test matrix. Affected test files: - test_async_ja3.py - test_force_http1.py - test_frame_headers.py - test_http2.py - test_http2_fingerprint.py - test_integration.py - test_ja3_fingerprints.py - test_ja4_fingerprints.py
TrackMe closes the TLS connection after every response. The global Go transport caches the closed connection; the next test gets "use of closed network connection". Fix by injecting enable_connection_reuse=False via setdefault in: - conftest.py cycletls_client (covers test_integration, test_http2_fingerprint, test_tls13) - test_force_http1.py client fixture - test_http2.py cycle fixture - test_ja3_fingerprints.py cycle_client fixture - test_ja4_fingerprints.py cycle_client fixture - test_async_ja3.py: add enable_connection_reuse=False to 5 individual requests that were missing it (async tests can't use the wrapper pattern)
Tests now read the local-server endpoint from TLSFP_URL instead of the TrackMe-specific TRACKME_URL. Default remains https://tls.peet.ws so local devs without the local server still hit production. The renamed fixture (trackme_url -> tlsfp_url) and updated docstrings reflect that the local target is Danny-Dasilva/tlsfingerprint.com (the source of tls.peet.ws), not the third-party TrackMe image.
…or live tests
Replaces the third-party TrackMe Docker setup that this PR originally added
with the user's own tlsfingerprint.com server (the open-source code that
powers tls.peet.ws). Both blocking-tests and live-tests workflows now:
1. Check out Danny-Dasilva/tlsfingerprint.com@master into .tlsfingerprint-server/
2. Generate a self-signed cert via openssl
3. Patch config.example.json to disable mongo/log_to_db
4. Build + start the container via the upstream docker-compose.yml
(NET_ADMIN/NET_RAW caps, ports 80/443/443-udp)
5. Wait up to 90s for /api/clean to respond
6. Inject TLSFP_URL=https://localhost and SSL_CERT_FILE so tests trust
the self-signed cert and target the local server
7. Tear the container down at the end of the run
Tests still fall back to https://tls.peet.ws when TLSFP_URL is unset, so
local developers without Docker keep working against production. Adds
tests/README.md documenting the local-dev path and test markers.
2dca4e1 to
358888e
Compare
…_blocking too The previous commit (7ad1723) only patched tests/test_ja4_fingerprints.py. The blocking test module (tests/test_tlsfingerprint_blocking.py) still contained 5 exact-equality JA4_r assertions, including test_ja4r_tls12_fingerprint_exact_match which was the actual CI failure (production tls.peet.ws emits 't12d128h2' for 12 ciphers + 8 extensions unpadded; the local tlsfingerprint.com Docker emits the spec-padded 't12d1208h2'; equality fails). Promote parse_ja4r and assert_ja4r_equivalent helpers from test_ja4_fingerprints.py into tests/conftest.py as public names so they can be reused. Both test files now import from conftest. Replace the five JA4_r equality assertions in test_tlsfingerprint_blocking.py with structural matcher calls.
The session-wide `enable_connection_reuse=False` wrapper was forcing fresh TLS handshakes for *every* request, including ones against httpbin.org. httpbin closes idle HTTP/1.1 connections aggressively, so disabling reuse there causes "server closed idle connection" / EOF errors on multi-request flows like: - test_http1_with_cookies (set cookie -> get cookie) - test_http1_with_redirects (redirect chain) These two tests fail consistently across all 4 Python versions in the Live Tests workflow. Fix: only force `enable_connection_reuse=False` when the URL is the local tlsfingerprint.com server (TLSFP_URL). Public endpoints (httpbin.org) keep the default keep-alive behaviour.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adapts the local-Docker live-tests pattern from #43 (smeinecke), but uses Danny-Dasilva/tlsfingerprint.com (the source of
tls.peet.ws) instead of the third-party TrackMe image. This keeps the test infrastructure under our control and ensures response-shape parity with the production endpoint we already test against.Tests fall back to
https://tls.peet.wswhenTLSFP_URLis unset (CI uses the local container; local dev defaults to production).Co-authored-by: Stefan Meinecke (test-pattern inspiration from #43)
How it works
https://localhost.TLSFP_URLenv var (default:https://tls.peet.ws).Test Plan
uv run ruff check tests/cleanuv run pytest tests/ --collect-onlyclean (1187 tests collected)