Skip to main content

max / synckit

Install the rustls provider on the test paths that build a client directly Three tests reach reqwest's Client::builder without going through SyncKitClient::new or the integration harness, so nothing had installed a provider and the build panicked. They only ever passed when a sibling test happened to run first. Lift the install in new() into a cfg(test) helper and call it from the unit test and from authed_short_timeout_client.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-23 20:52 UTC
Signed with PGP, not checked
Commit: 36e691c386890d4cd0f5c353536cc0a6e3a9f148
Parent: be92e3a
2 files changed, +22 insertions, -11 deletions
@@ -436,21 +436,26 @@
436 436 storage_version: RwLock<Option<u32>>,
437 437 }
438 438
439 + /// Install the rustls crypto provider once, for tests only.
440 + ///
441 + /// reqwest is built with `rustls-no-provider`, so a real consumer app installs the
442 + /// process-wide provider (audiofiles installs ring) before it ever builds a client.
443 + /// Tests have no such app, so every test path that builds a `reqwest::Client` calls
444 + /// this first or the build panics. Never compiled into a consumer build.
445 + #[cfg(test)]
446 + fn ensure_crypto_provider() {
447 + static PROVIDER: std::sync::Once = std::sync::Once::new();
448 + PROVIDER.call_once(|| {
449 + // Err means a provider is already installed, which is the outcome we want.
450 + let _ = rustls::crypto::ring::default_provider().install_default();
451 + });
452 + }
453 +
439 454 impl SyncKitClient {
440 455 /// Create a new client with the given configuration.
441 456 pub fn new(config: SyncKitConfig) -> Self {
442 - // reqwest is built with `rustls-no-provider`; a real consumer app installs the
443 - // process-wide crypto provider (audiofiles installs ring) before it ever builds
444 - // a client. Unit tests have no such app, so install ring here once, or the
445 - // client build below would panic. Never compiled into a consumer build.
446 457 #[cfg(test)]
447 - {
448 - static PROVIDER: std::sync::Once = std::sync::Once::new();
449 - PROVIDER.call_once(|| {
450 - // Err means a provider is already installed, which is the outcome we want.
451 - let _ = rustls::crypto::ring::default_provider().install_default();
452 - });
453 - }
458 + ensure_crypto_provider();
454 459
455 460 let https_only = requires_https(&config.server_url);
456 461 let http = Client::builder()
@@ -960,6 +965,9 @@
960 965
961 966 #[test]
962 967 fn with_http_client_starts_unauthenticated() {
968 + // This test builds a reqwest client directly, so it does not pass through
969 + // SyncKitClient::new and has to install the provider itself.
970 + ensure_crypto_provider();
963 971 let http = Client::builder()
964 972 .timeout(Duration::from_millis(100))
965 973 .build()
@@ -478,6 +478,9 @@
478 478 /// The timeout lives on the reqwest client, so it has to be set at construction
479 479 /// rather than on the SyncKit client afterwards.
480 480 fn authed_short_timeout_client(kit: &MockKit) -> SyncKitClient {
481 + // Builds a reqwest client directly rather than through SyncKitClient::new,
482 + // so the provider has to be installed here.
483 + ensure_crypto_provider();
481 484 let http = reqwest::Client::builder()
482 485 .timeout(Duration::from_millis(100))
483 486 .connect_timeout(Duration::from_millis(100))