From 5acdd523eeca65f8dad9b80298939fe394912cf1 Mon Sep 17 00:00:00 2001 From: Sarangan Rajamanickam Date: Mon, 21 Oct 2024 11:26:32 -0700 Subject: [PATCH] [@azure-tools/azure-http-specs] - Modify code to handle http-client-* packages tests (#1711) This PR is the `typespec-azure` counterpart of the PR https://github.com/microsoft/typespec/pull/4799. These changes are required in the specs to handle the test success in `http-client-java`, `http-client-net` and `http-client-python` packages. The scenarios are also validated using the `test:e2e` script. Please review and approve the PR. Thanks --- packages/azure-http-specs/spec-summary.md | 12 ++-- .../client-generator-core/access/main.tsp | 22 +++--- .../client-generator-core/usage/main.tsp | 6 +- .../specs/azure/core/traits/mockapi.ts | 72 ++++++++++++++++++- 4 files changed, 91 insertions(+), 21 deletions(-) diff --git a/packages/azure-http-specs/spec-summary.md b/packages/azure-http-specs/spec-summary.md index a98087ea5e..8a104557cf 100644 --- a/packages/azure-http-specs/spec-summary.md +++ b/packages/azure-http-specs/spec-summary.md @@ -8,12 +8,12 @@ - `get /azure/client-generator-core/access/internalOperation/publicDecoratorInInternal` This scenario contains internal operations. All should be generated but not exposed. -Expected query parameter: name= +Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` @@ -24,12 +24,12 @@ Expected response body: - `get /azure/client-generator-core/access/publicOperation/publicDecoratorInPublic` This scenario contains public operations. It should be generated and exported. -Expected query parameter: name= +Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` @@ -48,12 +48,12 @@ This scenario contains internal operations. All should be generated but not expo - `get /azure/client-generator-core/access/sharedModelInOperation/internal` This scenario contains two operations, one public, another internal. The public one should be generated and exported while the internal one should be generated but not exposed. -Expected query parameter: name= +Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/access/main.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/access/main.tsp index 0310e2dc53..6540ba8a25 100644 --- a/packages/azure-http-specs/specs/azure/client-generator-core/access/main.tsp +++ b/packages/azure-http-specs/specs/azure/client-generator-core/access/main.tsp @@ -15,11 +15,11 @@ namespace _Specs_.Azure.ClientGenerator.Core.Access; @scenario @scenarioDoc(""" This scenario contains public operations. It should be generated and exported. - Expected query parameter: name= + Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` """) @@ -51,11 +51,11 @@ namespace PublicOperation { @scenario @scenarioDoc(""" This scenario contains internal operations. All should be generated but not exposed. - Expected query parameter: name= + Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` """) @@ -98,11 +98,11 @@ namespace InternalOperation { @scenario @scenarioDoc(""" This scenario contains two operations, one public, another internal. The public one should be generated and exported while the internal one should be generated but not exposed. - Expected query parameter: name= + Expected query parameter: name="sample" Expected response body: ```json { - "name": + "name": "sample" } ``` """) @@ -157,14 +157,14 @@ namespace RelativeModelInOperation { } @doc(""" - Expected query parameter: name= + Expected query parameter: name="Madge" Expected response body: ```json { - "name": , + "name": "Madge", "inner": { - "name": + "name": "Madge" } } ``` @@ -175,11 +175,11 @@ namespace RelativeModelInOperation { op operation(@query name: string): OuterModel; @doc(""" - Expected query parameter: kind= + Expected query parameter: kind="real" Expected response body: ```json { - "name": , + "name": "real", "kind": "real" } ``` diff --git a/packages/azure-http-specs/specs/azure/client-generator-core/usage/main.tsp b/packages/azure-http-specs/specs/azure/client-generator-core/usage/main.tsp index ab01fd37c2..0e154c9747 100644 --- a/packages/azure-http-specs/specs/azure/client-generator-core/usage/main.tsp +++ b/packages/azure-http-specs/specs/azure/client-generator-core/usage/main.tsp @@ -28,7 +28,7 @@ namespace ModelInOperation { Expected body parameter: ```json { - "name": + "name": "Madge" } ``` """) @@ -48,7 +48,7 @@ namespace ModelInOperation { Expected response body: ```json { - "name": + "name": "Madge" } ``` """) @@ -78,7 +78,7 @@ namespace ModelInOperation { ```json { "result": { - "name": + "name": "Madge" } } ``` diff --git a/packages/azure-http-specs/specs/azure/core/traits/mockapi.ts b/packages/azure-http-specs/specs/azure/core/traits/mockapi.ts index c68ce4f6cb..5895300737 100644 --- a/packages/azure-http-specs/specs/azure/core/traits/mockapi.ts +++ b/packages/azure-http-specs/specs/azure/core/traits/mockapi.ts @@ -1,4 +1,11 @@ -import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api"; +import { + json, + MockRequest, + passOnSuccess, + ScenarioMockApi, + validateValueFormat, + ValidationError, +} from "@typespec/spec-api"; export const Scenarios: Record = {}; @@ -32,6 +39,39 @@ Scenarios.Azure_Core_Traits_smokeTest = passOnSuccess({ "x-ms-client-request-id": "86aede1f-96fa-4e7f-b1e1-bf8a947cb804", }, }, + handler: (req: MockRequest) => { + if (!("x-ms-client-request-id" in req.headers)) { + throw new ValidationError( + "Should submit header x-ms-client-request-id", + "any uuid", + undefined, + ); + } + if (req.params.id !== "1") { + throw new ValidationError("Expected path param id=1", "1", req.params.id); + } + req.expect.containsHeader("foo", "123"); + const if_none_match = req.headers["if-none-match"]; + const if_match = req.headers["if-match"]; + if (if_none_match !== '"invalid"' && if_match !== '"valid"') { + throw new ValidationError( + `Expected header "if-none-match" equals "invalid" but got ${if_none_match} or "if-match" equals "valid" but got ${if_match}`, + `"if-match": "valid" or "if-none-match": "invalid"`, + `"if-match": ${if_match} or "if-none-match": ${if_none_match}`, + ); + } + req.expect.containsHeader("if-unmodified-since", "Fri, 26 Aug 2022 14:38:00 GMT"); + req.expect.containsHeader("if-modified-since", "Thu, 26 Aug 2021 14:38:00 GMT"); + return { + status: 200, + body: json(validUser), + headers: { + bar: "456", + etag: "11bdc430-65e8-45ad-81d9-8ffa60d55b59", + "x-ms-client-request-id": req.headers["x-ms-client-request-id"], + }, + }; + }, kind: "MockApiDefinition", }); @@ -57,5 +97,35 @@ Scenarios.Azure_Core_Traits_repeatableAction = passOnSuccess({ "repeatability-result": "accepted", }, }, + handler: (req: MockRequest) => { + if (req.params.id !== "1") { + throw new ValidationError("Expected path param id=1", "1", req.params.id); + } + + if (!("repeatability-request-id" in req.headers)) { + throw new ValidationError("Repeatability-Request-ID is missing", "A UUID string", undefined); + } + if (!("repeatability-first-sent" in req.headers)) { + throw new ValidationError( + "Repeatability-First-Sent is missing", + "A date-time in headers format", + undefined, + ); + } + + validateValueFormat(req.headers["repeatability-request-id"], "uuid"); + validateValueFormat(req.headers["repeatability-first-sent"], "rfc7231"); + + const validBody = { userActionValue: "test" }; + req.expect.bodyEquals(validBody); + + return { + status: 200, + body: json({ userActionResult: "test" }), + headers: { + "repeatability-result": "accepted", + }, + }; + }, kind: "MockApiDefinition", });