Skip to content

feat: IBM WatsonX provider with integration and smoke tests (#1020) - #1052

Open
kannupriyakalra wants to merge 7 commits into
mainfrom
feature/issue-1020-ibm-watsonx-integration
Open

feat: IBM WatsonX provider with integration and smoke tests (#1020)#1052
kannupriyakalra wants to merge 7 commits into
mainfrom
feature/issue-1020-ibm-watsonx-integration

Conversation

@kannupriyakalra

Copy link
Copy Markdown
Collaborator

Summary

Implements #1020: integration and smoke tests for the IBM WatsonX provider.

This PR includes both the WatsonXClient implementation (since #1019 had not landed yet) and all the requested tests.

Changes

New source files:

  • modules/core/src/main/scala/org/llm4s/llmconnect/provider/WatsonXClient.scala — WatsonX client with IAM token exchange, caching, refresh, complete(), and streamComplete().
  • modules/core/src/main/scala/org/llm4s/llmconnect/config/ProviderConfig.scala — Added WatsonXConfig case class with apiKey, projectId, model, baseUrl, iamUrl fields.
  • modules/core/src/main/scala/org/llm4s/types/ProviderModelTypes.scala — Added WatsonX to ProviderKind enum.
  • modules/core/src/main/scala/org/llm4s/llmconnect/LLMConnect.scala — Registered WatsonXConfig -> WatsonXClient routing.

New test files:

  • modules/core/src/test/scala/org/llm4s/llmconnect/provider/WatsonXClientSpec.scala — 30+ mock-based unit tests covering all acceptance criteria.
  • modules/it/src/test/scala/org/llm4s/llmconnect/smoke/WatsonXSmokeSpec.scala — Real-endpoint smoke tests (skipped when credentials absent).

Test Coverage

All unit tests use MockHttpClient / FailingHttpClient — no IBM credentials required for sbt test.

Covered scenarios:

  • IAM token exchange and bearer token extraction
  • IAM token caching (no re-exchange within TTL)
  • IAM token refresh when expired (< 60s remaining)
  • IAM failure → ConfigurationError
  • IAM invalid JSON → ConfigurationError
  • Successful complete() with token usage
  • complete() with missing generated_textValidationError
  • WatsonX quota error (HTTP 429) → RateLimitError
  • WatsonX auth failure (HTTP 401/403) → AuthenticationError
  • WatsonX server error (HTTP 500) → ServiceError
  • Invalid project_id detected from error body → ValidationError
  • streamComplete() assembles chunks and captures token usage
  • Empty stream → ValidationError
  • Stream HTTP errors → RateLimitError
  • Network failure → propagated error
  • Lifecycle: close()ConfigurationError on subsequent calls
  • Provider exchange logging

Smoke Tests

Located in modules/it/src/test/scala/org/llm4s/llmconnect/smoke/WatsonXSmokeSpec.scala:

  • Requires WATSONX_API_KEY, WATSONX_PROJECT_ID; skips gracefully if absent
  • Tests complete() with ibm/granite-3-8b-instruct
  • Verifies token usage is populated
  • Tests streamComplete(): at least one chunk emitted
  • Tests IAM token exchange end-to-end

Run with: sbt testSmoke (requires IBM Cloud credentials)

Closes #1020

🤖 Generated with Claude Code

kannupriyakalra and others added 7 commits June 15, 2026 08:29
Resolves #1020. Implements WatsonXClient with IAM token-based auth,
complete() and streamComplete() support, and comprehensive mock-based
unit tests (WatsonXClientSpec) plus real-endpoint smoke tests (WatsonXSmokeSpec).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Run scalafmt on the three files that failed CI Quick Checks:
LLMConnect.scala, WatsonXClient.scala, and WatsonXClientSpec.scala.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The WatsonXClient uses a try/finally block for resource cleanup in
processStreamResponse(). Add DisableSyntax.NoKeywordFinally to the
scalafix:off suppression comment alongside the existing NoKeywordTry.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove unused 'token' parameter from handleErrorResponse in WatsonXClient
- Add missing WatsonX case to NamedProviderLoader pattern match using
  'endpoint' config field as the WatsonX projectId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add WatsonXConfig pattern match cases to:
- ProviderSetupRuntime.applyConfiguredSessionOverride
- ProviderSetupRuntime.overrideModel
- PrometheusMetricsExample providerName match

These were causing compiler warnings treated as errors (-Werror).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The describe() function in ProviderKindSpec was missing the WatsonX
case causing a non-exhaustive match warning treated as error (-Werror)
in test compilation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d update ProviderKindSpec for WatsonX

- Fix MockHttpClient.postStream to use the response returned by record()
  instead of the original constructor parameter, so streaming tests
  receive the correct queued HttpResponse (statusCode + body).
- Update ProviderKindSpec: bump expected size to 11, add WatsonX to
  allOf check, add WatsonX name assertion, and add watsonx fromName
  round-trip assertions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 15, 2026

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(test): integration and smoke tests for IBM WatsonX provider

1 participant