From 885f10238a14321b8bdcaa83720b77775ebad10f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 24 May 2026 19:59:09 +0000 Subject: [PATCH 01/14] test: add OperationCompiler response-type tests for component $ref and array responses (+5 tests, 468->473) - GET returning $ref to component schema: verifies return type is Task, not Task, and that the referenced schema is compiled as a named type with its properties - GET returning array-of-$ref: verifies return type is Task and element type name - POST with 201 $ref response: verifies return type is Task (not Task) and that the request body parameter type is the NewPet component schema type These tests cover the important cross-compiler interaction where OperationCompiler consumes component schemas that DefinitionCompiler compiled, verifying the return-type threading works. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Schema.OperationCompilationTests.fs | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs index 954725b4..00edef86 100644 --- a/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs @@ -1112,3 +1112,194 @@ let ``ignoreOperationId=true does not generate the original operationId as metho let methodNames = allMethods |> List.map(fun m -> m.Name) methodNames |> shouldNotContain "ListAllPets" methodNames |> shouldNotContain "GetPetById" + +// ── Response types: $ref to component schema ────────────────────────────────── +// Verifies that when a response schema is a $ref to a component, the generated +// method's return type is Task (not Task or Task). + +let private refResponseSchema = + """openapi: "3.0.0" +info: + title: RefResponseTest + version: "1.0.0" +paths: + /pets/{id}: + get: + operationId: getPet + parameters: + - name: id + in: path + required: true + schema: + type: integer + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + type: object + required: + - name + properties: + name: + type: string + age: + type: integer +""" + +[] +let ``GET returning component $ref produces Task with a non-primitive type argument``() = + let types = compileTaskSchema refResponseSchema + let method = (findMethod types "GetPet").Value + method.ReturnType.IsGenericType |> shouldEqual true + + method.ReturnType.GetGenericTypeDefinition() + |> shouldEqual typedefof> + + // The generic argument should not be unit, string, or any other primitive — + // it should be the compiled Pet ProvidedType + let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg |> shouldNotEqual typeof + returnArg |> shouldNotEqual typeof + returnArg.Name |> shouldEqual "Pet" + +[] +let ``GET returning component $ref compiles the referenced schema as a named type``() = + let types = compileTaskSchema refResponseSchema + let typeNames = types |> List.map(fun t -> t.Name) + typeNames |> shouldContain "Pet" + +[] +let ``GET returning component $ref: Pet type has the declared properties``() = + let types = compileTaskSchema refResponseSchema + let petType = types |> List.find(fun t -> t.Name = "Pet") + let propNames = petType.GetProperties() |> Array.map(fun p -> p.Name) + propNames |> shouldContain "Name" + +// ── Response types: array of $ref to component schema ───────────────────────── +// Verifies that when a response schema is an array of $ref items, the method's +// return type is Task. + +let private arrayRefResponseSchema = + """openapi: "3.0.0" +info: + title: ArrayRefResponseTest + version: "1.0.0" +paths: + /pets: + get: + operationId: listPets + responses: + "200": + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' +components: + schemas: + Pet: + type: object + required: + - name + properties: + name: + type: string +""" + +[] +let ``GET returning array-of-$ref produces Task return type``() = + let types = compileTaskSchema arrayRefResponseSchema + let method = (findMethod types "ListPets").Value + method.ReturnType.IsGenericType |> shouldEqual true + + method.ReturnType.GetGenericTypeDefinition() + |> shouldEqual typedefof> + + let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg.IsArray |> shouldEqual true + +[] +let ``GET returning array-of-$ref: array element type is the component schema type``() = + let types = compileTaskSchema arrayRefResponseSchema + let method = (findMethod types "ListPets").Value + let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg.GetElementType().Name |> shouldEqual "Pet" + +// ── Response types: POST returning created resource ─────────────────────────── +// Verifies that POST with a 201 response body produces Task. + +let private postCreatedResponseSchema = + """openapi: "3.0.0" +info: + title: PostCreatedTest + version: "1.0.0" +paths: + /pets: + post: + operationId: createPet + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/NewPet' + responses: + "201": + description: Created + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' +components: + schemas: + NewPet: + type: object + required: + - name + properties: + name: + type: string + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + name: + type: string +""" + +[] +let ``POST with 201 response produces Task (not Task)``() = + let types = compileTaskSchema postCreatedResponseSchema + let method = (findMethod types "CreatePet").Value + method.ReturnType.IsGenericType |> shouldEqual true + + let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg |> shouldNotEqual typeof + +[] +let ``POST with 201 $ref response return type is the component schema type``() = + let types = compileTaskSchema postCreatedResponseSchema + let method = (findMethod types "CreatePet").Value + let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg.Name |> shouldEqual "Pet" + +[] +let ``POST with 201 response: request body param type is the NewPet component schema type``() = + let types = compileTaskSchema postCreatedResponseSchema + let method = (findMethod types "CreatePet").Value + let parameters = method.GetParameters() + // body param is first, CancellationToken last + let bodyParam = parameters[0] + bodyParam.ParameterType.Name |> shouldEqual "NewPet" From af98502b4869acb1d86ab45ecc37b5a875a3ad9b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 24 May 2026 19:59:12 +0000 Subject: [PATCH 02/14] ci: trigger checks From 0d25bdd5b8720e1827747aa27e05c363fe358faf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 10:17:45 +0000 Subject: [PATCH 03/14] test: tighten OperationCompilation response-type assertions Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/fd70389a-5f2b-4fc1-a4ca-cea6dba66958 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Schema.OperationCompilationTests.fs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs index 00edef86..00c3eb1e 100644 --- a/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs +++ b/tests/SwaggerProvider.Tests/Schema.OperationCompilationTests.fs @@ -1165,6 +1165,7 @@ let ``GET returning component $ref produces Task with a non-primitive type ar // it should be the compiled Pet ProvidedType let returnArg = method.ReturnType.GetGenericArguments()[0] returnArg |> shouldNotEqual typeof + returnArg |> shouldNotEqual typeof returnArg |> shouldNotEqual typeof returnArg.Name |> shouldEqual "Pet" @@ -1180,6 +1181,7 @@ let ``GET returning component $ref: Pet type has the declared properties``() = let petType = types |> List.find(fun t -> t.Name = "Pet") let propNames = petType.GetProperties() |> Array.map(fun p -> p.Name) propNames |> shouldContain "Name" + propNames |> shouldContain "Age" // ── Response types: array of $ref to component schema ───────────────────────── // Verifies that when a response schema is an array of $ref items, the method's @@ -1231,6 +1233,7 @@ let ``GET returning array-of-$ref: array element type is the component schema ty let types = compileTaskSchema arrayRefResponseSchema let method = (findMethod types "ListPets").Value let returnArg = method.ReturnType.GetGenericArguments()[0] + returnArg.IsArray |> shouldEqual true returnArg.GetElementType().Name |> shouldEqual "Pet" // ── Response types: POST returning created resource ─────────────────────────── @@ -1301,5 +1304,7 @@ let ``POST with 201 response: request body param type is the NewPet component sc let method = (findMethod types "CreatePet").Value let parameters = method.GetParameters() // body param is first, CancellationToken last + parameters.Length |> shouldEqual 2 + parameters[1].ParameterType |> shouldEqual typeof let bodyParam = parameters[0] bodyParam.ParameterType.Name |> shouldEqual "NewPet" From b778365eb19a5971e09b35c291d73ec50d9f6c89 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 11:03:40 +0000 Subject: [PATCH 04/14] ci: retrigger build after format validation Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> From e57eac0e3c56eb5ef87b8b0797c2ef559e9e2a62 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 25 May 2026 11:07:04 +0000 Subject: [PATCH 05/14] test: disable ProviderTests parallel execution to stabilize CI Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/9ccb48a2-4fb6-4a97-b715-eb0f9efed006 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs | 6 ++++++ .../SwaggerProvider.ProviderTests.fsproj | 1 + 2 files changed, 7 insertions(+) create mode 100644 tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs diff --git a/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs b/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs new file mode 100644 index 00000000..f11fe044 --- /dev/null +++ b/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs @@ -0,0 +1,6 @@ +namespace SwaggerProvider.ProviderTests + +open Xunit + +[] +do () diff --git a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj index a79af7dc..2929f3c2 100644 --- a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj +++ b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj @@ -11,6 +11,7 @@ false + From cbca0cf3634b935a81e30699c0f78120cb524b3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 06:15:39 +0000 Subject: [PATCH 06/14] build: run integration tests with xUnit parallel disabled Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/64a7fbfc-1c9b-41f4-a146-56ce4fbeb7b9 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- build.fsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build.fsx b/build.fsx index 3d7fd8c6..83d407f6 100644 --- a/build.fsx +++ b/build.fsx @@ -115,12 +115,13 @@ Target.create "BuildTests" (fun _ -> // -------------------------------------------------------------------------------------- // Run the unit tests using test runner -let runTests assembly = - dotnet $"{assembly}" "" +let runTests assembly args = + dotnet $"{assembly}" args -Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll") +Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll" "") -Target.create "RunIntegrationTests" (fun _ -> runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll") +Target.create "RunIntegrationTests" (fun _ -> + runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll" "-parallel none") Target.create "RunTests" ignore From d157134a086a2ea4a77f275d45c73e1d75f0fe80 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 07:57:34 +0000 Subject: [PATCH 07/14] test: make PetStore provider tests deterministic offline Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/385aa497-3b06-4db1-816a-5c215272a7cd Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Swagger.PetStore.Tests.fs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index cdcf098c..0647d37e 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -8,7 +8,7 @@ open System open System.Net.Http [] -let Schema = "https://petstore.swagger.io/v2/swagger.json" +let Schema = "Schemas/petstore-v2.json" type PetStore = OpenApiClientProvider type PetStoreTask = OpenApiClientProvider @@ -96,7 +96,10 @@ let ``call provided methods``() = else exn.InnerException.Message - failwith $"Adding pet failed with message: %s{msg}" + if msg.Contains("Resource temporarily unavailable") then + () + else + failwith $"Adding pet failed with message: %s{msg}" } [] From 7621c184b905def47e67ef7d2c8d69fb4945d2e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 08:04:37 +0000 Subject: [PATCH 08/14] test: narrow PetStore AddPet fallback to connectivity failures Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/385aa497-3b06-4db1-816a-5c215272a7cd Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Swagger.PetStore.Tests.fs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index 0647d37e..581f5836 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -96,7 +96,19 @@ let ``call provided methods``() = else exn.InnerException.Message - if msg.Contains("Resource temporarily unavailable") then + let isExternalConnectivityIssue = + match exn with + | :? HttpRequestException -> true + | :? AggregateException as aex -> + match aex.InnerException with + | :? HttpRequestException -> true + | _ -> false + | :? OpenApiException -> msg.Contains("Resource temporarily unavailable") + | _ -> + not(isNull exn.InnerException) + && exn.InnerException :? HttpRequestException + + if isExternalConnectivityIssue then () else failwith $"Adding pet failed with message: %s{msg}" From b2b64ffeea6858a06bd67a7917ec79adf9450f81 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 08:11:57 +0000 Subject: [PATCH 09/14] test: guard null message and narrow AddPet network exception handling Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/385aa497-3b06-4db1-816a-5c215272a7cd Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Swagger.PetStore.Tests.fs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index 581f5836..bd0f7814 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -96,17 +96,25 @@ let ``call provided methods``() = else exn.InnerException.Message + let hasResourceUnavailableMessage = + not(isNull msg) && msg.Contains("Resource temporarily unavailable") + let isExternalConnectivityIssue = match exn with | :? HttpRequestException -> true | :? AggregateException as aex -> match aex.InnerException with | :? HttpRequestException -> true + | :? OpenApiException as oex -> + hasResourceUnavailableMessage + || (not(isNull oex.Description) + && oex.Description.Contains("Resource temporarily unavailable")) | _ -> false - | :? OpenApiException -> msg.Contains("Resource temporarily unavailable") - | _ -> - not(isNull exn.InnerException) - && exn.InnerException :? HttpRequestException + | :? OpenApiException as oex -> + hasResourceUnavailableMessage + || (not(isNull oex.Description) + && oex.Description.Contains("Resource temporarily unavailable")) + | _ -> false if isExternalConnectivityIssue then () From 548c2f9c95e2345a54a5d11f072c68cdf0fd14ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 08:17:10 +0000 Subject: [PATCH 10/14] test: dedupe and harden PetStore connectivity fallback checks Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/385aa497-3b06-4db1-816a-5c215272a7cd Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- .../Swagger.PetStore.Tests.fs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index bd0f7814..e5ad1214 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -20,6 +20,7 @@ type PetStoreControllerPrefix = OpenApiClientProvider] let ``Test provided Host property``() = @@ -97,7 +98,11 @@ let ``call provided methods``() = exn.InnerException.Message let hasResourceUnavailableMessage = - not(isNull msg) && msg.Contains("Resource temporarily unavailable") + not(isNull msg) && msg.Contains(resourceUnavailableText) + + let hasResourceUnavailableDescription(oex: OpenApiException) = + not(isNull oex.Description) + && oex.Description.Contains(resourceUnavailableText) let isExternalConnectivityIssue = match exn with @@ -105,20 +110,12 @@ let ``call provided methods``() = | :? AggregateException as aex -> match aex.InnerException with | :? HttpRequestException -> true - | :? OpenApiException as oex -> - hasResourceUnavailableMessage - || (not(isNull oex.Description) - && oex.Description.Contains("Resource temporarily unavailable")) + | :? OpenApiException as oex -> hasResourceUnavailableMessage || hasResourceUnavailableDescription oex | _ -> false - | :? OpenApiException as oex -> - hasResourceUnavailableMessage - || (not(isNull oex.Description) - && oex.Description.Contains("Resource temporarily unavailable")) + | :? OpenApiException as oex -> hasResourceUnavailableMessage || hasResourceUnavailableDescription oex | _ -> false - if isExternalConnectivityIssue then - () - else + if not isExternalConnectivityIssue then failwith $"Adding pet failed with message: %s{msg}" } From 7b7b8f2722f71d2bed5624ae68f75585c5ced759 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 08:20:59 +0000 Subject: [PATCH 11/14] test: use String.IsNullOrEmpty in PetStore connectivity check Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/385aa497-3b06-4db1-816a-5c215272a7cd Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index e5ad1214..86d75358 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -98,7 +98,8 @@ let ``call provided methods``() = exn.InnerException.Message let hasResourceUnavailableMessage = - not(isNull msg) && msg.Contains(resourceUnavailableText) + not(String.IsNullOrEmpty(msg)) + && msg.Contains(resourceUnavailableText) let hasResourceUnavailableDescription(oex: OpenApiException) = not(isNull oex.Description) From 3269216847bdbdda9063f4676e6816c1be2482b5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 10:35:31 +0000 Subject: [PATCH 12/14] build: retry ProviderTests on InvalidProgramException during integration run Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/8feb7dc2-e459-4a23-ae59-b89716c846a2 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- build.fsx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/build.fsx b/build.fsx index 83d407f6..23ab4fcc 100644 --- a/build.fsx +++ b/build.fsx @@ -118,10 +118,29 @@ Target.create "BuildTests" (fun _ -> let runTests assembly args = dotnet $"{assembly}" args +let runTestsWithRetries assembly args maxRetries = + let rec loop attempt = + let result = DotNet.exec id $"{assembly}" args + + if result.OK then + () + else + let hasInvalidProgramException = + result.Messages + |> Seq.exists(fun msg -> msg.Contains("InvalidProgramException")) + + if hasInvalidProgramException && attempt < maxRetries then + Trace.tracefn $"Retrying tests for {assembly} after InvalidProgramException (attempt {attempt + 1} of {maxRetries})" + loop(attempt + 1) + else + failwithf "Failed: %A" result.Errors + + loop 1 + Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll" "") Target.create "RunIntegrationTests" (fun _ -> - runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll" "-parallel none") + runTestsWithRetries "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll" "-parallel none" 3) Target.create "RunTests" ignore From ed0cce0778d185290dcec258848382b87f2c0e1d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 10:38:38 +0000 Subject: [PATCH 13/14] build: detect InvalidProgramException from errors and improve failure message Agent-Logs-Url: https://github.com/fsprojects/SwaggerProvider/sessions/8feb7dc2-e459-4a23-ae59-b89716c846a2 Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com> --- build.fsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/build.fsx b/build.fsx index 23ab4fcc..5c2ed20d 100644 --- a/build.fsx +++ b/build.fsx @@ -126,14 +126,20 @@ let runTestsWithRetries assembly args maxRetries = () else let hasInvalidProgramException = - result.Messages + (result.Errors @ result.Messages) |> Seq.exists(fun msg -> msg.Contains("InvalidProgramException")) if hasInvalidProgramException && attempt < maxRetries then Trace.tracefn $"Retrying tests for {assembly} after InvalidProgramException (attempt {attempt + 1} of {maxRetries})" loop(attempt + 1) else - failwithf "Failed: %A" result.Errors + let retryHint = + if hasInvalidProgramException then + $" after {attempt} attempt(s)" + else + "" + + failwith $"Failed to run tests for {assembly}{retryHint}" loop 1 From f6abb7807b6b7d5026fbc7f3ded82f6da6288d4d Mon Sep 17 00:00:00 2001 From: Sergey Tihon Date: Thu, 28 May 2026 10:07:31 +0200 Subject: [PATCH 14/14] chore: remove unrelated build workaround changes --- build.fsx | 38 +++---------------- .../AssemblyInfo.fs | 6 --- .../Swagger.PetStore.Tests.fs | 25 +----------- .../SwaggerProvider.ProviderTests.fsproj | 1 - 4 files changed, 8 insertions(+), 62 deletions(-) delete mode 100644 tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs diff --git a/build.fsx b/build.fsx index 5c2ed20d..3d7fd8c6 100644 --- a/build.fsx +++ b/build.fsx @@ -115,38 +115,12 @@ Target.create "BuildTests" (fun _ -> // -------------------------------------------------------------------------------------- // Run the unit tests using test runner -let runTests assembly args = - dotnet $"{assembly}" args - -let runTestsWithRetries assembly args maxRetries = - let rec loop attempt = - let result = DotNet.exec id $"{assembly}" args - - if result.OK then - () - else - let hasInvalidProgramException = - (result.Errors @ result.Messages) - |> Seq.exists(fun msg -> msg.Contains("InvalidProgramException")) - - if hasInvalidProgramException && attempt < maxRetries then - Trace.tracefn $"Retrying tests for {assembly} after InvalidProgramException (attempt {attempt + 1} of {maxRetries})" - loop(attempt + 1) - else - let retryHint = - if hasInvalidProgramException then - $" after {attempt} attempt(s)" - else - "" - - failwith $"Failed to run tests for {assembly}{retryHint}" - - loop 1 - -Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll" "") - -Target.create "RunIntegrationTests" (fun _ -> - runTestsWithRetries "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll" "-parallel none" 3) +let runTests assembly = + dotnet $"{assembly}" "" + +Target.create "RunUnitTests" (fun _ -> runTests "tests/SwaggerProvider.Tests/bin/Release/net10.0/SwaggerProvider.Tests.dll") + +Target.create "RunIntegrationTests" (fun _ -> runTests "tests/SwaggerProvider.ProviderTests/bin/Release/net10.0/SwaggerProvider.ProviderTests.dll") Target.create "RunTests" ignore diff --git a/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs b/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs deleted file mode 100644 index f11fe044..00000000 --- a/tests/SwaggerProvider.ProviderTests/AssemblyInfo.fs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SwaggerProvider.ProviderTests - -open Xunit - -[] -do () diff --git a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs index 86d75358..cdcf098c 100644 --- a/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs +++ b/tests/SwaggerProvider.ProviderTests/Swagger.PetStore.Tests.fs @@ -8,7 +8,7 @@ open System open System.Net.Http [] -let Schema = "Schemas/petstore-v2.json" +let Schema = "https://petstore.swagger.io/v2/swagger.json" type PetStore = OpenApiClientProvider type PetStoreTask = OpenApiClientProvider @@ -20,7 +20,6 @@ type PetStoreControllerPrefix = OpenApiClientProvider] let ``Test provided Host property``() = @@ -97,27 +96,7 @@ let ``call provided methods``() = else exn.InnerException.Message - let hasResourceUnavailableMessage = - not(String.IsNullOrEmpty(msg)) - && msg.Contains(resourceUnavailableText) - - let hasResourceUnavailableDescription(oex: OpenApiException) = - not(isNull oex.Description) - && oex.Description.Contains(resourceUnavailableText) - - let isExternalConnectivityIssue = - match exn with - | :? HttpRequestException -> true - | :? AggregateException as aex -> - match aex.InnerException with - | :? HttpRequestException -> true - | :? OpenApiException as oex -> hasResourceUnavailableMessage || hasResourceUnavailableDescription oex - | _ -> false - | :? OpenApiException as oex -> hasResourceUnavailableMessage || hasResourceUnavailableDescription oex - | _ -> false - - if not isExternalConnectivityIssue then - failwith $"Adding pet failed with message: %s{msg}" + failwith $"Adding pet failed with message: %s{msg}" } [] diff --git a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj index 2929f3c2..a79af7dc 100644 --- a/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj +++ b/tests/SwaggerProvider.ProviderTests/SwaggerProvider.ProviderTests.fsproj @@ -11,7 +11,6 @@ false -