Skip to content

Commit 1cf8601

Browse files
[http-client-csharp] adopt http\resiliency\srv-driven (microsoft#5142)
fixes: microsoft#3983
1 parent 432ca32 commit 1cf8601

File tree

23 files changed

+1170
-22
lines changed

23 files changed

+1170
-22
lines changed

packages/http-client-csharp/eng/scripts/Generate.ps1

+6-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ function IsSpecDir {
5050

5151
$failingSpecs = @(
5252
Join-Path 'http' 'payload' 'pageable'
53-
Join-Path 'http' 'resiliency' 'srv-driven'
5453
Join-Path 'http' 'special-headers' 'conditional-request'
5554
Join-Path 'http' 'type' 'model' 'flatten'
5655
Join-Path 'http' 'type' 'model' 'templated'
@@ -94,7 +93,7 @@ foreach ($directory in $directories) {
9493
$generationDir = Join-Path $generationDir $folder
9594
}
9695

97-
#create the directory if it doesn't exist
96+
# create the directory if it doesn't exist
9897
if (-not (Test-Path $generationDir)) {
9998
New-Item -ItemType Directory -Path $generationDir | Out-Null
10099
}
@@ -111,6 +110,11 @@ foreach ($directory in $directories) {
111110
exit $LASTEXITCODE
112111
}
113112

113+
# srv-driven contains two separate specs, for two separate clients. We need to generate both.
114+
if ($folders.Contains("srv-driven")) {
115+
Generate-Srv-Driven $directory.FullName $generationDir -generateStub $stubbed
116+
}
117+
114118
# TODO need to build but depends on https://github.com/Azure/autorest.csharp/issues/4463
115119
}
116120

packages/http-client-csharp/eng/scripts/Generation.psm1

+32-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ function Get-TspCommand {
2424
param (
2525
[string]$specFile,
2626
[string]$generationDir,
27-
[bool]$generateStub = $false
27+
[bool]$generateStub = $false,
28+
[string]$namespaceOverride = $null
2829
)
2930
$command = "npx tsp compile $specFile"
3031
$command += " --trace @typespec/http-client-csharp"
@@ -38,6 +39,11 @@ function Get-TspCommand {
3839
if ($generateStub) {
3940
$command += " --option @typespec/http-client-csharp.plugin-name=StubLibraryPlugin"
4041
}
42+
43+
if ($namespaceOverride) {
44+
$command += " --option @typespec/http-client-csharp.namespace=$namespaceOverride"
45+
}
46+
4147
return $command
4248
}
4349

@@ -72,7 +78,32 @@ function Compare-Paths {
7278
return $normalizedPath1.Contains($normalizedPath2)
7379
}
7480

81+
function Generate-Srv-Driven {
82+
param (
83+
[string]$specFilePath,
84+
[string]$outputDir,
85+
[bool]$generateStub = $false,
86+
[bool]$createOutputDirIfNotExist = $true
87+
)
88+
89+
$specFilePath = $(Join-Path $specFilePath "old.tsp")
90+
$outputDir = $(Join-Path $outputDir "v1")
91+
if ($createOutputDirIfNotExist -and -not (Test-Path $outputDir)) {
92+
New-Item -ItemType Directory -Path $outputDir | Out-Null
93+
}
94+
95+
Write-Host "Generating http\resiliency\srv-driven\v1" -ForegroundColor Cyan
96+
Invoke (Get-TspCommand $specFilePath $outputDir -generateStub $generateStub -namespaceOverride "Resiliency.ServiceDriven.V1")
97+
98+
# exit if the generation failed
99+
if ($LASTEXITCODE -ne 0) {
100+
exit $LASTEXITCODE
101+
}
102+
}
103+
104+
75105
Export-ModuleMember -Function "Invoke"
76106
Export-ModuleMember -Function "Get-TspCommand"
77107
Export-ModuleMember -Function "Refresh-Build"
78108
Export-ModuleMember -Function "Compare-Paths"
109+
Export-ModuleMember -Function "Generate-Srv-Driven"

packages/http-client-csharp/eng/scripts/Get-CadlRanch-Coverage.ps1

+9
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ foreach ($directory in $directories) {
2727
$outputDir = $directory.FullName.Substring(0, $directory.FullName.IndexOf("src") - 1)
2828
$subPath = $outputDir.Substring($cadlRanchRoot.Length + 1)
2929

30+
if ($subPath.Contains($(Join-Path 'srv-driven' 'v1'))) {
31+
continue
32+
}
33+
3034
Write-Host "Regenerating $subPath" -ForegroundColor Cyan
3135

3236
$specFile = Join-Path $specsDirectory $subPath "client.tsp"
@@ -40,6 +44,11 @@ foreach ($directory in $directories) {
4044
if ($LASTEXITCODE -ne 0) {
4145
exit $LASTEXITCODE
4246
}
47+
48+
# srv-driven contains two separate specs, for two separate clients. We need to generate both.
49+
if ($subPath.Contains('srv-driven')) {
50+
Generate-Srv-Driven $(Join-Path $specsDirectory $subPath) $outputDir -createOutputDirIfNotExist $false
51+
}
4352
}
4453

4554
# test all

packages/http-client-csharp/eng/scripts/Test-CadlRanch.ps1

+10
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ foreach ($directory in $directories) {
3232
if (-not (Compare-Paths $subPath $filter)) {
3333
continue
3434
}
35+
36+
if ($subPath.Contains($(Join-Path 'srv-driven' 'v1'))) {
37+
continue
38+
}
3539

3640
$testPath = "$cadlRanchRoot.Tests"
3741
$testFilter = "TestProjects.CadlRanch.Tests"
@@ -64,6 +68,12 @@ foreach ($directory in $directories) {
6468
exit $LASTEXITCODE
6569
}
6670

71+
# srv-driven contains two separate specs, for two separate clients. We need to generate both.
72+
if ($subPath.Contains("srv-driven")) {
73+
Generate-Srv-Driven $(Join-Path $specsDirectory $subPath) $outputDir -createOutputDirIfNotExist $false
74+
}
75+
76+
6777
Write-Host "Testing $subPath" -ForegroundColor Cyan
6878
$command = "dotnet test $cadlRanchCsproj --filter `"FullyQualifiedName~$testFilter`""
6979
Invoke $command

packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/src/Providers/ScmMethodProviderCollection.cs

+2-13
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,12 @@ public class ScmMethodProviderCollection : MethodProviderCollection
2323
private string _cleanOperationName;
2424
private readonly MethodProvider _createRequestMethod;
2525

26-
private readonly string _createRequestMethodName;
27-
2826
private ClientProvider Client { get; }
2927

3028
public ScmMethodProviderCollection(InputOperation operation, TypeProvider enclosingType)
3129
: base(operation, enclosingType)
3230
{
3331
_cleanOperationName = operation.Name.ToCleanName();
34-
_createRequestMethodName = "Create" + _cleanOperationName + "Request";
3532
Client = enclosingType as ClientProvider ?? throw new InvalidOperationException("Scm methods can only be built for client types.");
3633
_createRequestMethod = Client.RestClient.GetCreateRequestMethod(Operation);
3734
}
@@ -395,6 +392,7 @@ private ScmMethodProvider BuildProtocolMethod(MethodProvider createRequestMethod
395392

396393
var requiredParameters = new List<ParameterProvider>();
397394
var optionalParameters = new List<ParameterProvider>();
395+
398396
for (var i = 0; i < ProtocolMethodParameters.Count; i++)
399397
{
400398
var parameter = ProtocolMethodParameters[i];
@@ -419,8 +417,7 @@ private ScmMethodProvider BuildProtocolMethod(MethodProvider createRequestMethod
419417
parameter.DefaultValue = null;
420418
parameter.Type = parameter.Type.WithNullable(true);
421419
}
422-
// Now, the request options parameter can be optional due to the above changes to the method signature.
423-
requestOptionsParameter = ScmKnownParameters.OptionalRequestOptions;
420+
424421
requiredParameters.AddRange(optionalParameters);
425422
optionalParameters.Clear();
426423
}
@@ -494,14 +491,6 @@ private bool ShouldAddOptionalRequestOptionsParameter()
494491
{
495492
return true;
496493
}
497-
if (ProtocolMethodParameters[i].DefaultValue == null && ConvenienceMethodParameters[i].DefaultValue != null)
498-
{
499-
return true;
500-
}
501-
if (ProtocolMethodParameters[i].DefaultValue != null && ConvenienceMethodParameters[i].DefaultValue == null)
502-
{
503-
return true;
504-
}
505494
}
506495

507496
return false;

packages/http-client-csharp/generator/Microsoft.Generator.CSharp.ClientModel/test/Providers/ClientProviders/ClientProviderTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ public static IEnumerable<TestCaseData> RequestOptionsParameterInSignatureTestCa
745745
]), false, false);
746746

747747
// Protocol & convenience methods will have the same parameters.
748-
// One of the parameter is optional, so it should be make required in the protocol method, and RequestOptions can be optional.
748+
// One of the parameter is optional, so it should be made required in the protocol method.
749749
yield return new TestCaseData(
750750
InputFactory.Operation(
751751
"TestOperation",
@@ -761,7 +761,7 @@ public static IEnumerable<TestCaseData> RequestOptionsParameterInSignatureTestCa
761761
InputPrimitiveType.Int64,
762762
location: RequestLocation.None,
763763
isRequired: true),
764-
]), true, true);
764+
]), false, true);
765765

766766
// Protocol & convenience methods will have the same parameters.
767767
// One of the parameter is optional value type, so it should be made nullable required in the protocol method, and RequestOptions can be optional.
@@ -780,7 +780,7 @@ public static IEnumerable<TestCaseData> RequestOptionsParameterInSignatureTestCa
780780
InputPrimitiveType.Int64,
781781
location: RequestLocation.None,
782782
isRequired: true),
783-
]), true, true);
783+
]), false, true);
784784

785785
// convenience method only has a body param, so RequestOptions should be optional in protocol method.
786786
yield return new TestCaseData(

packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Properties/launchSettings.json

+5
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@
120120
"commandName": "Executable",
121121
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
122122
},
123+
"http-resiliency-srv-driven": {
124+
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/resiliency/srv-driven -p StubLibraryPlugin",
125+
"commandName": "Executable",
126+
"executablePath": "$(SolutionDir)/../dist/generator/Microsoft.Generator.CSharp.exe"
127+
},
123128
"http-routes": {
124129
"commandLineArgs": "$(SolutionDir)/TestProjects/CadlRanch/http/routes -p StubLibraryPlugin",
125130
"commandName": "Executable",

packages/http-client-csharp/generator/Microsoft.Generator.CSharp/src/Providers/ParameterProvider.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ private ParameterProvider BuildInputVariant()
121121
wireInfo: WireInfo,
122122
validation: Validation)
123123
{
124-
_asVariable = AsExpression
124+
_asVariable = AsExpression,
125+
SpreadSource = SpreadSource
125126
};
126127
}
127128

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using NUnit.Framework;
5+
using Resiliency.ServiceDriven.V1;
6+
using System.Threading.Tasks;
7+
8+
namespace TestProjects.CadlRanch.Tests.Http.Resiliency.SrvDriven
9+
{
10+
/// <summary>
11+
/// Contains tests for the service-driven resiliency V1 client.
12+
/// </summary>
13+
public partial class SrvDrivenTests : CadlRanchTestBase
14+
{
15+
// This test validates the v1 client behavior when both the service deployment and api version are set to V1.
16+
[CadlRanchTest]
17+
public Task AddOptionalParamFromNone_V1Client_V1Service_WithApiVersionV1() => Test(async (host) =>
18+
{
19+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
20+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV1, options);
21+
var response = await client.FromNoneAsync();
22+
23+
Assert.AreEqual(204, response.GetRawResponse().Status);
24+
});
25+
26+
// This test validates the v1 client behavior when the service deployment is set to V2 and the api version is set to V1.
27+
[CadlRanchTest]
28+
public Task AddOptionalParamFromNone_V1Client_V2Service_WithApiVersionV1() => Test(async (host) =>
29+
{
30+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
31+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
32+
var response = await client.FromNoneAsync();
33+
34+
Assert.AreEqual(204, response.GetRawResponse().Status);
35+
});
36+
37+
[CadlRanchTest]
38+
public Task AddOptionalParamFromOneOptional_V1Client_V1Service_WithApiVersionV1() => Test(async (host) =>
39+
{
40+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
41+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV1, options);
42+
var response = await client.FromOneOptionalAsync("optional");
43+
44+
Assert.AreEqual(204, response.GetRawResponse().Status);
45+
});
46+
47+
[CadlRanchTest]
48+
public Task AddOptionalParamFromOneOptional_V1Client_V2Service_WithApiVersionV1() => Test(async (host) =>
49+
{
50+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
51+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
52+
var response = await client.FromOneOptionalAsync("optional", cancellationToken: default);
53+
54+
Assert.AreEqual(204, response.GetRawResponse().Status);
55+
});
56+
57+
[CadlRanchTest]
58+
public Task AddOptionalParamFromOneRequired_V1Client_V1Service_WithApiVersionV1() => Test(async (host) =>
59+
{
60+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
61+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV1, options);
62+
var response = await client.FromOneRequiredAsync("required");
63+
64+
Assert.AreEqual(204, response.GetRawResponse().Status);
65+
});
66+
67+
[CadlRanchTest]
68+
public Task AddOptionalParamFromOneRequired_V1Client_V2Service_WithApiVersionV1() => Test(async (host) =>
69+
{
70+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
71+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
72+
var response = await client.FromOneRequiredAsync("required");
73+
74+
Assert.AreEqual(204, response.GetRawResponse().Status);
75+
});
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using NUnit.Framework;
5+
using System.Threading.Tasks;
6+
using Resiliency.ServiceDriven;
7+
8+
namespace TestProjects.CadlRanch.Tests.Http.Resiliency.SrvDriven
9+
{
10+
public partial class SrvDrivenTests : CadlRanchTestBase
11+
{
12+
private const string ServiceDeploymentV1 = "v1";
13+
private const string ServiceDeploymentV2 = "v2";
14+
15+
[CadlRanchTest]
16+
public Task AddOperation() => Test(async (host) =>
17+
{
18+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2);
19+
var response = await client.AddOperationAsync();
20+
21+
Assert.AreEqual(204, response.GetRawResponse().Status);
22+
});
23+
24+
// This test validates the "new" client behavior when the api version is set to V1.
25+
[CadlRanchTest]
26+
public Task AddOptionalParamFromNone_WithApiVersionV1() => Test(async (host) =>
27+
{
28+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
29+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
30+
var response = await client.FromNoneAsync();
31+
32+
Assert.AreEqual(204, response.GetRawResponse().Status);
33+
});
34+
35+
// This test validates the "new" client behavior when the api version is set to V2.
36+
[CadlRanchTest]
37+
public Task AddOptionalParamFromNone_WithApiVersionV2() => Test(async (host) =>
38+
{
39+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V2);
40+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
41+
var response = await client.FromNoneAsync("new", cancellationToken: default);
42+
43+
Assert.AreEqual(204, response.GetRawResponse().Status);
44+
});
45+
46+
[CadlRanchTest]
47+
public Task AddOptionalParamFromOneOptional_WithApiVersionV1() => Test(async (host) =>
48+
{
49+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
50+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
51+
var response = await client.FromOneOptionalAsync("optional");
52+
53+
Assert.AreEqual(204, response.GetRawResponse().Status);
54+
});
55+
56+
[CadlRanchTest]
57+
public Task AddOptionalParamFromOneOptional_WithApiVersionV2() => Test(async (host) =>
58+
{
59+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V2);
60+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
61+
var response = await client.FromOneOptionalAsync("optional", "new", cancellationToken: default);
62+
63+
Assert.AreEqual(204, response.GetRawResponse().Status);
64+
});
65+
66+
[CadlRanchTest]
67+
public Task AddOptionalParamFromOneRequired_WithApiVersionV1() => Test(async (host) =>
68+
{
69+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V1);
70+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
71+
var response = await client.FromOneRequiredAsync("required");
72+
73+
Assert.AreEqual(204, response.GetRawResponse().Status);
74+
});
75+
76+
[CadlRanchTest]
77+
public Task AddOptionalParamFromOneRequired_WithApiVersionV2() => Test(async (host) =>
78+
{
79+
var options = new ResiliencyServiceDrivenClientOptions(ResiliencyServiceDrivenClientOptions.ServiceVersion.V2);
80+
var client = new ResiliencyServiceDrivenClient(host, ServiceDeploymentV2, options);
81+
var response = await client.FromOneRequiredAsync("required", "new", cancellationToken: default);
82+
83+
Assert.AreEqual(204, response.GetRawResponse().Status);
84+
});
85+
}
86+
}

0 commit comments

Comments
 (0)