From 0d45c78b6cc9ab72e31d89887ccc296d3ca1062d Mon Sep 17 00:00:00 2001 From: Jorge Rangel <102122018+jorgerangel-msft@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:09:40 -0600 Subject: [PATCH] [http-client-csharp] Generate all req. response classifiers (#5174) This PR adds support for generating all the required response classifiers for the generated client. fixes: https://github.com/microsoft/typespec/issues/4865 contributes to: https://github.com/microsoft/typespec/issues/4903 --- .../Abstractions/StatusCodeClassifierApi.cs | 2 + .../Classifier2xxAnd4xxDefinition.cs | 104 ------- .../PipelineMessageClassifierProvider.cs | 7 +- .../src/Providers/RestClientProvider.cs | 176 +++++------ .../Classifier2xxAnd4xxDefinitionTests.cs | 61 ---- .../RestClientProviderTests.cs | 275 ++++++++++++++---- .../CanChangeClientNamespace.cs | 43 --- .../ValidateAllClientResponseClassifiers.cs | 164 +++++++++++ .../test/common/InputFactory.cs | 5 +- .../UnbrandedTypeSpecClient.RestClient.cs | 36 +-- 10 files changed, 480 insertions(+), 393 deletions(-) delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Classifier2xxAnd4xxDefinition.cs delete mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Definitions/Classifier2xxAnd4xxDefinitionTests.cs create mode 100644 packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/ValidateAllClientResponseClassifiers.cs diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/StatusCodeClassifierApi.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/StatusCodeClassifierApi.cs index 1414b0f97f..ed545b6ea3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/StatusCodeClassifierApi.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Abstractions/StatusCodeClassifierApi.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using Microsoft.Generator.CSharp.Expressions; using Microsoft.Generator.CSharp.Primitives; using Microsoft.Generator.CSharp.Snippets; @@ -17,6 +18,7 @@ public StatusCodeClassifierApi(Type type, ValueExpression original) : base(type, public abstract CSharpType ResponseClassifierType { get; } public abstract ValueExpression Create(int code); + public abstract ValueExpression Create(IEnumerable codes); public abstract StatusCodeClassifierApi FromExpression(ValueExpression original); public abstract StatusCodeClassifierApi ToExpression(); } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Classifier2xxAnd4xxDefinition.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Classifier2xxAnd4xxDefinition.cs deleted file mode 100644 index 81d3330b88..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/Classifier2xxAnd4xxDefinition.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// cspell:ignore Retryable - -using System; -using System.ClientModel.Primitives; -using System.IO; -using Microsoft.Generator.CSharp.Expressions; -using Microsoft.Generator.CSharp.Primitives; -using Microsoft.Generator.CSharp.Providers; -using Microsoft.Generator.CSharp.Snippets; -using Microsoft.Generator.CSharp.Statements; -using static Microsoft.Generator.CSharp.Snippets.Snippet; - -namespace Microsoft.Generator.CSharp.ClientModel.Providers -{ - internal class Classifier2xxAnd4xxDefinition : TypeProvider - { - public Classifier2xxAnd4xxDefinition(TypeProvider declaringType) - { - DeclaringTypeProvider = declaringType; - } - - protected override string BuildName() => "Classifier2xxAnd4xx"; - - protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{DeclaringTypeProvider!.Name}.RestClient.cs"); - - protected override TypeSignatureModifiers GetDeclarationModifiers() - => TypeSignatureModifiers.Private | TypeSignatureModifiers.Class; - - protected override MethodProvider[] BuildMethods() - { - // TODO: Is there a better way to implement the methods? - return ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType.FrameworkType == typeof(PipelineMessageClassifier) - ? [BuildTryClassifyErrorMethod(), BuildTryClassifyRetryMethod()] - : []; - } - - protected override string GetNamespace() => DeclaringTypeProvider!.Type.Namespace; - - protected override CSharpType[] BuildImplements() - { - return [ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType]; - } - - private MethodProvider BuildTryClassifyRetryMethod() - { - var messageParam = new ParameterProvider("message", FormattableStringHelpers.Empty, typeof(PipelineMessage)); - var exceptionParam = new ParameterProvider("exception", FormattableStringHelpers.Empty, typeof(Exception)); - var isRetryableParam = new ParameterProvider("isRetryable", FormattableStringHelpers.Empty, typeof(bool), isOut: true); - var signature = new MethodSignature( - "TryClassify", - FormattableStringHelpers.Empty, - MethodSignatureModifiers.Public | MethodSignatureModifiers.Override, - typeof(bool), - null, - [messageParam, exceptionParam, isRetryableParam]); - return new MethodProvider( - signature, - new MethodBodyStatements( - [ - isRetryableParam.Assign(False).Terminate(), - Return(False) - ]), - this); - } - - private MethodProvider BuildTryClassifyErrorMethod() - { - var messageParam = new ParameterProvider("message", FormattableStringHelpers.Empty, typeof(PipelineMessage)); - var isErrorParam = new ParameterProvider("isError", FormattableStringHelpers.Empty, typeof(bool), isOut: true); - var signature = new MethodSignature( - "TryClassify", - FormattableStringHelpers.Empty, - MethodSignatureModifiers.Public | MethodSignatureModifiers.Override, - typeof(bool), - null, - [messageParam, isErrorParam]); - return new MethodProvider( - signature, - new MethodBodyStatements( - [ - isErrorParam.Assign(False).Terminate(), - new IfStatement(messageParam.Property("Response").Equal(Null)) - { - Return(False) - }, - isErrorParam.Assign(new SwitchExpression(messageParam.Property("Response").Property("Status"), - [ - new SwitchCaseExpression( - ValueExpression.Empty.GreaterThanOrEqual(Literal(200)).AndExpr(ValueExpression.Empty.LessThan(Literal(300))), - False), - new SwitchCaseExpression( - ValueExpression.Empty.GreaterThanOrEqual(Literal(400)).AndExpr(ValueExpression.Empty.LessThan(Literal(500))), - False), - SwitchCaseExpression.Default(True) - ])).Terminate(), - Return(True) - ]), - this); - } - } -} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/PipelineMessageClassifierProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/PipelineMessageClassifierProvider.cs index 2e1f4ea702..dcb3407ec3 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/PipelineMessageClassifierProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/PipelineMessageClassifierProvider.cs @@ -5,6 +5,8 @@ using static Microsoft.Generator.CSharp.Snippets.Snippet; using System.ClientModel.Primitives; using Microsoft.Generator.CSharp.Primitives; +using System.Collections.Generic; +using System.Linq; namespace Microsoft.Generator.CSharp.ClientModel.Providers { @@ -20,7 +22,10 @@ public PipelineMessageClassifierProvider(ValueExpression original) : base(typeof public override CSharpType ResponseClassifierType => typeof(PipelineMessageClassifier); public override ValueExpression Create(int code) - => Static().Invoke(nameof(PipelineMessageClassifier.Create), [New.Array(typeof(ushort), true, true, [Literal(code)])]); + => Create([code]); + + public override ValueExpression Create(IEnumerable codes) + => Static().Invoke(nameof(PipelineMessageClassifier.Create), [New.Array(typeof(ushort), true, true, [.. codes.Select(Literal)])]); public override StatusCodeClassifierApi FromExpression(ValueExpression original) => new PipelineMessageClassifierProvider(original); diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs index df0bb55918..7c597bf4c8 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/RestClientProvider.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; -using System.Net.Http; using Microsoft.Generator.CSharp.ClientModel.Primitives; using Microsoft.Generator.CSharp.ClientModel.Snippets; using Microsoft.Generator.CSharp.Expressions; @@ -31,88 +30,41 @@ public class RestClientProvider : TypeProvider private Dictionary? _methodCache; private Dictionary MethodCache => _methodCache ??= []; + private readonly Dictionary, PropertyProvider> _pipelineMessage20xClassifiers; private readonly InputClient _inputClient; - internal ClientProvider ClientProvider { get; } - - private FieldProvider _pipelineMessageClassifier200; - private FieldProvider _pipelineMessageClassifier201; - private FieldProvider _pipelineMessageClassifier202; - private FieldProvider _pipelineMessageClassifier204; - private FieldProvider _pipelineMessageClassifier2xxAnd4xx; - private TypeProvider _classifier2xxAnd4xxDefinition; - - private PropertyProvider _classifier201Property; - private PropertyProvider _classifier200Property; - private PropertyProvider _classifier202Property; - private PropertyProvider _classifier204Property; - private PropertyProvider _classifier2xxAnd4xxProperty; public RestClientProvider(InputClient inputClient, ClientProvider clientProvider) { _inputClient = inputClient; ClientProvider = clientProvider; - _pipelineMessageClassifier200 = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, "_pipelineMessageClassifier200", this); - _pipelineMessageClassifier201 = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, "_pipelineMessageClassifier201", this); - _pipelineMessageClassifier202 = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, "_pipelineMessageClassifier202", this); - _pipelineMessageClassifier204 = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, "_pipelineMessageClassifier204", this); - _classifier2xxAnd4xxDefinition = new Classifier2xxAnd4xxDefinition(this); - _pipelineMessageClassifier2xxAnd4xx = new FieldProvider(FieldModifiers.Private | FieldModifiers.Static, _classifier2xxAnd4xxDefinition.Type, "_pipelineMessageClassifier2xxAnd4xx", this); - _classifier200Property = GetResponseClassifierProperty(_pipelineMessageClassifier200, 200); - _classifier201Property = GetResponseClassifierProperty(_pipelineMessageClassifier201, 201); - _classifier202Property = GetResponseClassifierProperty(_pipelineMessageClassifier202, 202); - _classifier204Property = GetResponseClassifierProperty(_pipelineMessageClassifier204, 204); - _classifier2xxAnd4xxProperty = new PropertyProvider( - $"Gets the PipelineMessageClassifier2xxAnd4xx", - MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, - _classifier2xxAnd4xxDefinition.Type, - "PipelineMessageClassifier2xxAnd4xx", - new ExpressionPropertyBody(_pipelineMessageClassifier2xxAnd4xx.Assign(New.Instance(_classifier2xxAnd4xxDefinition.Type), true)), - this); + _pipelineMessage20xClassifiers = BuildPipelineMessage20xClassifiers(); } + internal ClientProvider ClientProvider { get; } + protected override string BuildRelativeFilePath() => Path.Combine("src", "Generated", $"{Name}.RestClient.cs"); protected override string BuildName() => _inputClient.Name.ToCleanName(); protected override PropertyProvider[] BuildProperties() { - return - [ - _classifier200Property, - _classifier201Property, - _classifier202Property, - _classifier204Property, - _classifier2xxAnd4xxProperty - ]; - } - - private PropertyProvider GetResponseClassifierProperty(FieldProvider pipelineMessageClassifier, int code) - { - return new PropertyProvider( - null, - MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, - ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, - pipelineMessageClassifier.Name.Substring(1).ToCleanName(), - new ExpressionPropertyBody( - pipelineMessageClassifier.Assign(This.ToApi().Create(code))), - this); + return [.. _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name)]; } protected override FieldProvider[] BuildFields() { - return - [ - _pipelineMessageClassifier200, - _pipelineMessageClassifier201, - _pipelineMessageClassifier202, - _pipelineMessageClassifier204, - _pipelineMessageClassifier2xxAnd4xx - ]; - } + List pipelineMessage20xClassifiersFields = new(_pipelineMessage20xClassifiers.Count); + var orderedClassifierProperties = _pipelineMessage20xClassifiers.Values.OrderBy(v => v.Name); - protected override TypeProvider[] BuildNestedTypes() - { - return [_classifier2xxAnd4xxDefinition]; + foreach (var classifierProperty in orderedClassifierProperties) + { + if (classifierProperty.BackingField != null) + { + pipelineMessage20xClassifiersFields.Add(classifierProperty.BackingField); + } + } + + return [.. pipelineMessage20xClassifiersFields]; } protected override MethodProvider[] BuildMethods() @@ -129,12 +81,6 @@ protected override MethodProvider[] BuildMethods() return [.. methods]; } - private bool IsCreateRequest(MethodProvider method) - { - var span = method.Signature.Name.AsSpan(); - return span.StartsWith("Create", StringComparison.Ordinal) && span.EndsWith("Request", StringComparison.Ordinal); - } - private MethodProvider BuildCreateRequestMethod(InputOperation operation) { var pipelineField = ClientProvider.PipelineProperty.ToApi(); @@ -186,26 +132,50 @@ private IReadOnlyList GetSetContent(HttpRequestApi request, return contentParam is null ? [] : [request.Content().Assign(contentParam).Terminate()]; } - private PropertyProvider GetClassifier(InputOperation operation) + private Dictionary, PropertyProvider> BuildPipelineMessage20xClassifiers() { - if (operation.HttpMethod == HttpMethod.Head.ToString()) - return _classifier2xxAnd4xxProperty; + // Contains a mapping of classifier status codes to their corresponding pipeline message classifier property + Dictionary, PropertyProvider> classifiers = new(new StatusCodesComparer()); - var response = operation.Responses.First(r => !r.IsErrorResponse); //should only be one of these - - if (response.StatusCodes.Count == 1) + foreach (var inputOperation in _inputClient.Operations) { - return response.StatusCodes[0] switch + var statusCodes = GetSuccessStatusCodes(inputOperation); + if (statusCodes.Count > 0 && !classifiers.ContainsKey(statusCodes)) { - 200 => _classifier200Property, - 201 => _classifier201Property, - 202 => _classifier202Property, - 204 => _classifier204Property, - _ => throw new InvalidOperationException($"Unexpected status code {response.StatusCodes[0]}") - }; + var classifierNameSuffix = string.Join(string.Empty, statusCodes); + var classifierBackingField = new FieldProvider( + FieldModifiers.Private | FieldModifiers.Static, + ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, + $"_pipelineMessageClassifier{classifierNameSuffix}", + this); + + var classifierProperty = new PropertyProvider( + null, + MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, + ClientModelPlugin.Instance.TypeFactory.StatusCodeClassifierApi.ResponseClassifierType, + classifierBackingField.Name.Substring(1).ToCleanName(), + new ExpressionPropertyBody( + classifierBackingField.Assign(This.ToApi().Create(GetSuccessStatusCodes(inputOperation)))), + this) + { + BackingField = classifierBackingField + }; + + classifiers[statusCodes] = classifierProperty; + } } - throw new InvalidOperationException("Multiple status codes not supported"); + return classifiers; + } + + private PropertyProvider GetClassifier(InputOperation operation) + { + if (_pipelineMessage20xClassifiers.TryGetValue(GetSuccessStatusCodes(operation), out var classifier)) + { + return classifier; + } + + throw new InvalidOperationException($"Unexpected status codes for operation {operation.Name}"); } private IEnumerable AppendHeaderParameters(HttpRequestApi request, InputOperation operation, Dictionary paramMap) @@ -509,6 +479,26 @@ private static bool TryGetSpecialHeaderParam(InputParameter inputParameter, [Not return false; } + private static List GetSuccessStatusCodes(InputOperation operation) + { + HashSet statusCodes = []; + foreach (var response in operation.Responses) + { + if (response.IsErrorResponse) + continue; + + foreach (var statusCode in response.StatusCodes) + { + if (statusCode >= 200 && statusCode < 300) + { + statusCodes.Add(statusCode); + } + } + } + + return [.. statusCodes.OrderBy(i => i)]; + } + internal MethodProvider GetCreateRequestMethod(InputOperation operation) { _ = Methods; // Ensure methods are built @@ -637,5 +627,23 @@ internal enum MethodType Protocol, Convenience } + + private class StatusCodesComparer : IEqualityComparer> + { + bool IEqualityComparer>.Equals(List? x, List? y) + { + return x != null && y != null && x.SequenceEqual(y); + } + + int IEqualityComparer>.GetHashCode(List obj) + { + HashCode hash = new(); + foreach (var item in obj) + { + hash.Add(item); + } + return hash.ToHashCode(); + } + } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Definitions/Classifier2xxAnd4xxDefinitionTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Definitions/Classifier2xxAnd4xxDefinitionTests.cs deleted file mode 100644 index 67b6ab2212..0000000000 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/Definitions/Classifier2xxAnd4xxDefinitionTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Generator.CSharp.ClientModel.Providers; -using Microsoft.Generator.CSharp.Tests.Common; -using NUnit.Framework; - -namespace Microsoft.Generator.CSharp.ClientModel.Tests.Providers.Definitions -{ - public class Classifier2xxAnd4xxDefinitionTests - { - [TestCaseSource(nameof(GetTypeNamespaceTestCases))] - public void TestGetTypeNamespace(string mockJson) - { - MockHelpers.LoadMockPlugin(configuration: mockJson); - var inputClient = InputFactory.Client("TestClient"); - var restClientProvider = new ClientProvider(inputClient).RestClient; - Assert.IsNotNull(restClientProvider); - - var classifier2xxAnd4xxDefinition = new Classifier2xxAnd4xxDefinition(restClientProvider); - var result = classifier2xxAnd4xxDefinition.Type.Namespace; - - Assert.AreEqual(restClientProvider.Type.Namespace, result); - } - - [Test] - public async Task TestGetTypeCustomNamespace() - { - var inputClient = InputFactory.Client("TestClient"); - var plugin = await MockHelpers.LoadMockPluginAsync( - clients: () => [inputClient], - compilation: async () => await Helpers.GetCompilationFromDirectoryAsync()); - - // Find the rest client provider - var clientProvider = plugin.Object.OutputLibrary.TypeProviders.SingleOrDefault(t => t is ClientProvider); - Assert.IsNotNull(clientProvider); - var restClientProvider = (clientProvider as ClientProvider)!.RestClient; - Assert.IsNotNull(restClientProvider); - - var classifier2xxAnd4xxDefinition = new Classifier2xxAnd4xxDefinition(restClientProvider!); - var result = classifier2xxAnd4xxDefinition.Type.Namespace; - - Assert.AreEqual(restClientProvider!.Type.Namespace, result); - } - - public static IEnumerable GetTypeNamespaceTestCases - { - get - { - yield return new TestCaseData(@"{ - ""output-folder"": ""outputFolder"", - ""library-name"": ""libraryName"", - ""namespace"": ""testNamespace"" - }"); - } - } - } -} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs index 3a1b883d6f..dc6aa4525b 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/RestClientProviderTests.cs @@ -73,26 +73,10 @@ public void ValidateFields() Assert.AreEqual("_pipelineMessageClassifier200", pipelineMessageClassifier200.Name); Assert.AreEqual(FieldModifiers.Private | FieldModifiers.Static, pipelineMessageClassifier200.Modifiers); - //validate _pipelineMessageClassifier201 - Assert.IsTrue(fieldHash.ContainsKey("_pipelineMessageClassifier201")); - var pipelineMessageClassifier201 = fieldHash["_pipelineMessageClassifier201"]; - Assert.AreEqual("PipelineMessageClassifier", pipelineMessageClassifier201.Type.Name); - Assert.AreEqual("_pipelineMessageClassifier201", pipelineMessageClassifier201.Name); - Assert.AreEqual(FieldModifiers.Private | FieldModifiers.Static, pipelineMessageClassifier201.Modifiers); - - //validate _pipelineMessageClassifier204 - Assert.IsTrue(fieldHash.ContainsKey("_pipelineMessageClassifier204")); - var pipelineMessageClassifier204 = fieldHash["_pipelineMessageClassifier204"]; - Assert.AreEqual("PipelineMessageClassifier", pipelineMessageClassifier204.Type.Name); - Assert.AreEqual("_pipelineMessageClassifier204", pipelineMessageClassifier204.Name); - Assert.AreEqual(FieldModifiers.Private | FieldModifiers.Static, pipelineMessageClassifier204.Modifiers); - - //validate _pipelineMessageClassifier2xxAnd4xx - Assert.IsTrue(fieldHash.ContainsKey("_pipelineMessageClassifier2xxAnd4xx")); - var pipelineMessageClassifier2xxAnd4xx = fieldHash["_pipelineMessageClassifier2xxAnd4xx"]; - Assert.AreEqual("Classifier2xxAnd4xx", pipelineMessageClassifier2xxAnd4xx.Type.Name); - Assert.AreEqual("_pipelineMessageClassifier2xxAnd4xx", pipelineMessageClassifier2xxAnd4xx.Name); - Assert.AreEqual(FieldModifiers.Private | FieldModifiers.Static, pipelineMessageClassifier2xxAnd4xx.Modifiers); + //validate _pipelineMessageClassifier201 isn't present + Assert.IsFalse(fieldHash.ContainsKey("_pipelineMessageClassifier201")); + //validate _pipelineMessageClassifier204 isn't present + Assert.IsFalse(fieldHash.ContainsKey("_pipelineMessageClassifier204")); } [Test] @@ -109,29 +93,10 @@ public void ValidateProperties() Assert.AreEqual(MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, pipelineMessageClassifier200.Modifiers); Assert.IsFalse(pipelineMessageClassifier200.Body.HasSetter); - //validate _pipelineMessageClassifier201 - Assert.IsTrue(propertyHash.ContainsKey("PipelineMessageClassifier201")); - var pipelineMessageClassifier201 = propertyHash["PipelineMessageClassifier201"]; - Assert.AreEqual("PipelineMessageClassifier", pipelineMessageClassifier201.Type.Name); - Assert.AreEqual("PipelineMessageClassifier201", pipelineMessageClassifier201.Name); - Assert.AreEqual(MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, pipelineMessageClassifier201.Modifiers); - Assert.IsFalse(pipelineMessageClassifier201.Body.HasSetter); - - //validate _pipelineMessageClassifier204 - Assert.IsTrue(propertyHash.ContainsKey("PipelineMessageClassifier204")); - var pipelineMessageClassifier204 = propertyHash["PipelineMessageClassifier204"]; - Assert.AreEqual("PipelineMessageClassifier", pipelineMessageClassifier204.Type.Name); - Assert.AreEqual("PipelineMessageClassifier204", pipelineMessageClassifier204.Name); - Assert.AreEqual(MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, pipelineMessageClassifier204.Modifiers); - Assert.IsFalse(pipelineMessageClassifier204.Body.HasSetter); - - //validate _pipelineMessageClassifier2xxAnd4xx - Assert.IsTrue(propertyHash.ContainsKey("PipelineMessageClassifier2xxAnd4xx")); - var pipelineMessageClassifier2xxAnd4xx = propertyHash["PipelineMessageClassifier2xxAnd4xx"]; - Assert.AreEqual("Classifier2xxAnd4xx", pipelineMessageClassifier2xxAnd4xx.Type.Name); - Assert.AreEqual("PipelineMessageClassifier2xxAnd4xx", pipelineMessageClassifier2xxAnd4xx.Name); - Assert.AreEqual(MethodSignatureModifiers.Private | MethodSignatureModifiers.Static, pipelineMessageClassifier2xxAnd4xx.Modifiers); - Assert.IsFalse(pipelineMessageClassifier2xxAnd4xx.Body.HasSetter); + //validate _pipelineMessageClassifier201 isn't present + Assert.IsFalse(propertyHash.ContainsKey("PipelineMessageClassifier201")); + //validate _pipelineMessageClassifier204 isn't present + Assert.IsFalse(propertyHash.ContainsKey("PipelineMessageClassifier204")); } [TestCaseSource(nameof(GetMethodParametersTestCases))] @@ -256,26 +221,112 @@ public void ValidateClientWithApiVersionPathParameter(InputClient inputClient) public void ValidateClientResponseClassifiers(InputClient inputClient) { var restClientProvider = new ClientProvider(inputClient).RestClient; - var method = restClientProvider.Methods.FirstOrDefault(m => m.Signature.Name == "CreateTestOperationRequest"); - Assert.IsNotNull(method); + Dictionary fieldHash = restClientProvider.Fields.ToDictionary(f => f.Name); + Dictionary propertyHash = restClientProvider.Properties.ToDictionary(p => p.Name); - var bodyStatements = method?.BodyStatements as MethodBodyStatements; - Assert.IsNotNull(bodyStatements); - /* verify that the expected classifier is present in the body */ - var inputOp = inputClient.Operations.FirstOrDefault(); - Assert.IsNotNull(inputOp); - var expectedStatusCode = inputOp!.Responses.FirstOrDefault()?.StatusCodes.FirstOrDefault(); - Assert.IsNotNull(expectedStatusCode); - if (expectedStatusCode == 201) + foreach (var inputOperation in inputClient.Operations) + { + List expectedStatusCodes = []; + foreach (var response in inputOperation.Responses) + { + if (response.IsErrorResponse) + continue; + expectedStatusCodes.AddRange(response.StatusCodes); + } + + Assert.IsTrue(expectedStatusCodes.Count > 0); + + var classifierNameSuffix = string.Join(string.Empty, expectedStatusCodes.OrderBy(s => s)); + Assert.IsNotEmpty(classifierNameSuffix); + + // validate fields + Assert.IsTrue(fieldHash.ContainsKey($"_pipelineMessageClassifier{classifierNameSuffix}")); + // validate properties + Assert.IsTrue(propertyHash.ContainsKey($"PipelineMessageClassifier{classifierNameSuffix}")); + + // verify that the expected classifier is present in the CreateRequest method body + var method = restClientProvider.Methods.FirstOrDefault(m => m.Signature.Name == $"CreateTestOperation{classifierNameSuffix}Request"); + Assert.IsNotNull(method); + + var bodyStatements = method?.BodyStatements as MethodBodyStatements; + Assert.IsNotNull(bodyStatements); + + ValidateResponseClassifier(bodyStatements!, classifierNameSuffix); + } + } + + // This test validates that all the success status codes have their respective classifiers generated. + [Test] + public void ValidateAllClientResponseClassifiers() + { + var inputClient = InputFactory.Client( + "TestClient", + operations: + [ + OperationWith204Resp, + OperationWith205Resp, + OperationWith206Resp, + OperationWith200Resp, + OperationWith202Resp, + OperationWith201Resp, + OperationWith203Resp, + OperationWith200201202Resp, + OperationWith200201202Resp_Duplicate + ]); + var restClientProvider = new ClientProvider(inputClient).RestClient; + var writer = new TypeProviderWriter(restClientProvider); + var file = writer.Write(); + + Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); + } + + // validates no duplicate properties or fields are generated for the same status codes. + [TestCaseSource(nameof(TestResponseClassifiersDuplicationTestCases))] + public void TestResponseClassifierDuplication(InputClient inputClient) + { + var restClientProvider = new ClientProvider(inputClient).RestClient; + var classifierFields = restClientProvider.Fields.Where(f => f.Name.StartsWith("_pipelineMessageClassifier")).ToList(); + var classifierProperties = restClientProvider.Properties.Where(p => p.Name.StartsWith("PipelineMessageClassifier")).ToList(); + + Assert.AreEqual(4, classifierFields.Count); + Assert.AreEqual(4, classifierProperties.Count); + + Assert.IsTrue(classifierFields.Any(f => f.Name == "_pipelineMessageClassifier200")); + Assert.IsTrue(classifierFields.Any(f => f.Name == "_pipelineMessageClassifier201202")); + Assert.IsTrue(classifierFields.Any(f => f.Name == "_pipelineMessageClassifier201204")); + Assert.IsTrue(classifierFields.Any(f => f.Name == "_pipelineMessageClassifier200201204")); + + Assert.IsTrue(classifierProperties.Any(p => p.Name == "PipelineMessageClassifier200")); + Assert.IsTrue(classifierProperties.Any(p => p.Name == "PipelineMessageClassifier201202")); + Assert.IsTrue(classifierProperties.Any(p => p.Name == "PipelineMessageClassifier201204")); + Assert.IsTrue(classifierProperties.Any(p => p.Name == "PipelineMessageClassifier200201204")); + } + + [Test] + public void ValidateGetResponseClassifiersThrowsWhenNoSuccess() + { + var inputOp = InputFactory.Operation( + "TestOperation", + responses: [InputFactory.OperationResponse([500])]); + var inputClient = InputFactory.Client( + "TestClient", + operations: [inputOp]); + Assert.IsNotNull(inputClient); + + var restClientProvider = new ClientProvider(inputClient).RestClient; + Assert.IsNotNull(restClientProvider); + + try { - Assert.IsTrue(bodyStatements!.Statements.Any(s => s.ToDisplayString() == "message.ResponseClassifier = PipelineMessageClassifier201;\n")); - Assert.IsFalse(bodyStatements!.Statements.Any(s => s.ToDisplayString() == "message.ResponseClassifier = PipelineMessageClassifier200;\n")); + var methods = restClientProvider.Methods; } - else if (expectedStatusCode == 200) + catch (InvalidOperationException e) { - Assert.IsTrue(bodyStatements!.Statements.Any(s => s.ToDisplayString() == "message.ResponseClassifier = PipelineMessageClassifier200;\n")); - Assert.IsFalse(bodyStatements!.Statements.Any(s => s.ToDisplayString() == "message.ResponseClassifier = PipelineMessageClassifier201;\n")); + Assert.AreEqual($"Unexpected status codes for operation {inputOp.Name}", e.Message); + return; } + + Assert.Fail("Expected Exception to be thrown."); } [Test] @@ -307,6 +358,14 @@ public void TestBuildCreateRequestMethodWithQueryParameters() Assert.AreEqual(Helpers.GetExpectedFromFile(), file.Content); } + private static void ValidateResponseClassifier(MethodBodyStatements bodyStatements, string parsedStatusCodes) + { + var classifier = $"PipelineMessageClassifier{parsedStatusCodes}"; + var classifierStatement = $"message.ResponseClassifier = {classifier};\n"; + + Assert.IsTrue(bodyStatements.Statements.Any(s => s.ToDisplayString() == classifierStatement)); + } + private readonly static InputOperation BasicOperation = InputFactory.Operation( "CreateMessage", parameters: @@ -326,21 +385,75 @@ public void TestBuildCreateRequestMethodWithQueryParameters() InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) ]); + private static readonly InputOperation OperationWith200Resp = InputFactory.Operation( + "TestOperation200", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([200])]); + private static readonly InputOperation OperationWith200201202Resp = InputFactory.Operation( + "TestOperation200201202", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([201, 200, 202])]); + private static readonly InputOperation OperationWith200201202Resp_Duplicate = InputFactory.Operation( + "DuplicateTestOperation200201202", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([201, 200, 202])]); + private static readonly InputOperation OperationWith201Resp = InputFactory.Operation( - "TestOperation", + "TestOperation201", parameters: [ InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) ], responses: [InputFactory.OperationResponse([201])]); - private static readonly InputOperation OperationWith200Resp = InputFactory.Operation( - "TestOperation", + private static readonly InputOperation OperationWith202Resp = InputFactory.Operation( + "TestOperation202", parameters: [ InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) ], - responses: [InputFactory.OperationResponse([200])]); + responses: [InputFactory.OperationResponse([202])]); + + private static readonly InputOperation OperationWith203Resp = InputFactory.Operation( + "TestOperation203", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([203])]); + + private static readonly InputOperation OperationWith204Resp = InputFactory.Operation( + "TestOperation204", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([204])]); + + private static readonly InputOperation OperationWith205Resp = InputFactory.Operation( + "TestOperation205", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([205])]); + + private static readonly InputOperation OperationWith206Resp = InputFactory.Operation( + "TestOperation206", + parameters: + [ + InputFactory.Parameter("message", InputPrimitiveType.Boolean, isRequired: true) + ], + responses: [InputFactory.OperationResponse([206])]); private readonly static InputOperation OperationWithSpreadParam = InputFactory.Operation( "CreateMessageWithSpread", @@ -455,8 +568,44 @@ public void TestBuildCreateRequestMethodWithQueryParameters() private static IEnumerable ValidateClientResponseClassifiersTestCases => [ + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith200Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith200201202Resp])), new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith201Resp])), - new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith200Resp])) + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith202Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith203Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith204Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith205Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith206Resp])), + new TestCaseData(InputFactory.Client("TestClient", operations: [OperationWith203Resp, OperationWith200Resp, OperationWith202Resp])), + ]; + + private static IEnumerable TestResponseClassifiersDuplicationTestCases => + [ + new TestCaseData(InputFactory.Client("TestClient", operations: + [ + // _pipelineMessageClassifier200 + InputFactory.Operation("TestOperation200", + responses: [InputFactory.OperationResponse([200])]), + InputFactory.Operation("TestOperation200_1", + responses: [InputFactory.OperationResponse([200])]), + // _pipelineMessageClassifier201202 + InputFactory.Operation("TestOperation202201", + responses: [InputFactory.OperationResponse([201, 202])]), + InputFactory.Operation("TestOperation202201_1", + responses: [InputFactory.OperationResponse([201, 202])]), + InputFactory.Operation("TestOperation202_201", + responses: [InputFactory.OperationResponse([202]), InputFactory.OperationResponse([201])]), + InputFactory.Operation("TestOperation202_201_1", + responses: [InputFactory.OperationResponse([202]), InputFactory.OperationResponse([201])]), + // _pipelineMessageClassifier201204 + InputFactory.Operation("TestOperation204_201", + responses: [InputFactory.OperationResponse([204]), InputFactory.OperationResponse([201])]), + InputFactory.Operation("TestOperation204_201_1", + responses: [InputFactory.OperationResponse([201]), InputFactory.OperationResponse([204])]), + // _pipelineMessageClassifier200202204 + InputFactory.Operation("TestOperation200_201_204", + responses: [InputFactory.OperationResponse([204]), InputFactory.OperationResponse([201]), InputFactory.OperationResponse([200])]), + ])) ]; private static IEnumerable GetSpreadParameterModelTestCases => diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderCustomizationTests/CanChangeClientNamespace.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderCustomizationTests/CanChangeClientNamespace.cs index 3edc8fd499..04bdf42158 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderCustomizationTests/CanChangeClientNamespace.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderCustomizationTests/CanChangeClientNamespace.cs @@ -2,53 +2,10 @@ #nullable disable -using System; -using System.ClientModel.Primitives; - namespace Sample.Custom { /// public partial class TestClient { - private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier200; - private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier201; - private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier202; - private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier204; - private static global::Sample.Custom.TestClient.Classifier2xxAnd4xx _pipelineMessageClassifier2xxAnd4xx; - - private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); - - private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier201 => _pipelineMessageClassifier201 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 201 }); - - private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier202 => _pipelineMessageClassifier202 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 202 }); - - private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier204 => _pipelineMessageClassifier204 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 204 }); - - private static global::Sample.Custom.TestClient.Classifier2xxAnd4xx PipelineMessageClassifier2xxAnd4xx => _pipelineMessageClassifier2xxAnd4xx ??= new global::Sample.Custom.TestClient.Classifier2xxAnd4xx(); - - private class Classifier2xxAnd4xx : global::System.ClientModel.Primitives.PipelineMessageClassifier - { - public override bool TryClassify(global::System.ClientModel.Primitives.PipelineMessage message, out bool isError) - { - isError = false; - if ((message.Response == null)) - { - return false; - } - isError = message.Response.Status switch - { - ((>= 200) and (< 300)) => false, - ((>= 400) and (< 500)) => false, - _ => true - }; - return true; - } - - public override bool TryClassify(global::System.ClientModel.Primitives.PipelineMessage message, global::System.Exception exception, out bool isRetryable) - { - isRetryable = false; - return false; - } - } } } diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/ValidateAllClientResponseClassifiers.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/ValidateAllClientResponseClassifiers.cs new file mode 100644 index 0000000000..4d7a3c184a --- /dev/null +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/RestClientProviders/TestData/RestClientProviderTests/ValidateAllClientResponseClassifiers.cs @@ -0,0 +1,164 @@ +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace Sample +{ + /// + public partial class TestClient + { + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier200; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier200201202; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier201; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier202; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier203; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier204; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier205; + private static global::System.ClientModel.Primitives.PipelineMessageClassifier _pipelineMessageClassifier206; + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier200201202 => _pipelineMessageClassifier200201202 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 200, 201, 202 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier201 => _pipelineMessageClassifier201 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 201 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier202 => _pipelineMessageClassifier202 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 202 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier203 => _pipelineMessageClassifier203 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 203 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier204 => _pipelineMessageClassifier204 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 204 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier205 => _pipelineMessageClassifier205 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 205 }); + + private static global::System.ClientModel.Primitives.PipelineMessageClassifier PipelineMessageClassifier206 => _pipelineMessageClassifier206 = global::System.ClientModel.Primitives.PipelineMessageClassifier.Create(stackalloc ushort[] { 206 }); + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation204Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier204; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation205Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier205; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation206Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier206; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation200Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation202Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier202; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation201Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier201; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation203Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier203; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateTestOperation200201202Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200201202; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + + internal global::System.ClientModel.Primitives.PipelineMessage CreateDuplicateTestOperation200201202Request(global::System.ClientModel.BinaryContent content, global::System.ClientModel.Primitives.RequestOptions options) + { + global::System.ClientModel.Primitives.PipelineMessage message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200201202; + global::System.ClientModel.Primitives.PipelineRequest request = message.Request; + request.Method = "GET"; + global::Sample.ClientUriBuilder uri = new global::Sample.ClientUriBuilder(); + uri.Reset(_endpoint); + request.Uri = uri.ToUri(); + request.Content = content; + message.Apply(options); + return message; + } + } +} diff --git a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/common/InputFactory.cs b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/common/InputFactory.cs index 72269024a7..377a9c3c63 100644 --- a/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/common/InputFactory.cs +++ b/packages/http-client-csharp/generator/Microsoft.Generator.CSharp/test/common/InputFactory.cs @@ -214,7 +214,8 @@ public static InputOperation Operation( IEnumerable? responses = null, IEnumerable? requestMediaTypes = null, string uri = "", - string path = "") + string path = "", + string httpMethod = "GET") { return new InputOperation( name, @@ -225,7 +226,7 @@ public static InputOperation Operation( access, parameters is null ? [] : [.. parameters], responses is null ? [OperationResponse()] : [.. responses], - "GET", + httpMethod, BodyMediaType.Json, uri, path, diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.RestClient.cs b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.RestClient.cs index 5f6ddb7250..e5ed76fe1f 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.RestClient.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Unbranded-TypeSpec/src/Generated/UnbrandedTypeSpecClient.RestClient.cs @@ -12,21 +12,12 @@ namespace UnbrandedTypeSpec public partial class UnbrandedTypeSpecClient { private static PipelineMessageClassifier _pipelineMessageClassifier200; - private static PipelineMessageClassifier _pipelineMessageClassifier201; - private static PipelineMessageClassifier _pipelineMessageClassifier202; private static PipelineMessageClassifier _pipelineMessageClassifier204; - private static Classifier2xxAnd4xx _pipelineMessageClassifier2xxAnd4xx; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 = PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); - private static PipelineMessageClassifier PipelineMessageClassifier201 => _pipelineMessageClassifier201 = PipelineMessageClassifier.Create(stackalloc ushort[] { 201 }); - - private static PipelineMessageClassifier PipelineMessageClassifier202 => _pipelineMessageClassifier202 = PipelineMessageClassifier.Create(stackalloc ushort[] { 202 }); - private static PipelineMessageClassifier PipelineMessageClassifier204 => _pipelineMessageClassifier204 = PipelineMessageClassifier.Create(stackalloc ushort[] { 204 }); - private static Classifier2xxAnd4xx PipelineMessageClassifier2xxAnd4xx => _pipelineMessageClassifier2xxAnd4xx ??= new Classifier2xxAnd4xx(); - internal PipelineMessage CreateSayHiRequest(string headParameter, string queryParameter, string optionalQuery, RequestOptions options) { PipelineMessage message = Pipeline.CreateMessage(); @@ -314,7 +305,7 @@ internal PipelineMessage CreateStillConvenientRequest(RequestOptions options) internal PipelineMessage CreateHeadAsBooleanRequest(string id, RequestOptions options) { PipelineMessage message = Pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier2xxAnd4xx; + message.ResponseClassifier = PipelineMessageClassifier204; PipelineRequest request = message.Request; request.Method = "HEAD"; ClientUriBuilder uri = new ClientUriBuilder(); @@ -341,30 +332,5 @@ internal PipelineMessage CreateWithApiVersionRequest(string p1, RequestOptions o message.Apply(options); return message; } - - private class Classifier2xxAnd4xx : PipelineMessageClassifier - { - public override bool TryClassify(PipelineMessage message, out bool isError) - { - isError = false; - if (message.Response == null) - { - return false; - } - isError = message.Response.Status switch - { - >= 200 and < 300 => false, - >= 400 and < 500 => false, - _ => true - }; - return true; - } - - public override bool TryClassify(PipelineMessage message, Exception exception, out bool isRetryable) - { - isRetryable = false; - return false; - } - } } }