Skip to content

Expose timeout on Kotlin client builder; disable in tests#317

Merged
jeremy merged 1 commit into
mainfrom
kotlin/expose-builder-timeout
May 20, 2026
Merged

Expose timeout on Kotlin client builder; disable in tests#317
jeremy merged 1 commit into
mainfrom
kotlin/expose-builder-timeout

Conversation

@jeremy
Copy link
Copy Markdown
Member

@jeremy jeremy commented May 20, 2026

Summary

  • BasecampClientBuilder didn't surface a timeout knob, so callers were stuck on the 30-second default baked into BasecampConfig. Wired it through.
  • configureClient() skips installing Ktor's HttpTimeout plugin when timeout is Duration.INFINITE.
  • Test client construction now flows through a new testBasecampClient { … } helper that defaults timeout to Duration.INFINITE. Tests that want to exercise timeout behavior can override inside the block.

Why

Ktor 3.5.0 (KTOR-8271, bumped in #311) made HttpTimeout honor the kotlinx-coroutines test scheduler's virtual clock. Under runTest, the dispatcher idles while MockEngine posts its response back from Dispatchers.IO; virtual time auto-advances past 30s; the timeout coroutine fires and every request fails with HttpRequestTimeoutException. 66 tests broke from a single dependency bump.

Rather than pinning ktor or sniffing for MockEngine in production code, this surfaces timeout as a real public builder field and uses the existing API (set it to INFINITE) to opt out in tests. Production code path is unchanged.

Test plan

  • make kt-test green (was 66 failures before this change).
  • Future timeout-behavior tests can set timeout = 100.milliseconds inside testBasecampClient { … } and assert HttpRequestTimeoutException — a capability KTOR-8271 unlocked.

Summary by cubic

Expose a request timeout on the Kotlin BasecampClientBuilder and disable it by default in tests to prevent false timeouts after the Ktor 3.5.0 update. Centralizes the 30s default, validates the value, and installs HttpTimeout only when the timeout is finite.

  • New Features

    • Added timeout: Duration to BasecampClientBuilder (defaults to BasecampConfig.DEFAULT_TIMEOUT = 30s). Set Duration.INFINITE to disable.
    • Validate timeout at build: must be positive or Duration.INFINITE.
    • configureClient() installs HttpTimeout only when the timeout is finite; default moved to BasecampConfig.DEFAULT_TIMEOUT shared by builder and config.
  • Bug Fixes

    • Tests now build clients via testBasecampClient { ... } with timeout = Duration.INFINITE to avoid HttpRequestTimeoutException under runTest with Ktor 3.5.0’s virtual clock. Override the timeout in tests when needed.

Written for commit b777b8e. Summary will update on new commits. Review in cubic

Copilot AI review requested due to automatic review settings May 20, 2026 13:11
@github-actions github-actions Bot added the enhancement New feature or request label May 20, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR exposes a configurable request timeout on the Kotlin BasecampClientBuilder, makes HttpTimeout opt-in by skipping plugin installation when the configured timeout is Duration.INFINITE, and updates Kotlin tests to construct clients with timeouts disabled by default to avoid runTest virtual-time induced timeouts after the Ktor 3.5.0 bump.

Tip

If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

Changes:

  • Add timeout: Duration to BasecampClientBuilder and pass it through to BasecampConfig.
  • Only install Ktor’s HttpTimeout plugin when the configured timeout is finite.
  • Introduce testBasecampClient { ... } (defaults to Duration.INFINITE) and migrate tests to use it.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt Exposes timeout on the builder and conditionally installs HttpTimeout only for finite timeouts.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TestBasecampClient.kt Adds a shared test helper that disables timeouts by default (using Duration.INFINITE).
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/AuthStrategyTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/ClientTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/CommentsServiceTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/DownloadTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/PaginationTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/PeopleServiceTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/ProjectsServiceTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/RetryTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/TodosServiceTest.kt Switches test client construction to testBasecampClient.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/WebhooksServiceTest.kt Switches test client construction to testBasecampClient.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt
Comment thread kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt Outdated
Comment thread kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 12 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt Outdated
Comment thread kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/BasecampClient.kt Outdated
@github-actions github-actions Bot added bug Something isn't working and removed enhancement New feature or request labels May 20, 2026
BasecampClientBuilder didn't surface the timeout knob, so callers were
stuck on the 30-second default baked into BasecampConfig. Wire it
through (with BasecampConfig.DEFAULT_TIMEOUT as the single source of
truth), reject non-positive timeouts at build(), and skip installing
Ktor's HttpTimeout plugin when the timeout is Duration.INFINITE.

In tests, route all client construction through a new
testBasecampClient helper that defaults timeout to INFINITE. Ktor 3.5.0
(KTOR-8271) made HttpTimeout honor the kotlinx-coroutines test
scheduler's virtual clock, so under runTest the 30s timeout was firing
before MockEngine's IO-dispatched response could return — breaking 66
tests. Tests that want to exercise timeout behavior can override the
default inside the block.

Adds ClientTest cases covering timeout propagation, non-positive
rejection, and the INFINITE-skips-install regression guard.
@jeremy jeremy force-pushed the kotlin/expose-builder-timeout branch from b608f6a to b777b8e Compare May 20, 2026 20:34
@github-actions github-actions Bot added the breaking Breaking change to public API label May 20, 2026
@github-actions
Copy link
Copy Markdown

⚠️ Potential breaking changes detected:

  • Default value for the timeout configuration in BasecampConfig was changed from a hardcoded '30.seconds' to 'DEFAULT_TIMEOUT'. This constitutes a breaking change as it may alter the default behavior for existing clients relying on the previous value.
  • A new validation was added to ensure that the 'timeout' value in BasecampClientBuilder is either positive or 'Duration.INFINITE'. This could cause runtime errors for clients previously setting invalid timeout values.

Review carefully before merging. Consider a major version bump.

@jeremy jeremy enabled auto-merge (squash) May 20, 2026 20:35
@jeremy jeremy merged commit ad3fc4a into main May 20, 2026
43 of 44 checks passed
@jeremy jeremy deleted the kotlin/expose-builder-timeout branch May 20, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaking change to public API bug Something isn't working kotlin

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants