Skip to content

Add type provider integration tests for CancellationToken-overloaded methods#338

Merged
sergey-tihon merged 3 commits intorepo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95from
copilot/sub-pr-336
Mar 23, 2026
Merged

Add type provider integration tests for CancellationToken-overloaded methods#338
sergey-tihon merged 3 commits intorepo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95from
copilot/sub-pr-336

Conversation

Copy link
Contributor

Copilot AI commented Mar 23, 2026

The CancellationToken PR lacked integration tests that exercise the TP-generated CT overloads end-to-end against a real HTTP server.

Changes

  • v3/Swashbuckle.CancellationToken.Tests.fs — new test module with 4 [<Fact>] tests calling TP-generated methods with explicit CT arguments:

    • CancellationToken.None on GET and POST operations
    • Active CancellationTokenSource token (happy path)
    • Pre-cancelled token → asserts OperationCanceledException
  • SwaggerProvider.ProviderTests.fsproj — includes the new file, ordered after Swashbuckle.ReturnControllers.Tests.fs (which defines the api instance these tests reuse)

// Explicit CancellationToken.None
let! result = api.GetApiReturnBoolean(CancellationToken.None)

// Active token
use cts = new CancellationTokenSource()
let! result = api.GetApiReturnInt32(cts.Token)

// Pre-cancelled → OperationCanceledException
use cts = new CancellationTokenSource()
cts.Cancel()
let! _ = api.GetApiReturnString(cts.Token)  // throws

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copy link
Contributor Author

Copilot AI commented Mar 23, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • petstore.swagger.io
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTempiXPNHK/tmpa0d7dc1fc7d0470caabd2d412b9e0d9f.rsp git conf�� --local credential.helper (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTempRgGS22/tmp88efa443e8d448f99de291eeff3ced7b.rsp git ogs.�� linuxagent-logcollector.slice (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTempL58rKC/tmp5f8b101f8b714b81aff5ebcb17be25ae.rsp bash --no�� --noprofile (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title [WIP] Add CancellationToken support to OpenApiClientProvider generated methods Add type provider integration tests for CancellationToken-overloaded methods Mar 23, 2026
Copilot AI requested a review from sergey-tihon March 23, 2026 20:47
@sergey-tihon
Copy link
Member

@copilot ci still failing

… invalid IL for structs

Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/cd02aac9-3f51-40c9-af2f-11d1eda31d77
Copy link
Contributor Author

Copilot AI commented Mar 23, 2026

@copilot ci still failing

Fixed in e74b3e2. Root cause: Expr.Coerce(expr, typeof<CancellationToken>) generates a castclass IL instruction which is only valid for reference types — CancellationToken is a struct, so the JIT rejected it with InvalidProgramException.

Fix: extract the CT argument by position (always the last parameter in the overload) and use Expr.Cast<Threading.CancellationToken>(ctArg) which is a typed wrapper with no IL cast instruction. Also replaced the fragile sVar.Name = "cancellationToken" check that could collide with OpenAPI spec parameters of the same name.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • petstore.swagger.io
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTemppJyfcF/tmpf860966a85c0444d9d34ff83f7d6577f.rsp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@sergey-tihon sergey-tihon marked this pull request as ready for review March 23, 2026 21:27
Copilot AI review requested due to automatic review settings March 23, 2026 21:27
Copy link
Contributor

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

Adds end-to-end integration coverage for type-provider-generated CancellationToken overloads against the existing Swashbuckle test server, and updates the v3 operation invocation compiler to reliably extract the CT argument.

Changes:

  • Add new v3 integration tests that call TP-generated methods with explicit CancellationToken arguments (including pre-cancelled token behavior).
  • Register the new test module in the provider test project with correct compile ordering.
  • Adjust v3 OperationCompiler to extract CancellationToken by argument position (last argument) instead of by name.

Reviewed changes

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

File Description
tests/SwaggerProvider.ProviderTests/v3/Swashbuckle.CancellationToken.Tests.fs New integration tests exercising CT overloads (GET/POST, active token, pre-cancelled token).
tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj Includes the new test file after Swashbuckle.ReturnControllers.Tests.fs to reuse api.
src/SwaggerProvider.DesignTime/v3/OperationCompiler.fs Changes CT extraction in provided method invoke code to be position-based and avoid prior name/cast issues.

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

Comment on lines +276 to +287
// When the CancellationToken overload is generated, CancellationToken is always appended last.
// Extract it by position to avoid name-collision issues and invalid Expr.Coerce
// on a struct type (which generates an invalid castclass IL instruction).
let apiArgs, ct =
let allArgs = List.tail args // skip `this`

if includeCancellationToken then
match List.rev allArgs with
| ctArg :: revApiArgs -> List.rev revApiArgs, Expr.Cast<Threading.CancellationToken>(ctArg)
| [] -> failwith "Expected CancellationToken argument but argument list was empty"
else
allArgs, <@ Threading.CancellationToken.None @>
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The PR title/description focuses on adding integration tests, but this hunk also changes type provider code generation behavior (CancellationToken argument extraction). Please update the PR description/title to reflect the compiler change (or split into a separate PR) so reviewers don’t miss the functional impact.

Copilot uses AI. Check for mistakes.
if includeCancellationToken then
match List.rev allArgs with
| ctArg :: revApiArgs -> List.rev revApiArgs, Expr.Cast<Threading.CancellationToken>(ctArg)
| [] -> failwith "Expected CancellationToken argument but argument list was empty"
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

This failwith message is likely only hit when TP invocation arguments are unexpected, but it would be much easier to diagnose if it included the operation/method name (e.g., providedMethodName) and the received argument count. Consider switching to failwithf with that context.

Suggested change
| [] -> failwith "Expected CancellationToken argument but argument list was empty"
| [] ->
failwithf
"Method '%s' expected a CancellationToken argument as the last parameter but received %d argument(s)."
providedMethodName
allArgs.Length

Copilot uses AI. Check for mistakes.
@sergey-tihon sergey-tihon merged commit b2f0d80 into repo-assist/feat-cancellationtoken-issue-212-2026-03-23-448c1cde90ec7d95 Mar 23, 2026
18 checks passed
@sergey-tihon sergey-tihon deleted the copilot/sub-pr-336 branch March 23, 2026 22:12
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.

3 participants