diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3443b389a108..3e17f5b42b2d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -202,10 +202,10 @@ # ServiceOwners: @ryogok @TFR258 @tburns10 @areddish @toothache # PRLabel: %Cognitive - Face -/sdk/cognitiveservices/Vision.Face/ @JinyuID @dipidoo @SteveMSFT @msyache @longli0 @ShaoAnLin @lulululululu +/sdk/cognitiveservices/Vision.Face/ @JinyuID @dipidoo @SteveMSFT @msyache @longli0 @lulululululu # ServiceLabel: %Cognitive - Face -# ServiceOwners: @JinyuID @dipidoo @SteveMSFT @msyache @longli0 @ShaoAnLin @lulululululu +# ServiceOwners: @JinyuID @dipidoo @SteveMSFT @msyache @longli0 @lulululululu # PRLabel: %Cognitive - Form Recognizer /sdk/documentintelligence/ @kinelski @pallavit @joseharriaga diff --git a/common/ManagementTestShared/Redesign/ManagementRecordedTestBase.cs b/common/ManagementTestShared/Redesign/ManagementRecordedTestBase.cs index 595fa61d0866..0af83311687f 100644 --- a/common/ManagementTestShared/Redesign/ManagementRecordedTestBase.cs +++ b/common/ManagementTestShared/Redesign/ManagementRecordedTestBase.cs @@ -73,44 +73,40 @@ private void Initialize() protected void IgnoreNetworkDependencyVersions() { // Ignore the api-version of Network operations - UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers\/Microsoft.Network\/(.*?)\?api-version=(?[a-z0-9-]+)", "**" - ) + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/providers\/Microsoft.Network\/(.*?)\?api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } protected void IgnoreAuthorizationDependencyVersions() { // Ignore the api-version of Authorization operations - UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers\/Microsoft.Authorization\/(.*?)\?api-version=(?[a-z0-9-]+)", "**" - ) + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/providers\/Microsoft.Authorization\/(.*?)\?api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } protected void IgnoreKeyVaultDependencyVersions() { // Ignore the api-version of KeyVault operations - UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers\/Microsoft.KeyVault\/(.*?)\?api-version=(?[a-z0-9-]+)", "**" - ) + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/providers\/Microsoft.KeyVault\/(.*?)\?api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } protected void IgnoreManagedIdentityDependencyVersions() { // Ignore the api-version of ManagedIdentity operations - UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers\/Microsoft.ManagedIdentity\/(.*?)\?api-version=(?[a-z0-9-]+)", "**" - ) + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/providers\/Microsoft.ManagedIdentity\/(.*?)\?api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } diff --git a/eng/Packages.Data.props b/eng/Packages.Data.props index dd274ab8d63e..6b66917a2d93 100644 --- a/eng/Packages.Data.props +++ b/eng/Packages.Data.props @@ -144,7 +144,8 @@ - + + @@ -223,7 +224,7 @@ All should have PrivateAssets="All" set so they don't become package dependencies --> - + diff --git a/eng/common/pipelines/templates/steps/verify-restapi-spec-location.yml b/eng/common/pipelines/templates/steps/verify-restapi-spec-location.yml index cffdc564f826..f96cd36dc811 100644 --- a/eng/common/pipelines/templates/steps/verify-restapi-spec-location.yml +++ b/eng/common/pipelines/templates/steps/verify-restapi-spec-location.yml @@ -22,3 +22,4 @@ steps: displayName: Verify REST API spec location for "${{ parameters.PackageName }}" env: GH_TOKEN: $(azuresdk-github-pat) + condition: and(succeededOrFailed(), ne(variables['Skip.Verify-RestApiSpecLocation'], 'true')) diff --git a/eng/emitter-package-lock.json b/eng/emitter-package-lock.json index 8bae4eaded2f..ba0dcec7fc2f 100644 --- a/eng/emitter-package-lock.json +++ b/eng/emitter-package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "dependencies": { - "@azure-tools/typespec-csharp": "0.2.0-beta.20240508.5" + "@azure-tools/typespec-csharp": "0.2.0-beta.20240513.2" }, "devDependencies": { "@azure-tools/typespec-azure-core": "0.41.0", @@ -18,9 +18,9 @@ } }, "node_modules/@autorest/csharp": { - "version": "3.0.0-beta.20240508.5", - "resolved": "https://registry.npmjs.org/@autorest/csharp/-/csharp-3.0.0-beta.20240508.5.tgz", - "integrity": "sha512-QKvbrKnSlt3zuu7/UHXYPf0SnKyEqGhcqe+B6pwN8B1y4cCxg13taD9aa6GOJWus0XCtssTsybBO6z2VX4eYGA==" + "version": "3.0.0-beta.20240513.2", + "resolved": "https://registry.npmjs.org/@autorest/csharp/-/csharp-3.0.0-beta.20240513.2.tgz", + "integrity": "sha512-2lb/mPFCncERoAAmBBKhmUnvyv47HdYel2omLYupS5j+zcgfsVviT4ZNmrBT3xZQuptQqdapSU75Qpwp4JeRJQ==" }, "node_modules/@azure-tools/typespec-azure-core": { "version": "0.41.0", @@ -57,11 +57,11 @@ } }, "node_modules/@azure-tools/typespec-csharp": { - "version": "0.2.0-beta.20240508.5", - "resolved": "https://registry.npmjs.org/@azure-tools/typespec-csharp/-/typespec-csharp-0.2.0-beta.20240508.5.tgz", - "integrity": "sha512-OzKOSAbhUvmdWks2efFJUaxTKOvo2bU+1tNx2JKPTrnPnrdUcyKdc+vEXSdQXEsM210qupG3giWnCXKk+wyIrg==", + "version": "0.2.0-beta.20240513.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-csharp/-/typespec-csharp-0.2.0-beta.20240513.2.tgz", + "integrity": "sha512-azCQnF4dtwRDc7iRqDTBGhxzZOCgDbYUYdUoXDieGvP+mS4r4Ns95uVyirFJwwFWMhHzntRs4U/07/iYGEHkfQ==", "dependencies": { - "@autorest/csharp": "3.0.0-beta.20240508.5", + "@autorest/csharp": "3.0.0-beta.20240513.2", "json-serialize-refs": "0.1.0-0", "winston": "^3.8.2" }, @@ -693,9 +693,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -868,9 +868,9 @@ } }, "node_modules/semver": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.1.tgz", - "integrity": "sha512-f/vbBsu+fOiYt+lmwZV0rVwJScl46HppnOA1ZvIuBWKOTlllpyJ3bfVax76/OrhCH38dyxoDIA8K7uB963IYgA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, "bin": { "semver": "bin/semver.js" diff --git a/eng/emitter-package.json b/eng/emitter-package.json index 6bc74f989c11..f375651846f2 100644 --- a/eng/emitter-package.json +++ b/eng/emitter-package.json @@ -1,14 +1,14 @@ { "main": "dist/src/index.js", "dependencies": { - "@azure-tools/typespec-csharp": "0.2.0-beta.20240508.5" + "@azure-tools/typespec-csharp": "0.2.0-beta.20240513.2" }, "devDependencies": { "@typespec/versioning": "0.55.0", + "@typespec/openapi": "0.55.0", "@azure-tools/typespec-azure-core": "0.41.0", - "@typespec/rest": "0.55.0", "@typespec/http": "0.55.0", - "@typespec/openapi": "0.55.0", + "@typespec/rest": "0.55.0", "@azure-tools/typespec-client-generator-core": "0.41.8", "@typespec/compiler": "0.55.0" } diff --git a/eng/pipelines/aggregate-reports.yml b/eng/pipelines/aggregate-reports.yml index 6ee613046eb7..aa84228ae386 100644 --- a/eng/pipelines/aggregate-reports.yml +++ b/eng/pipelines/aggregate-reports.yml @@ -168,6 +168,26 @@ stages: -WorkingDirectory '$(Build.ArtifactStagingDirectory)' -NupkgFilesDestination 'nupkgFiles' + - task: AzureCLI@2 + displayName: Azure CLI Login + inputs: + azureSubscription: azure-sdk-apiscan + scriptType: pscore + scriptLocation: inlineScript + addSpnToEnvironment: true + inlineScript: | + az --version + az account show -o json + Write-Host "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$($env:servicePrincipalId)" + Write-Host "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$($env:tenantId)" + Write-Host "##vso[task.setvariable variable=ARM_OIDC_TOKEN;issecret=true]$($env:idToken)" + + - pwsh: | + # Need to re-login with the az login so that it presists and can be used in the APISca task + az login --service-principal -u $(ARM_CLIENT_ID) --tenant $(ARM_TENANT_ID) --allow-no-subscriptions --federated-token $(ARM_OIDC_TOKEN) + az account show -o json + displayName: Persist CLI Login for ApiScan usage + - task: securedevelopmentteam.vss-secure-development-tools.build-task-apiscan.APIScan@2 displayName: 'Run APIScan' inputs: @@ -179,8 +199,14 @@ stages: preserveLogsFolder: true verbosityLevel: standard env: - # azure-sdk-apiscan (81109e5f-0620-423c-a37a-c22fbf8973a7) - AzureServicesAuthConnectionString: runAs=App;AppId=81109e5f-0620-423c-a37a-c22fbf8973a7;TenantId=72f988bf-86f1-41af-91ab-2d7cd011db47;AppKey=$(azure-sdk-apiscan-client-secret) + AzureServicesAuthConnectionString: RunAs=Developer;DeveloperTool=AzureCli + + - pwsh: | + az account show -o json + az logout + az account clear + displayName: Logout of Azure CLI + condition: succeededOrFailed() - task: securedevelopmentteam.vss-secure-development-tools.build-task-postanalysis.PostAnalysis@2 displayName: 'Post Analysis (ApiScan)' diff --git a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Customized/Models/RequestReportRecordContract.cs b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Customized/Models/RequestReportRecordContract.cs index 4f76350d6a31..b827bd67a5b7 100644 --- a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Customized/Models/RequestReportRecordContract.cs +++ b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Customized/Models/RequestReportRecordContract.cs @@ -14,7 +14,7 @@ namespace Azure.ResourceManager.ApiManagement.Models public partial class RequestReportRecordContract : IUtf8JsonSerializable, IJsonModel { [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SerializeBackendResponseCodeValue(Utf8JsonWriter writer) + private void SerializeBackendResponseCodeValue(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStringValue(BackendResponseCode); } diff --git a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Generated/Models/RequestReportRecordContract.Serialization.cs b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Generated/Models/RequestReportRecordContract.Serialization.cs index f0b9daf760f8..b9e2a4bb302d 100644 --- a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Generated/Models/RequestReportRecordContract.Serialization.cs +++ b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/src/Generated/Models/RequestReportRecordContract.Serialization.cs @@ -65,7 +65,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR if (Optional.IsDefined(BackendResponseCode)) { writer.WritePropertyName("backendResponseCode"u8); - SerializeBackendResponseCodeValue(writer); + SerializeBackendResponseCodeValue(writer, options); } if (Optional.IsDefined(ResponseCode)) { diff --git a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/tests/Scenario/LoggerTests.cs b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/tests/Scenario/LoggerTests.cs index 3ac9a284a45d..764aae709b6e 100644 --- a/sdk/apimanagement/Azure.ResourceManager.ApiManagement/tests/Scenario/LoggerTests.cs +++ b/sdk/apimanagement/Azure.ResourceManager.ApiManagement/tests/Scenario/LoggerTests.cs @@ -52,10 +52,10 @@ private void IgnoreApiVersionInEventHubOperations() { // Ignore the api-version of EventHub operations UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers/Microsoft.EventHub/namespaces/([\S]+)?pi-version=(?[a-z0-9-]+)", "**" - ) + @"/providers/Microsoft.EventHub/namespaces/([\S]+)?pi-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs index 490820a617a4..82068c89e2be 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/src/ConfigurationClient.cs @@ -200,10 +200,8 @@ public virtual async Task> AddConfigurationSettin case 200: case 201: return await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false); - case 412: - throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); default: - throw new RequestFailedException(response); + throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); } } catch (Exception e) @@ -239,10 +237,8 @@ public virtual Response AddConfigurationSetting(Configurat case 200: case 201: return CreateResponse(response); - case 412: - throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); default: - throw new RequestFailedException(response); + throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()); } } catch (Exception e) @@ -309,10 +305,9 @@ public virtual async Task> SetConfigurationSettin return response.Status switch { 200 => await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false), - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -352,10 +347,9 @@ public virtual Response SetConfigurationSetting(Configurat return response.Status switch { 200 => CreateResponse(response), - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -441,10 +435,9 @@ private async Task DeleteConfigurationSettingAsync(string key, string { 200 => response, 204 => response, - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -470,10 +463,9 @@ private Response DeleteConfigurationSetting(string key, string label, MatchCondi { 200 => response, 204 => response, - 409 => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), // Throws on 412 if resource was modified. - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -596,7 +588,7 @@ internal virtual async Task> GetConfigurationSett { 200 => await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false), 304 => CreateResourceModifiedResponse(response), - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()) }; } catch (Exception e) @@ -633,7 +625,7 @@ internal virtual Response GetConfigurationSetting(string k { 200 => CreateResponse(response), 304 => CreateResourceModifiedResponse(response), - _ => throw new RequestFailedException(response), + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()) }; } catch (Exception e) @@ -1386,7 +1378,7 @@ private async ValueTask> SetReadOnlyAsync(string 200 => async ? await CreateResponseAsync(response, cancellationToken).ConfigureAwait(false) : CreateResponse(response), - _ => throw new RequestFailedException(response) + _ => throw new RequestFailedException(response, null, new ConfigurationRequestFailedDetailsParser()), }; } catch (Exception e) @@ -1469,22 +1461,24 @@ private static RequestContext CreateRequestContext(ErrorOptions errorOptions, Ca private class ConfigurationRequestFailedDetailsParser : RequestFailedDetailsParser { + private const string TroubleshootingMessage = + "For troubleshooting information, see https://aka.ms/azsdk/net/appconfiguration/troubleshoot."; public override bool TryParse(Response response, out ResponseError error, out IDictionary data) { switch (response.Status) { case 409: - error = new ResponseError(null, "The setting is read only"); + error = new ResponseError(null, $"The setting is read only. {TroubleshootingMessage}"); data = null; return true; case 412: - error = new ResponseError(null, "Setting was already present."); + error = new ResponseError(null, $"Setting was already present. {TroubleshootingMessage}"); data = null; return true; default: - error = null; + error = new ResponseError(null, TroubleshootingMessage); data = null; - return false; + return true; } } } diff --git a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs index 30e86abf2eba..59c01dd4ee35 100644 --- a/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs +++ b/sdk/appconfiguration/Azure.Data.AppConfiguration/tests/ConfigurationMockTests.cs @@ -29,6 +29,7 @@ public class ConfigurationMockTests : ClientTestBase private static readonly string s_credential = "b1d9b31"; private static readonly string s_secret = "aabbccdd"; private static readonly string s_connectionString = $"Endpoint={s_endpoint};Id={s_credential};Secret={s_secret}"; + private static readonly string s_troubleshootingLink = "https://aka.ms/azsdk/net/appconfiguration/troubleshoot"; private static readonly string s_version = new ConfigurationClientOptions().Version; private static readonly ConfigurationSetting s_testSetting = new ConfigurationSetting("test_key", "test_value") @@ -108,6 +109,27 @@ public void GetNotFound() Assert.AreEqual(404, exception.Status); } + // This test validates that the client throws an exception with the expected error message when it receives a + // non-success status code from the service. + [TestCase((int)HttpStatusCode.Unauthorized)] + [TestCase(403)] + [TestCase((int)HttpStatusCode.NotFound)] + public void GetUnsucessfulResponse(int statusCode) + { + var response = new MockResponse(statusCode); + var mockTransport = new MockTransport(response); + ConfigurationClient service = CreateTestService(mockTransport); + + RequestFailedException exception = Assert.ThrowsAsync(async () => + { + await service.GetConfigurationSettingAsync(key: s_testSetting.Key); + }); + + Assert.AreEqual(statusCode, exception.Status); + + Assert.True(exception?.Message.Contains(s_troubleshootingLink)); + } + [Test] public async Task GetIfChangedModified() { diff --git a/sdk/automanage/Azure.ResourceManager.Automanage/tests/AutomanageTestBase.cs b/sdk/automanage/Azure.ResourceManager.Automanage/tests/AutomanageTestBase.cs index 91793367162a..633f39d90dbe 100644 --- a/sdk/automanage/Azure.ResourceManager.Automanage/tests/AutomanageTestBase.cs +++ b/sdk/automanage/Azure.ResourceManager.Automanage/tests/AutomanageTestBase.cs @@ -151,10 +151,10 @@ private void IgnoreApiVersionInResourcesOperations() { // Ignore the api-version of deployment operations UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/providers/Microsoft.Resources/deployments/[^/]+(/operationStatuses/[^/]+)?pi-version=(?[a-z0-9-]+)", "**" - ) + @"/providers/Microsoft.Resources/deployments/[^/]+(/operationStatuses/[^/]+)?pi-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } } diff --git a/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageCollectionTests.cs b/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageCollectionTests.cs index 96af24a03ff4..82ed9166303a 100644 --- a/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageCollectionTests.cs +++ b/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageCollectionTests.cs @@ -17,7 +17,7 @@ public class BatchApplicationPackageCollectionTests : BatchManagementTestBase public BatchApplicationPackageCollectionTests(bool isAsync) : base(isAsync)//, RecordedTestMode.Record) { - BodyKeySanitizers.Add(new BodyKeySanitizer("https://fakeaccount.blob.core.windows.net") { JsonPath = "properties.storageUrl" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.storageUrl") { Value = "https://fakeaccount.blob.core.windows.net" }); } [SetUp] diff --git a/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageOperationTests.cs b/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageOperationTests.cs index 289e2c33b794..a0817a403da3 100644 --- a/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageOperationTests.cs +++ b/sdk/batch/Azure.ResourceManager.Batch/tests/TestCase/BatchApplicationPackageOperationTests.cs @@ -16,7 +16,7 @@ public class BatchApplicationPackageOperationTests : BatchManagementTestBase public BatchApplicationPackageOperationTests(bool isAsync) : base(isAsync)//, RecordedTestMode.Record) { - BodyKeySanitizers.Add(new BodyKeySanitizer("https://fakeaccount.blob.core.windows.net") { JsonPath = "properties.storageUrl" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.storageUrl") { Value = "https://fakeaccount.blob.core.windows.net" }); } [SetUp] diff --git a/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientAutomatedLiveTestsBase.cs b/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientAutomatedLiveTestsBase.cs index 7686da463215..96d3c5f7ddea 100644 --- a/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientAutomatedLiveTestsBase.cs +++ b/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientAutomatedLiveTestsBase.cs @@ -52,10 +52,10 @@ public CallAutomationClientAutomatedLiveTestsBase(bool isAsync, RecordedTestMode JsonPathSanitizers.Add("$..botAppId"); JsonPathSanitizers.Add("$..ivrContext"); JsonPathSanitizers.Add("$..dialog.botAppId"); - BodyKeySanitizers.Add(new BodyKeySanitizer(@"https://sanitized.skype.com/api/servicebuscallback/events?q=SanitizedSanitized") { JsonPath = "..callbackUri" }); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(TestDispatcherRegEx, "https://sanitized.skype.com")); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx, "https://sanitized.skype.com")); - UriRegexSanitizers.Add(new UriRegexSanitizer(TestDispatcherQNameRegEx, SanitizeValue)); + BodyKeySanitizers.Add(new BodyKeySanitizer("..callbackUri") { Value = @"https://sanitized.skype.com/api/servicebuscallback/events?q=SanitizedSanitized"}); + BodyRegexSanitizers.Add(new BodyRegexSanitizer(TestDispatcherRegEx) { Value = "https://sanitized.skype.com" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx) { Value = "https://sanitized.skype.com" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(TestDispatcherQNameRegEx)); } [SetUp] diff --git a/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs b/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs index df5f4eac2f50..483a7a8df157 100644 --- a/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs +++ b/sdk/communication/Azure.Communication.CallAutomation/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs @@ -22,8 +22,8 @@ public CallAutomationClientLiveTestsBase(bool isAsync) : base(isAsync) JsonPathSanitizers.Add("$..id"); JsonPathSanitizers.Add("$..rawId"); JsonPathSanitizers.Add("$..value"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx, "https://sanitized.skype.com")); - } + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx) { Value = "https://sanitized.skype.com" }); + } public bool SkipCallAutomationInteractionLiveTests => TestEnvironment.Mode != RecordedTestMode.Playback && Environment.GetEnvironmentVariable("SKIP_CALLAUTOMATION_INTERACTION_LIVE_TESTS")== "TRUE"; diff --git a/sdk/communication/Azure.Communication.CallingServer/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs b/sdk/communication/Azure.Communication.CallingServer/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs index 9c5bfaa8fe6d..466250eab7e7 100644 --- a/sdk/communication/Azure.Communication.CallingServer/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs +++ b/sdk/communication/Azure.Communication.CallingServer/tests/Infrastructure/CallAutomationClientLiveTestsBase.cs @@ -20,7 +20,7 @@ public CallAutomationClientLiveTestsBase(bool isAsync) : base(isAsync) JsonPathSanitizers.Add("$..id"); JsonPathSanitizers.Add("$..rawId"); JsonPathSanitizers.Add("$..value"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx, "https://sanitized.skype.com")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx) {Value = "https://sanitized.skype.com" }); IgnoredHeaders.Add("Repeatability-Request-ID"); IgnoredHeaders.Add("Repeatability-First-Sent"); } diff --git a/sdk/communication/Azure.Communication.Chat/tests/Infrastructure/ChatLiveTestBase.cs b/sdk/communication/Azure.Communication.Chat/tests/Infrastructure/ChatLiveTestBase.cs index 237301630813..84eaa1feb2fe 100644 --- a/sdk/communication/Azure.Communication.Chat/tests/Infrastructure/ChatLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.Chat/tests/Infrastructure/ChatLiveTestBase.cs @@ -17,8 +17,8 @@ public ChatLiveTestBase(bool isAsync) : base(isAsync) { JsonPathSanitizers.Add("$..token"); SanitizedHeaders.Add("x-ms-content-sha256"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx, "https://sanitized.communication.azure.com")); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIIdentityReplacerRegEx, "/identities/Sanitized")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx) {Value = "https://sanitized.communication.azure.com" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIIdentityReplacerRegEx) { Value = "/identities/Sanitized" }); } /// diff --git a/sdk/communication/Azure.Communication.Email/tests/EmailClientLiveTestBase.cs b/sdk/communication/Azure.Communication.Email/tests/EmailClientLiveTestBase.cs index a2a0e2efef86..ceb67ac889dd 100644 --- a/sdk/communication/Azure.Communication.Email/tests/EmailClientLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.Email/tests/EmailClientLiveTestBase.cs @@ -18,9 +18,9 @@ public EmailClientLiveTestBase(bool isAsync) : base(isAsync) { SanitizedHeaders.Add("x-ms-content-sha256"); SanitizedHeaders.Add("Operation-Id"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx, "https://sanitized.communication.azure.com")); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIRoomsIdReplacerRegEx, "emails/operations/sanitizedId?api")); - HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("Operation-Location", "https://sanitized.communication.azure.com/emails/operations/sanitizedId?api-version=2023-03-31")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx) { Value = "https://sanitized.communication.azure.com" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIRoomsIdReplacerRegEx) { Value = "emails/operations/sanitizedId?api" }); + HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("Operation-Location") { Value = "https://sanitized.communication.azure.com/emails/operations/sanitizedId?api-version=2023-03-31" }); } protected EmailClient CreateEmailClient() diff --git a/sdk/communication/Azure.Communication.Identity/tests/Infrastructure/CommunicationIdentityClientLiveTestBase.cs b/sdk/communication/Azure.Communication.Identity/tests/Infrastructure/CommunicationIdentityClientLiveTestBase.cs index eff5bcdc1df8..c5c61e19f41f 100644 --- a/sdk/communication/Azure.Communication.Identity/tests/Infrastructure/CommunicationIdentityClientLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.Identity/tests/Infrastructure/CommunicationIdentityClientLiveTestBase.cs @@ -27,8 +27,8 @@ public CommunicationIdentityClientLiveTestBase(bool isAsync) : base(isAsync) JsonPathSanitizers.Add("$..userId"); JsonPathSanitizers.Add("$..id"); SanitizedHeaders.Add("x-ms-content-sha256"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIIdentityReplacerRegEx, "/identities/Sanitized")); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx, "https://sanitized.communication.azure.com")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIIdentityReplacerRegEx) { Value = "/identities/Sanitized" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx) { Value = "https://sanitized.communication.azure.com" }); } /// diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/DistributionPolicy.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/DistributionPolicy.Serialization.cs index 61441f94a396..f97a7252be54 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/DistributionPolicy.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/DistributionPolicy.Serialization.cs @@ -44,7 +44,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWrit if (Optional.IsDefined(OfferExpiresAfter)) { writer.WritePropertyName("offerExpiresAfterSeconds"u8); - WriteOfferExpiresAfter(writer); + WriteOfferExpiresAfter(writer, options); } if (Optional.IsDefined(Mode)) { diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/PassThroughWorkerSelectorAttachment.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/PassThroughWorkerSelectorAttachment.Serialization.cs index 5cf54bd67de3..6fd846f2f4c8 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/PassThroughWorkerSelectorAttachment.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/PassThroughWorkerSelectorAttachment.Serialization.cs @@ -33,7 +33,7 @@ void IJsonModel.Write(Utf8JsonWriter writer if (Optional.IsDefined(ExpiresAfter)) { writer.WritePropertyName("expiresAfterSeconds"u8); - WriteExpiresAfter(writer); + WriteExpiresAfter(writer, options); } writer.WritePropertyName("kind"u8); writer.WriteStringValue(Kind.ToString()); diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterJobPositionDetails.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterJobPositionDetails.Serialization.cs index 810cbbb81f63..42854e26a139 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterJobPositionDetails.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterJobPositionDetails.Serialization.cs @@ -35,7 +35,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelRead writer.WritePropertyName("queueLength"u8); writer.WriteNumberValue(QueueLength); writer.WritePropertyName("estimatedWaitTimeMinutes"u8); - WriteEstimatedWaitTime(writer); + WriteEstimatedWaitTime(writer, options); if (options.Format != "W" && _serializedAdditionalRawData != null) { foreach (var item in _serializedAdditionalRawData) diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterQueueStatistics.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterQueueStatistics.Serialization.cs index 9de60cd93edf..ae66b3af51b1 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterQueueStatistics.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterQueueStatistics.Serialization.cs @@ -33,7 +33,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderW if (Optional.IsCollectionDefined(EstimatedWaitTimes)) { writer.WritePropertyName("estimatedWaitTimeMinutes"u8); - WriteEstimatedWaitTimes(writer); + WriteEstimatedWaitTimes(writer, options); } if (Optional.IsDefined(LongestJobWaitTimeMinutes)) { diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterWorkerSelector.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterWorkerSelector.Serialization.cs index f99a999c731b..f41ab6488f8a 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterWorkerSelector.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/RouterWorkerSelector.Serialization.cs @@ -45,7 +45,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWr if (Optional.IsDefined(ExpiresAfter)) { writer.WritePropertyName("expiresAfterSeconds"u8); - WriteExpiresAfter(writer); + WriteExpiresAfter(writer, options); } if (Optional.IsDefined(Expedite)) { diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Generated/WaitTimeExceptionTrigger.Serialization.cs b/sdk/communication/Azure.Communication.JobRouter/src/Generated/WaitTimeExceptionTrigger.Serialization.cs index ab04b58854a9..b50c1aa8324c 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Generated/WaitTimeExceptionTrigger.Serialization.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Generated/WaitTimeExceptionTrigger.Serialization.cs @@ -27,7 +27,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelRead writer.WriteStartObject(); writer.WritePropertyName("thresholdSeconds"u8); - WriteThresholdSeconds(writer); + WriteThresholdSeconds(writer, options); writer.WritePropertyName("kind"u8); writer.WriteStringValue(Kind.ToString()); if (options.Format != "W" && _serializedAdditionalRawData != null) diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/DistributionPolicy.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/DistributionPolicy.cs index 54ef097dcc8d..2603fb4dbb09 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/DistributionPolicy.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/DistributionPolicy.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -35,7 +36,7 @@ internal DistributionPolicy(TimeSpan? offerExpiresAfter, DistributionMode mode) public TimeSpan? OfferExpiresAfter { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteOfferExpiresAfter(Utf8JsonWriter writer) + internal void WriteOfferExpiresAfter(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteNumberValue(OfferExpiresAfter.Value.TotalSeconds); } diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/PassThroughWorkerSelectorAttachment.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/PassThroughWorkerSelectorAttachment.cs index faefd7a204b1..8d97474909d4 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/PassThroughWorkerSelectorAttachment.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/PassThroughWorkerSelectorAttachment.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -19,7 +20,7 @@ public partial class PassThroughWorkerSelectorAttachment public TimeSpan? ExpiresAfter { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteExpiresAfter(Utf8JsonWriter writer) + internal void WriteExpiresAfter(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteNumberValue(ExpiresAfter.Value.TotalSeconds); } diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterJobPositionDetails.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterJobPositionDetails.cs index bc2d33e445ed..f0a340b07939 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterJobPositionDetails.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterJobPositionDetails.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -16,7 +17,7 @@ public partial class RouterJobPositionDetails public TimeSpan EstimatedWaitTime { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteEstimatedWaitTime(Utf8JsonWriter writer) + internal void WriteEstimatedWaitTime(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteNumberValue(EstimatedWaitTime.TotalMinutes); } diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterQueueStatistics.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterQueueStatistics.cs index 7fa078d6e47f..bb5e1255003d 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterQueueStatistics.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterQueueStatistics.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text.Json; @@ -20,7 +21,7 @@ public partial class RouterQueueStatistics public IDictionary EstimatedWaitTimes { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteEstimatedWaitTimes(Utf8JsonWriter writer) + internal void WriteEstimatedWaitTimes(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStartObject(); foreach (var item in EstimatedWaitTimes) diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterWorkerSelector.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterWorkerSelector.cs index 545469c11258..7a13ddba8648 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterWorkerSelector.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/RouterWorkerSelector.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -16,7 +17,7 @@ public partial class RouterWorkerSelector public TimeSpan? ExpiresAfter { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteExpiresAfter(Utf8JsonWriter writer) + internal void WriteExpiresAfter(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteNumberValue(ExpiresAfter.Value.TotalSeconds); } diff --git a/sdk/communication/Azure.Communication.JobRouter/src/Models/WaitTimeExceptionTrigger.cs b/sdk/communication/Azure.Communication.JobRouter/src/Models/WaitTimeExceptionTrigger.cs index fcc4ffbe8a80..9887c9e9de76 100644 --- a/sdk/communication/Azure.Communication.JobRouter/src/Models/WaitTimeExceptionTrigger.cs +++ b/sdk/communication/Azure.Communication.JobRouter/src/Models/WaitTimeExceptionTrigger.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -27,7 +28,7 @@ public WaitTimeExceptionTrigger(TimeSpan threshold) public TimeSpan Threshold { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteThresholdSeconds(Utf8JsonWriter writer) + internal void WriteThresholdSeconds(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteNumberValue(Threshold.TotalSeconds); } diff --git a/sdk/communication/Azure.Communication.JobRouter/tests/Infrastructure/RouterLiveTestBase.cs b/sdk/communication/Azure.Communication.JobRouter/tests/Infrastructure/RouterLiveTestBase.cs index 28587e2c0e33..9c5d94949af5 100644 --- a/sdk/communication/Azure.Communication.JobRouter/tests/Infrastructure/RouterLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.JobRouter/tests/Infrastructure/RouterLiveTestBase.cs @@ -28,7 +28,7 @@ public RouterLiveTestBase(bool isAsync, RecordedTestMode? mode = RecordedTestMod JsonPathSanitizers.Add("$..functionKey"); JsonPathSanitizers.Add("$..appKey"); SanitizedHeaders.Add("x-ms-content-sha256"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx, "https://sanitized.comminication.azure.com")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainRegEx) { Value = "https://sanitized.comminication.azure.com" }); } [SetUp] diff --git a/sdk/communication/Azure.Communication.Messages/tests/Infrastructure/MessagesLiveTestBase.cs b/sdk/communication/Azure.Communication.Messages/tests/Infrastructure/MessagesLiveTestBase.cs index f2abe6d155e8..2169246add97 100644 --- a/sdk/communication/Azure.Communication.Messages/tests/Infrastructure/MessagesLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.Messages/tests/Infrastructure/MessagesLiveTestBase.cs @@ -18,7 +18,7 @@ public MessagesLiveTestBase(bool isAsync) : base(isAsync) SanitizedHeaders.Add("x-ms-content-sha256"); SanitizedHeaders.Add("Repeatability-Request-ID"); SanitizedHeaders.Add("Repeatability-First-Sent"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx, "https://sanitized.communication.azure.com")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx) { Value = "https://sanitized.communication.azure.com" }); } protected NotificationMessagesClient CreateInstrumentedNotificationMessagesClient() diff --git a/sdk/communication/Azure.Communication.PhoneNumbers/tests/Infrastructure/PhoneNumbersClientLiveTestBase.cs b/sdk/communication/Azure.Communication.PhoneNumbers/tests/Infrastructure/PhoneNumbersClientLiveTestBase.cs index b1df5451c7d8..c6fc10ee925e 100644 --- a/sdk/communication/Azure.Communication.PhoneNumbers/tests/Infrastructure/PhoneNumbersClientLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.PhoneNumbers/tests/Infrastructure/PhoneNumbersClientLiveTestBase.cs @@ -20,13 +20,13 @@ public class PhoneNumbersClientLiveTestBase : RecordedTestBase This is the ProgrammableConnectivity client library for developing .NET applications interacting with Azure Programmable Connectivity Gateways. Azure SDK Code Generation ProgrammableConnectivity for Azure Data Plane - 1.0.0-beta.1 + 1.0.0-beta.2 Azure ProgrammableConnectivity $(RequiredTargetFrameworks) true diff --git a/sdk/communication/Azure.Communication.ProgrammableConnectivity/tests/ProgrammableConnectivityClientTest.cs b/sdk/communication/Azure.Communication.ProgrammableConnectivity/tests/ProgrammableConnectivityClientTest.cs index 7822ba4b2836..7a846e70114b 100644 --- a/sdk/communication/Azure.Communication.ProgrammableConnectivity/tests/ProgrammableConnectivityClientTest.cs +++ b/sdk/communication/Azure.Communication.ProgrammableConnectivity/tests/ProgrammableConnectivityClientTest.cs @@ -25,8 +25,11 @@ public class ProgrammableConnectivityClientTest : RecordedTestBase diff --git a/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTestBase.cs b/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTestBase.cs index 476ae5ab4416..bac20471f87e 100644 --- a/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTestBase.cs +++ b/sdk/communication/Azure.Communication.Sms/tests/SmsClientLiveTestBase.cs @@ -20,7 +20,7 @@ public SmsClientLiveTestBase(bool isAsync) : base(isAsync) JsonPathSanitizers.Add("$..repeatabilityRequestId"); JsonPathSanitizers.Add("$..repeatabilityFirstSent"); SanitizedHeaders.Add("x-ms-content-sha256"); - UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx, "https://sanitized.communication.azure.com")); + UriRegexSanitizers.Add(new UriRegexSanitizer(URIDomainNameReplacerRegEx) { Value = "https://sanitized.communication.azure.com" }); } [OneTimeSetUp] diff --git a/sdk/compute/Azure.ResourceManager.Compute/CHANGELOG.md b/sdk/compute/Azure.ResourceManager.Compute/CHANGELOG.md index 476618ee6da7..5cc92772446a 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/CHANGELOG.md +++ b/sdk/compute/Azure.ResourceManager.Compute/CHANGELOG.md @@ -1,6 +1,16 @@ # Release History -## 1.5.0-beta.2 (Unreleased) +## 1.6.0-beta.1 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + +## 1.5.0 (2024-05-10) ### Features Added diff --git a/sdk/compute/Azure.ResourceManager.Compute/src/Azure.ResourceManager.Compute.csproj b/sdk/compute/Azure.ResourceManager.Compute/src/Azure.ResourceManager.Compute.csproj index 85094ad0dbc4..375047c4cf34 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/src/Azure.ResourceManager.Compute.csproj +++ b/sdk/compute/Azure.ResourceManager.Compute/src/Azure.ResourceManager.Compute.csproj @@ -1,8 +1,8 @@ - 1.5.0-beta.2 + 1.6.0-beta.1 - 1.4.0 + 1.5.0 Azure.ResourceManager.Compute Microsoft Azure management client SDK for Azure resource provider Microsoft.Compute. azure;management;compute diff --git a/sdk/compute/Azure.ResourceManager.Compute/src/Customize/Models/ComputeResourceSkuLocationInfo.cs b/sdk/compute/Azure.ResourceManager.Compute/src/Customize/Models/ComputeResourceSkuLocationInfo.cs index c7b5aae2b3b3..083db5c5acf9 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/src/Customize/Models/ComputeResourceSkuLocationInfo.cs +++ b/sdk/compute/Azure.ResourceManager.Compute/src/Customize/Models/ComputeResourceSkuLocationInfo.cs @@ -3,6 +3,7 @@ #nullable disable +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -18,7 +19,7 @@ public partial class ComputeResourceSkuLocationInfo public Azure.ResourceManager.Resources.Models.ExtendedLocationType? ExtendedLocationType { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteExtendedLocationType(Utf8JsonWriter writer) + internal void WriteExtendedLocationType(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStringValue(ExtendedLocationType.Value.ToString()); } diff --git a/sdk/compute/Azure.ResourceManager.Compute/src/Generated/Models/ComputeResourceSkuLocationInfo.Serialization.cs b/sdk/compute/Azure.ResourceManager.Compute/src/Generated/Models/ComputeResourceSkuLocationInfo.Serialization.cs index 239070533a9a..50695f68bfec 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/src/Generated/Models/ComputeResourceSkuLocationInfo.Serialization.cs +++ b/sdk/compute/Azure.ResourceManager.Compute/src/Generated/Models/ComputeResourceSkuLocationInfo.Serialization.cs @@ -65,7 +65,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, Mod if (options.Format != "W" && Optional.IsDefined(ExtendedLocationType)) { writer.WritePropertyName("type"u8); - WriteExtendedLocationType(writer); + WriteExtendedLocationType(writer, options); } if (options.Format != "W" && _serializedAdditionalRawData != null) { diff --git a/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineCollectionTests.cs b/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineCollectionTests.cs index 515f796516fd..e8b525f49674 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineCollectionTests.cs +++ b/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineCollectionTests.cs @@ -80,7 +80,6 @@ public async Task GetAll() [TestCase] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task GetAllInSubscription() { var collection = await GetVirtualMachineCollectionAsync(); diff --git a/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineManagedIdentityTests.cs b/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineManagedIdentityTests.cs index e40e172d85d3..e447a132ac31 100644 --- a/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineManagedIdentityTests.cs +++ b/sdk/compute/Azure.ResourceManager.Compute/tests/Scenario/VirtualMachineManagedIdentityTests.cs @@ -1,14 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Threading.Tasks; using Azure.Core; using Azure.Core.TestFramework; using Azure.ResourceManager.Compute.Models; using Azure.ResourceManager.Compute.Tests.Helpers; -using Azure.ResourceManager.Resources; using Azure.ResourceManager.Models; +using Azure.ResourceManager.Resources; using NUnit.Framework; namespace Azure.ResourceManager.Compute.Tests @@ -32,7 +31,6 @@ private async Task CreateUserAssignedIdentityAsync() [TestCase] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task CreateVmWithSystemAssignedIdentity() { var collection = await GetVirtualMachineCollectionAsync(); @@ -51,7 +49,6 @@ public async Task CreateVmWithSystemAssignedIdentity() [TestCase] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task CreateVmWithUserAssignedIdentity() { var collection = await GetVirtualMachineCollectionAsync(); @@ -72,7 +69,6 @@ public async Task CreateVmWithUserAssignedIdentity() [TestCase] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task CreateVmWithSystemAndUserAssignedIdentity() { var collection = await GetVirtualMachineCollectionAsync(); @@ -93,7 +89,6 @@ public async Task CreateVmWithSystemAndUserAssignedIdentity() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromNoneToSystem() { var collection = await GetVirtualMachineCollectionAsync(); @@ -119,7 +114,6 @@ public async Task UpdateVmIdentityFromNoneToSystem() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromNoneToUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -148,7 +142,6 @@ public async Task UpdateVmIdentityFromNoneToUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromNoneToSystemAndUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -177,7 +170,6 @@ public async Task UpdateVmIdentityFromNoneToSystemAndUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemToNone() { var collection = await GetVirtualMachineCollectionAsync(); @@ -205,7 +197,6 @@ public async Task UpdateVmIdentityFromSystemToNone() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemToUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -238,7 +229,6 @@ public async Task UpdateVmIdentityFromSystemToUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemToSystemUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -271,7 +261,6 @@ public async Task UpdateVmIdentityFromSystemToSystemUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromUserToNone() { var collection = await GetVirtualMachineCollectionAsync(); @@ -301,7 +290,6 @@ public async Task UpdateVmIdentityFromUserToNone() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromUserToSystem() { var collection = await GetVirtualMachineCollectionAsync(); @@ -333,7 +321,6 @@ public async Task UpdateVmIdentityFromUserToSystem() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromUserToSystemUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -366,7 +353,6 @@ public async Task UpdateVmIdentityFromUserToSystemUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromUserToTwoUsers() { var collection = await GetVirtualMachineCollectionAsync(); @@ -435,7 +421,6 @@ public async Task UpdateVmIdentityToRemoveUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromTwoUsersToOneUser() { var collection = await GetVirtualMachineCollectionAsync(); @@ -474,7 +459,6 @@ public async Task UpdateVmIdentityFromTwoUsersToOneUser() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemUserToNone() { var collection = await GetVirtualMachineCollectionAsync(); @@ -504,7 +488,6 @@ public async Task UpdateVmIdentityFromSystemUserToNone() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemUserToSystem() { var collection = await GetVirtualMachineCollectionAsync(); @@ -536,7 +519,6 @@ public async Task UpdateVmIdentityFromSystemUserToSystem() [Test] [RecordedTest] - [LiveOnly(Reason = "PrincipalId cannot be stored in test recordings.")] public async Task UpdateVmIdentityFromSystemUserToUser() { var collection = await GetVirtualMachineCollectionAsync(); diff --git a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs index 957b39e4ec30..89492b2692b4 100644 --- a/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs +++ b/sdk/containerregistry/Azure.Containers.ContainerRegistry/tests/ContainerRegistryRecordedTestBase.cs @@ -111,17 +111,17 @@ private void InitializeRecordingSanitizers() string encodedBody = Base64Url.EncodeString($"{{\"exp\":{expiresOn.ToUnixTimeSeconds()}}}"); var jwtSanitizedValue = $"{SanitizeValue}.{encodedBody}.{SanitizeValue}"; - BodyKeySanitizers.Add(new BodyKeySanitizer(jwtSanitizedValue) + BodyKeySanitizers.Add(new BodyKeySanitizer("$..refresh_token") { - JsonPath = "$..refresh_token" + Value = jwtSanitizedValue }); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"access_token=(?.*?)(?=&|$)", SanitizeValue) + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"access_token=(?.*?)(?=&|$)") { GroupForReplace = "group" }); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"refresh_token=(?.*?)(?=&|$)", SanitizeValue) + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"refresh_token=(?.*?)(?=&|$)") { GroupForReplace = "group" }); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.Serialization.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.Serialization.cs index 703324ecefda..51dba567f57d 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.Serialization.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.Serialization.cs @@ -15,13 +15,13 @@ public partial class BodyKeySanitizer : IUtf8JsonSerializable void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) { writer.WriteStartObject(); - if (Optional.IsDefined(JsonPath)) + writer.WritePropertyName("jsonPath"u8); + writer.WriteStringValue(JsonPath); + if (Optional.IsDefined(Value)) { - writer.WritePropertyName("jsonPath"u8); - writer.WriteStringValue(JsonPath); + writer.WritePropertyName("value"u8); + writer.WriteStringValue(Value); } - writer.WritePropertyName("value"u8); - writer.WriteStringValue(Value); if (Optional.IsDefined(Regex)) { writer.WritePropertyName("regex"u8); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.cs index b5cd7d537f0a..73fce1764004 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyKeySanitizer.cs @@ -14,19 +14,19 @@ namespace Azure.Core.TestFramework.Models public partial class BodyKeySanitizer { /// Initializes a new instance of BodyKeySanitizer. - /// - /// is null. - public BodyKeySanitizer(string value) + /// + /// is null. + public BodyKeySanitizer(string jsonPath) { - Argument.AssertNotNull(value, nameof(value)); + Argument.AssertNotNull(jsonPath, nameof(jsonPath)); - Value = value; + JsonPath = jsonPath; } - /// Gets or sets the json path. - public string JsonPath { get; set; } - /// Gets the value. - public string Value { get; } + /// Gets the json path. + public string JsonPath { get; } + /// Gets or sets the value. + public string Value { get; set; } /// Gets or sets the regex. public string Regex { get; set; } /// Gets or sets the group for replace. diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.Serialization.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.Serialization.cs index d2f8ad69dc79..56a2e6dac478 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.Serialization.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.Serialization.cs @@ -17,8 +17,11 @@ void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) writer.WriteStartObject(); writer.WritePropertyName("regex"u8); writer.WriteStringValue(Regex); - writer.WritePropertyName("value"u8); - writer.WriteStringValue(Value); + if (Optional.IsDefined(Value)) + { + writer.WritePropertyName("value"u8); + writer.WriteStringValue(Value); + } if (Optional.IsDefined(GroupForReplace)) { writer.WritePropertyName("groupForReplace"u8); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.cs index dc40026ce935..e05f19ec524a 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/BodyRegexSanitizer.cs @@ -15,21 +15,18 @@ public partial class BodyRegexSanitizer { /// Initializes a new instance of BodyRegexSanitizer. /// - /// - /// or is null. - public BodyRegexSanitizer(string regex, string value) + /// is null. + public BodyRegexSanitizer(string regex) { Argument.AssertNotNull(regex, nameof(regex)); - Argument.AssertNotNull(value, nameof(value)); Regex = regex; - Value = value; } /// Gets the regex. public string Regex { get; } - /// Gets the value. - public string Value { get; } + /// Gets or sets the value. + public string Value { get; set; } /// Gets or sets the group for replace. public string GroupForReplace { get; set; } /// Condition to apply for the sanitization or transform. If the condition is not met, sanitization/transform is not performed. diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.Serialization.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.Serialization.cs index 4be8f40c2461..3f7b845c7fed 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.Serialization.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.Serialization.cs @@ -17,8 +17,11 @@ void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) writer.WriteStartObject(); writer.WritePropertyName("key"u8); writer.WriteStringValue(Key); - writer.WritePropertyName("value"u8); - writer.WriteStringValue(Value); + if (Optional.IsDefined(Value)) + { + writer.WritePropertyName("value"u8); + writer.WriteStringValue(Value); + } if (Optional.IsDefined(Regex)) { writer.WritePropertyName("regex"u8); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.cs index 292c844b8861..21328d5c5ece 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderRegexSanitizer.cs @@ -15,21 +15,18 @@ public partial class HeaderRegexSanitizer { /// Initializes a new instance of HeaderRegexSanitizer. /// - /// - /// or is null. - public HeaderRegexSanitizer(string key, string value) + /// is null. + public HeaderRegexSanitizer(string key) { Argument.AssertNotNull(key, nameof(key)); - Argument.AssertNotNull(value, nameof(value)); Key = key; - Value = value; } /// Gets the key. public string Key { get; } - /// Gets the value. - public string Value { get; } + /// Gets or sets the value. + public string Value { get; set; } /// Gets or sets the regex. public string Regex { get; set; } /// Gets or sets the group for replace. diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.Serialization.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.Serialization.cs index 104b78a727d9..477dc45f5101 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.Serialization.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.Serialization.cs @@ -17,8 +17,11 @@ void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) writer.WriteStartObject(); writer.WritePropertyName("key"u8); writer.WriteStringValue(Key); - writer.WritePropertyName("value"u8); - writer.WriteStringValue(Value); + if (Optional.IsDefined(Value)) + { + writer.WritePropertyName("value"u8); + writer.WriteStringValue(Value); + } if (Optional.IsDefined(Condition)) { writer.WritePropertyName("condition"u8); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.cs index eccaa0526381..ab2a51d3de7e 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/HeaderTransform.cs @@ -15,21 +15,18 @@ public partial class HeaderTransform { /// Initializes a new instance of HeaderTransform. /// - /// - /// or is null. - public HeaderTransform(string key, string value) + /// is null. + public HeaderTransform(string key) { Argument.AssertNotNull(key, nameof(key)); - Argument.AssertNotNull(value, nameof(value)); Key = key; - Value = value; } /// Gets the key. public string Key { get; } - /// Gets the value. - public string Value { get; } + /// Gets or sets the value. + public string Value { get; set; } /// Condition to apply for the sanitization or transform. If the condition is not met, sanitization/transform is not performed. public Condition Condition { get; set; } } diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.Serialization.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.Serialization.cs index 149f8fcfaff3..129fc51f66d3 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.Serialization.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.Serialization.cs @@ -17,8 +17,11 @@ void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) writer.WriteStartObject(); writer.WritePropertyName("regex"u8); writer.WriteStringValue(Regex); - writer.WritePropertyName("value"u8); - writer.WriteStringValue(Value); + if (Optional.IsDefined(Value)) + { + writer.WritePropertyName("value"u8); + writer.WriteStringValue(Value); + } if (Optional.IsDefined(GroupForReplace)) { writer.WritePropertyName("groupForReplace"u8); diff --git a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.cs index d66de6445e74..114444daa83d 100644 --- a/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/Generated/Models/UriRegexSanitizer.cs @@ -15,21 +15,18 @@ public partial class UriRegexSanitizer { /// Initializes a new instance of UriRegexSanitizer. /// - /// - /// or is null. - public UriRegexSanitizer(string regex, string value) + /// is null. + public UriRegexSanitizer(string regex) { Argument.AssertNotNull(regex, nameof(regex)); - Argument.AssertNotNull(value, nameof(value)); Regex = regex; - Value = value; } /// Gets the regex. public string Regex { get; } - /// Gets the value. - public string Value { get; } + /// Gets or sets the value. + public string Value { get; set; } /// Gets or sets the group for replace. public string GroupForReplace { get; set; } } diff --git a/sdk/core/Azure.Core.TestFramework/src/HeaderRegexSanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/HeaderRegexSanitizer.cs index f64ee849235f..8edac6ced22c 100644 --- a/sdk/core/Azure.Core.TestFramework/src/HeaderRegexSanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/HeaderRegexSanitizer.cs @@ -5,12 +5,13 @@ namespace Azure.Core.TestFramework.Models { public partial class HeaderRegexSanitizer { - public static HeaderRegexSanitizer CreateWithQueryParameter(string headerKey, string queryParameter, string value) => - new(headerKey, value) + public static HeaderRegexSanitizer CreateWithQueryParameter(string headerKey, string queryParameter, string sanitizedValue) => + new(headerKey) { // match the value of the query parameter up until the next ampersand or the end of the string Regex = $@"([\x0026|&|?]{queryParameter}=)(?[^&]+)", - GroupForReplace = "group" + GroupForReplace = "group", + Value = sanitizedValue }; } } diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs index 6e34afa2e4ef..a4954ad99345 100644 --- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs +++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs @@ -177,9 +177,10 @@ public string ReplacementHost { _replacementHost = value; UriRegexSanitizers.Add( - new UriRegexSanitizer(@"https://(?[^/]+)/", _replacementHost) + new UriRegexSanitizer(@"https://(?[^/]+)/") { - GroupForReplace = "host" + GroupForReplace = "host", + Value = _replacementHost }); } } diff --git a/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs b/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs index 44afcdc9d64a..434200d0a147 100644 --- a/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs +++ b/sdk/core/Azure.Core.TestFramework/src/TestRecording.cs @@ -99,7 +99,7 @@ private async Task ApplySanitizersAsync() { foreach (string header in _recordedTestBase.SanitizedHeaders) { - await _proxy.Client.AddHeaderSanitizerAsync(new HeaderRegexSanitizer(header, Sanitized), RecordingId); + await _proxy.Client.AddHeaderSanitizerAsync(new HeaderRegexSanitizer(header), RecordingId); } foreach (var header in _recordedTestBase.HeaderRegexSanitizers) @@ -128,7 +128,7 @@ await _proxy.Client.AddUriSanitizerAsync( foreach (string path in _recordedTestBase.JsonPathSanitizers) { - await _proxy.Client.AddBodyKeySanitizerAsync(new BodyKeySanitizer(Sanitized) { JsonPath = path }, RecordingId); + await _proxy.Client.AddBodyKeySanitizerAsync(new BodyKeySanitizer(path), RecordingId); } foreach (BodyKeySanitizer sanitizer in _recordedTestBase.BodyKeySanitizers) diff --git a/sdk/core/Azure.Core.TestFramework/src/UriRegexSanitizer.cs b/sdk/core/Azure.Core.TestFramework/src/UriRegexSanitizer.cs index 2772118d8845..5f2840e1aaa2 100644 --- a/sdk/core/Azure.Core.TestFramework/src/UriRegexSanitizer.cs +++ b/sdk/core/Azure.Core.TestFramework/src/UriRegexSanitizer.cs @@ -5,10 +5,11 @@ namespace Azure.Core.TestFramework.Models { public partial class UriRegexSanitizer { - public static UriRegexSanitizer CreateWithQueryParameter(string queryParameter, string value) => - new($@"([\x0026|&|?]{queryParameter}=)(?[^&]+)", value) + public static UriRegexSanitizer CreateWithQueryParameter(string queryParameter, string sanitizedValue) => + new($@"([\x0026|&|?]{queryParameter}=)(?[^&]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = sanitizedValue }; } } diff --git a/sdk/core/Azure.Core.TestFramework/src/testproxy.json b/sdk/core/Azure.Core.TestFramework/src/testproxy.json index 84a01751ceac..5012901cfc8d 100644 --- a/sdk/core/Azure.Core.TestFramework/src/testproxy.json +++ b/sdk/core/Azure.Core.TestFramework/src/testproxy.json @@ -700,8 +700,7 @@ } }, "required": [ - "key", - "value" + "key" ] }, "BodyKeySanitizer": { @@ -722,7 +721,7 @@ } }, "required": [ - "value" + "jsonPath" ] }, "BodyRegexSanitizer": { @@ -743,8 +742,7 @@ } }, "required": [ - "regex", - "value" + "regex" ] }, "HeaderRegexSanitizer": { @@ -765,8 +763,7 @@ } }, "required": [ - "key", - "value" + "key" ] }, "UriRegexSanitizer": { @@ -784,8 +781,7 @@ } }, "required": [ - "regex", - "value" + "regex" ] }, "Condition": { diff --git a/sdk/core/Azure.Core/perf/HttpMessageSanitizerBenchmark.cs b/sdk/core/Azure.Core/perf/HttpMessageSanitizerBenchmark.cs new file mode 100644 index 000000000000..ceb8256fc8cc --- /dev/null +++ b/sdk/core/Azure.Core/perf/HttpMessageSanitizerBenchmark.cs @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using BenchmarkDotNet.Attributes; + +namespace Azure.Core.Perf; + +[MemoryDiagnoser] +public class HttpMessageSanitizerBenchmark +{ + private HttpMessageSanitizer _sanitizer; + + [GlobalSetup] + public void Setup() + { + _sanitizer = new HttpMessageSanitizer( + allowedQueryParameters: new[] { "api-version" }, + allowedHeaders: Array.Empty() + ); + } + + [Benchmark] + public string SanitizeHeader() + { + return _sanitizer.SanitizeHeader("header", "value"); + } + + [Benchmark] + public string SanitizeUrl() + { + return _sanitizer.SanitizeUrl("https://www.example.com"); + } + + [Benchmark] + public string SanitizeUrlWithQueryNoValue() + { + return _sanitizer.SanitizeUrl("https://www.example.com?param1"); + } + + [Benchmark] + public string SanitizeUrlWithAllowedQuery() + { + return _sanitizer.SanitizeUrl("https://www.example.com?api-version=2024-05-01"); + } + + [Benchmark] + public string SanitizeUrlWithDisallowedQuery() + { + return _sanitizer.SanitizeUrl("https://www.example.com?param1=value1"); + } +} diff --git a/sdk/core/Azure.Core/src/Shared/HttpMessageSanitizer.cs b/sdk/core/Azure.Core/src/Shared/HttpMessageSanitizer.cs index 23162660e41a..36becf22a5d2 100644 --- a/sdk/core/Azure.Core/src/Shared/HttpMessageSanitizer.cs +++ b/sdk/core/Azure.Core/src/Shared/HttpMessageSanitizer.cs @@ -1,140 +1,198 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#nullable enable using System; using System.Collections.Generic; using System.Text; using System.Linq; -namespace Azure.Core +namespace Azure.Core; + +internal class HttpMessageSanitizer { - internal class HttpMessageSanitizer - { - private const string LogAllValue = "*"; - private readonly bool _logAllHeaders; - private readonly bool _logFullQueries; - private readonly string[] _allowedQueryParameters; - private readonly string _redactedPlaceholder; - private readonly HashSet _allowedHeaders; + private const string LogAllValue = "*"; + private readonly bool _logAllHeaders; + private readonly bool _logFullQueries; + private readonly string[] _allowedQueryParameters; + private readonly string _redactedPlaceholder; + private readonly HashSet _allowedHeaders; - internal static HttpMessageSanitizer Default = new HttpMessageSanitizer(Array.Empty(), Array.Empty()); + [ThreadStatic] + private static StringBuilder? s_cachedStringBuilder; + private const int MaxCachedStringBuilderCapacity = 1024; - public HttpMessageSanitizer(string[] allowedQueryParameters, string[] allowedHeaders, string redactedPlaceholder = "REDACTED") - { - _logAllHeaders = allowedHeaders.Contains(LogAllValue); - _logFullQueries = allowedQueryParameters.Contains(LogAllValue); + internal static HttpMessageSanitizer Default = new HttpMessageSanitizer(Array.Empty(), Array.Empty()); - _allowedQueryParameters = allowedQueryParameters; - _redactedPlaceholder = redactedPlaceholder; - _allowedHeaders = new HashSet(allowedHeaders, StringComparer.InvariantCultureIgnoreCase); - } + public HttpMessageSanitizer(string[] allowedQueryParameters, string[] allowedHeaders, string redactedPlaceholder = "REDACTED") + { + _logAllHeaders = allowedHeaders.Contains(LogAllValue); + _logFullQueries = allowedQueryParameters.Contains(LogAllValue); - public string SanitizeHeader(string name, string value) - { - if (_logAllHeaders || _allowedHeaders.Contains(name)) - { - return value; - } + _allowedQueryParameters = allowedQueryParameters; + _redactedPlaceholder = redactedPlaceholder; + _allowedHeaders = new HashSet(allowedHeaders, StringComparer.InvariantCultureIgnoreCase); + } - return _redactedPlaceholder; + public string SanitizeHeader(string name, string value) + { + if (_logAllHeaders || _allowedHeaders.Contains(name)) + { + return value; } - public string SanitizeUrl(string url) + return _redactedPlaceholder; + } + + public string SanitizeUrl(string url) + { + if (_logFullQueries) { - if (_logFullQueries) - { - return url; - } + return url; + } #if NET5_0_OR_GREATER - int indexOfQuerySeparator = url.IndexOf('?', StringComparison.Ordinal); + int indexOfQuerySeparator = url.IndexOf('?', StringComparison.Ordinal); #else - int indexOfQuerySeparator = url.IndexOf('?'); + int indexOfQuerySeparator = url.IndexOf('?'); #endif - if (indexOfQuerySeparator == -1) + if (indexOfQuerySeparator == -1) + { + return url; + } + + // PERF: Avoid allocations in this heavily-used method: + // 1. Use ReadOnlySpan to avoid creating substrings. + // 2. Defer creating a StringBuilder until absolutely necessary. + // 3. Use a rented StringBuilder to avoid allocating a new one + // each time. + + // Create the StringBuilder only when necessary (when we encounter + // a query parameter that needs to be redacted) + StringBuilder? stringBuilder = null; + + // Keeps track of the number of characters we've processed so far + // so that, if we need to create a StringBuilder, we know how many + // characters to copy over from the original URL. + int lengthSoFar = indexOfQuerySeparator + 1; + + ReadOnlySpan query = url.AsSpan(indexOfQuerySeparator + 1); // +1 to skip the '?' + + while (query.Length > 0) + { + int endOfParameterValue = query.IndexOf('&'); + int endOfParameterName = query.IndexOf('='); + bool noValue = false; + + // Check if we have parameter without value + if ((endOfParameterValue == -1 && endOfParameterName == -1) || + (endOfParameterValue != -1 && (endOfParameterName == -1 || endOfParameterName > endOfParameterValue))) { - return url; + endOfParameterName = endOfParameterValue; + noValue = true; } - StringBuilder stringBuilder = new StringBuilder(url.Length); - stringBuilder.Append(url, 0, indexOfQuerySeparator); + if (endOfParameterName == -1) + { + endOfParameterName = query.Length; + } - string query = url.Substring(indexOfQuerySeparator); + if (endOfParameterValue == -1) + { + endOfParameterValue = query.Length; + } + else + { + // include the separator + endOfParameterValue++; + } - int queryIndex = 1; - stringBuilder.Append('?'); + ReadOnlySpan parameterName = query.Slice(0, endOfParameterName); - do + bool isAllowed = false; + foreach (string name in _allowedQueryParameters) { - int endOfParameterValue = query.IndexOf('&', queryIndex); - int endOfParameterName = query.IndexOf('=', queryIndex); - bool noValue = false; - - // Check if we have parameter without value - if ((endOfParameterValue == -1 && endOfParameterName == -1) || - (endOfParameterValue != -1 && (endOfParameterName == -1 || endOfParameterName > endOfParameterValue))) + if (parameterName.Equals(name.AsSpan(), StringComparison.OrdinalIgnoreCase)) { - endOfParameterName = endOfParameterValue; - noValue = true; + isAllowed = true; + break; } + } - if (endOfParameterName == -1) - { - endOfParameterName = query.Length; - } + int valueLength = endOfParameterValue; + int nameLength = endOfParameterName; - if (endOfParameterValue == -1) + if (isAllowed || noValue) + { + if (stringBuilder is null) { - endOfParameterValue = query.Length; + lengthSoFar += valueLength; } else { - // include the separator - endOfParameterValue++; + AppendReadOnlySpan(stringBuilder, query.Slice(0, valueLength)); } + } + else + { + // Encountered a query value that needs to be redacted. + // Create the StringBuilder if we haven't already. + stringBuilder ??= RentStringBuilder(url.Length).Append(url, 0, lengthSoFar); - ReadOnlySpan parameterName = query.AsSpan(queryIndex, endOfParameterName - queryIndex); + AppendReadOnlySpan(stringBuilder, query.Slice(0, nameLength)) + .Append('=') + .Append(_redactedPlaceholder); - bool isAllowed = false; - foreach (string name in _allowedQueryParameters) + if (query[endOfParameterValue - 1] == '&') { - if (parameterName.Equals(name.AsSpan(), StringComparison.OrdinalIgnoreCase)) - { - isAllowed = true; - break; - } + stringBuilder.Append('&'); } + } + + query = query.Slice(valueLength); + } - int valueLength = endOfParameterValue - queryIndex; - int nameLength = endOfParameterName - queryIndex; + return stringBuilder is null ? url : ToStringAndReturnStringBuilder(stringBuilder); - if (isAllowed) - { - stringBuilder.Append(query, queryIndex, valueLength); - } - else - { - if (noValue) - { - stringBuilder.Append(query, queryIndex, valueLength); - } - else - { - stringBuilder.Append(query, queryIndex, nameLength); - stringBuilder.Append('='); - stringBuilder.Append(_redactedPlaceholder); - if (query[endOfParameterValue - 1] == '&') - { - stringBuilder.Append('&'); - } - } - } + static StringBuilder AppendReadOnlySpan(StringBuilder builder, ReadOnlySpan span) + { +#if NET6_0_OR_GREATER + return builder.Append(span); +#else + foreach (char c in span) + { + builder.Append(c); + } + + return builder; +#endif + } + } + + private static StringBuilder RentStringBuilder(int capacity) + { + if (capacity <= MaxCachedStringBuilderCapacity) + { + StringBuilder? builder = s_cachedStringBuilder; + if (builder is not null && builder.Capacity >= capacity) + { + s_cachedStringBuilder = null; + return builder; + } + } - queryIndex += valueLength; - } while (queryIndex < query.Length); + return new StringBuilder(capacity); + } - return stringBuilder.ToString(); + private static string ToStringAndReturnStringBuilder(StringBuilder builder) + { + string result = builder.ToString(); + if (builder.Capacity <= MaxCachedStringBuilderCapacity) + { + s_cachedStringBuilder = builder.Clear(); } + + return result; } } diff --git a/sdk/core/System.ClientModel/CHANGELOG.md b/sdk/core/System.ClientModel/CHANGELOG.md index 16ae29a238b2..7eab2e617278 100644 --- a/sdk/core/System.ClientModel/CHANGELOG.md +++ b/sdk/core/System.ClientModel/CHANGELOG.md @@ -4,10 +4,15 @@ ### Features Added -- Added `BufferResponse` property to `RequestOptions` so protocol method callers can override the client value for response content buffering. +- Added `BufferResponse` property to `RequestOptions` so protocol method callers can turn off response buffering if desired. +- Added `AsyncResultCollection` and `ResultCollection` for clients to return from service methods where the service response contains a collection of values. +- Added `AsyncPageableCollection`, `PageableCollection` and `ResultPage` for clients to return from service methods where collection values are delivered to the client over one or more service responses. +- Added `SetRawResponse` method to `ClientResult` to allow the response held by the result to be changed, for example by derived types that obtain multiple responses from polling the service. ### Breaking Changes +- `ClientResult.GetRawResponse` will now throw `InvalidOperationException` if called before the result's raw response is set, for example by collection result types that delay sending a request to the service until the collection is enumerated. + ### Bugs Fixed ### Other Changes diff --git a/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs b/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs index a7fe9b8604a5..53cdd65eb9a9 100644 --- a/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs +++ b/sdk/core/System.ClientModel/api/System.ClientModel.net6.0.cs @@ -7,6 +7,12 @@ public ApiKeyCredential(string key) { } public static implicit operator System.ClientModel.ApiKeyCredential (string key) { throw null; } public void Update(string key) { } } + public abstract partial class AsyncPageableCollection : System.ClientModel.AsyncResultCollection + { + protected AsyncPageableCollection() { } + public abstract System.Collections.Generic.IAsyncEnumerable> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?)); + public override System.Collections.Generic.IAsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } public abstract partial class AsyncResultCollection : System.ClientModel.ClientResult, System.Collections.Generic.IAsyncEnumerable { protected internal AsyncResultCollection() { } @@ -48,6 +54,12 @@ protected internal ClientResult(T value, System.ClientModel.Primitives.PipelineR public virtual T Value { get { throw null; } } public static implicit operator T (System.ClientModel.ClientResult result) { throw null; } } + public abstract partial class PageableCollection : System.ClientModel.ResultCollection + { + protected PageableCollection() { } + public abstract System.Collections.Generic.IEnumerable> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?)); + public override System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } + } public abstract partial class ResultCollection : System.ClientModel.ClientResult, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { protected internal ResultCollection() { } @@ -55,6 +67,13 @@ protected internal ResultCollection(System.ClientModel.Primitives.PipelineRespon public abstract System.Collections.Generic.IEnumerator GetEnumerator(); System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } } + public partial class ResultPage : System.ClientModel.ResultCollection + { + internal ResultPage() { } + public string? ContinuationToken { get { throw null; } } + public static System.ClientModel.ResultPage Create(System.Collections.Generic.IEnumerable values, string? continuationToken, System.ClientModel.Primitives.PipelineResponse response) { throw null; } + public override System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } + } } namespace System.ClientModel.Primitives { @@ -254,7 +273,7 @@ public sealed override void Process(System.ClientModel.Primitives.PipelineMessag public partial class RequestOptions { public RequestOptions() { } - public bool? BufferResponse { get { throw null; } set { } } + public bool BufferResponse { get { throw null; } set { } } public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } } public System.ClientModel.Primitives.ClientErrorBehaviors ErrorOptions { get { throw null; } set { } } public void AddHeader(string name, string value) { } diff --git a/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs b/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs index 15e1f1f75fae..e43b75c72c1e 100644 --- a/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs +++ b/sdk/core/System.ClientModel/api/System.ClientModel.netstandard2.0.cs @@ -7,6 +7,12 @@ public ApiKeyCredential(string key) { } public static implicit operator System.ClientModel.ApiKeyCredential (string key) { throw null; } public void Update(string key) { } } + public abstract partial class AsyncPageableCollection : System.ClientModel.AsyncResultCollection + { + protected AsyncPageableCollection() { } + public abstract System.Collections.Generic.IAsyncEnumerable> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?)); + public override System.Collections.Generic.IAsyncEnumerator GetAsyncEnumerator(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } public abstract partial class AsyncResultCollection : System.ClientModel.ClientResult, System.Collections.Generic.IAsyncEnumerable { protected internal AsyncResultCollection() { } @@ -48,6 +54,12 @@ protected internal ClientResult(T value, System.ClientModel.Primitives.PipelineR public virtual T Value { get { throw null; } } public static implicit operator T (System.ClientModel.ClientResult result) { throw null; } } + public abstract partial class PageableCollection : System.ClientModel.ResultCollection + { + protected PageableCollection() { } + public abstract System.Collections.Generic.IEnumerable> AsPages(string? continuationToken = null, int? pageSizeHint = default(int?)); + public override System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } + } public abstract partial class ResultCollection : System.ClientModel.ClientResult, System.Collections.Generic.IEnumerable, System.Collections.IEnumerable { protected internal ResultCollection() { } @@ -55,6 +67,13 @@ protected internal ResultCollection(System.ClientModel.Primitives.PipelineRespon public abstract System.Collections.Generic.IEnumerator GetEnumerator(); System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; } } + public partial class ResultPage : System.ClientModel.ResultCollection + { + internal ResultPage() { } + public string? ContinuationToken { get { throw null; } } + public static System.ClientModel.ResultPage Create(System.Collections.Generic.IEnumerable values, string? continuationToken, System.ClientModel.Primitives.PipelineResponse response) { throw null; } + public override System.Collections.Generic.IEnumerator GetEnumerator() { throw null; } + } } namespace System.ClientModel.Primitives { @@ -253,7 +272,7 @@ public sealed override void Process(System.ClientModel.Primitives.PipelineMessag public partial class RequestOptions { public RequestOptions() { } - public bool? BufferResponse { get { throw null; } set { } } + public bool BufferResponse { get { throw null; } set { } } public System.Threading.CancellationToken CancellationToken { get { throw null; } set { } } public System.ClientModel.Primitives.ClientErrorBehaviors ErrorOptions { get { throw null; } set { } } public void AddHeader(string name, string value) { } diff --git a/sdk/core/System.ClientModel/src/Convenience/AsyncPageableCollectionOfT.cs b/sdk/core/System.ClientModel/src/Convenience/AsyncPageableCollectionOfT.cs new file mode 100644 index 000000000000..1a36bab43a6b --- /dev/null +++ b/sdk/core/System.ClientModel/src/Convenience/AsyncPageableCollectionOfT.cs @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace System.ClientModel; + +/// +/// Represents a collection of results returned from a cloud service operation +/// sequentially over one or more calls to the service. +/// +public abstract class AsyncPageableCollection : AsyncResultCollection +{ + /// + /// Create a new instance of . + /// + /// This constructor does not take a + /// because derived types are expected to defer the first service call + /// until the collection is enumerated using await foreach. + /// + protected AsyncPageableCollection() : base() + { + } + + /// + /// Return an enumerable of that aynchronously + /// enumerates the collection's pages instead of the collection's individual + /// values. This may make multiple service requests. + /// + /// A token indicating where the collection + /// of results returned from the service should begin. Passing null + /// will start the collection at the first page of values. + /// The number of items to request that the + /// service return in a , if the service supports + /// such requests. + /// An async sequence of , each holding + /// the subset of collection values contained in a given service response. + /// + public abstract IAsyncEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default); + + /// + /// Return an enumerator that iterates asynchronously through the collection + /// values. This may make multiple service requests. + /// + /// The used + /// with requests made while enumerating asynchronously. + /// An that can iterate + /// asynchronously through the collection values. + public override async IAsyncEnumerator GetAsyncEnumerator(CancellationToken cancellationToken = default) + { + await foreach (ResultPage page in AsPages().ConfigureAwait(false).WithCancellation(cancellationToken)) + { + foreach (T value in page) + { + yield return value; + } + } + } +} diff --git a/sdk/core/System.ClientModel/src/Convenience/PageableCollectionOfT.cs b/sdk/core/System.ClientModel/src/Convenience/PageableCollectionOfT.cs new file mode 100644 index 000000000000..eff5d4f5e0c8 --- /dev/null +++ b/sdk/core/System.ClientModel/src/Convenience/PageableCollectionOfT.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace System.ClientModel; + +/// +/// Represents a collection of results returned from a cloud service operation +/// sequentially over one or more calls to the service. +/// +public abstract class PageableCollection : ResultCollection +{ + /// + /// Create a new instance of . + /// + /// This constructor does not take a + /// because derived types are expected to defer the first service call + /// until the collection is enumerated using foreach. + protected PageableCollection() : base() + { + } + + /// + /// Return an enumerable of that enumerates the + /// collection's pages instead of the collection's individual values. This + /// may make multiple service requests. + /// + /// A token indicating where the collection + /// of results returned from the service should begin. Passing null + /// will start the collection at the first page of values. + /// The number of items to request that the + /// service return in a , if the service supports + /// such requests. + /// A sequence of , each holding the + /// subset of collection values contained in a given service response. + /// + public abstract IEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default); + + /// + /// Return an enumerator that iterates through the collection values. This + /// may make multiple service requests. + /// + /// An that can iterate through the + /// collection values. + public override IEnumerator GetEnumerator() + { + foreach (ResultPage page in AsPages()) + { + foreach (T value in page) + { + yield return value; + } + } + } +} diff --git a/sdk/core/System.ClientModel/src/Convenience/ResultPageOfT.cs b/sdk/core/System.ClientModel/src/Convenience/ResultPageOfT.cs new file mode 100644 index 000000000000..9542295127ca --- /dev/null +++ b/sdk/core/System.ClientModel/src/Convenience/ResultPageOfT.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace System.ClientModel; + +/// +/// Represents the subset (or page) of results contained in a single response +/// from a cloud service returning a collection of results sequentially over +/// one or more calls to the service (i.e. a paged collection). +/// +public class ResultPage : ResultCollection +{ + private readonly IEnumerable _values; + + private ResultPage(IEnumerable values, string? continuationToken, PipelineResponse response) + : base(response) + { + _values = values; + ContinuationToken = continuationToken; + } + + /// + /// Creates a new . + /// + /// The values contained in . + /// + /// The token that can be used to request + /// the next page of results from the service, or null if this page + /// holds the final subset of values. + /// The holding the + /// collection values returned by the service. + /// An instance of holding the provided + /// values. + public static ResultPage Create(IEnumerable values, string? continuationToken, PipelineResponse response) + => new(values, continuationToken, response); + + /// + /// Gets the continuation token used to request the next + /// . May be null or empty when no values + /// remain to be returned from the collection. + /// + public string? ContinuationToken { get; } + + /// + public override IEnumerator GetEnumerator() + => _values.GetEnumerator(); +} diff --git a/sdk/core/System.ClientModel/src/Internal/SSE/AsyncServerSentEventEnumerable.cs b/sdk/core/System.ClientModel/src/Internal/SSE/AsyncServerSentEventEnumerable.cs index 2873f9568235..e7efca1805b1 100644 --- a/sdk/core/System.ClientModel/src/Internal/SSE/AsyncServerSentEventEnumerable.cs +++ b/sdk/core/System.ClientModel/src/Internal/SSE/AsyncServerSentEventEnumerable.cs @@ -17,30 +17,45 @@ internal class AsyncServerSentEventEnumerable : IAsyncEnumerable GetAsyncEnumerator(CancellationToken cancellationToken = default) { - return new AsyncServerSentEventEnumerator(_contentStream, cancellationToken); + return new AsyncServerSentEventEnumerator(_contentStream, this, cancellationToken); } private sealed class AsyncServerSentEventEnumerator : IAsyncEnumerator { - private readonly CancellationToken _cancellationToken; private readonly ServerSentEventReader _reader; + private readonly AsyncServerSentEventEnumerable _enumerable; + private readonly CancellationToken _cancellationToken; public ServerSentEvent Current { get; private set; } - public AsyncServerSentEventEnumerator(Stream contentStream, CancellationToken cancellationToken = default) + public AsyncServerSentEventEnumerator(Stream contentStream, + AsyncServerSentEventEnumerable enumerable, + CancellationToken cancellationToken = default) { _reader = new(contentStream); + _enumerable = enumerable; _cancellationToken = cancellationToken; } public async ValueTask MoveNextAsync() { ServerSentEvent? nextEvent = await _reader.TryGetNextEventAsync(_cancellationToken).ConfigureAwait(false); + _enumerable.LastEventId = _reader.LastEventId; + _enumerable.ReconnectionInterval = _reader.ReconnectionInterval; if (nextEvent.HasValue) { diff --git a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEvent.cs b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEvent.cs index 64d5a7197afa..f962dd2bac4b 100644 --- a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEvent.cs +++ b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEvent.cs @@ -9,24 +9,17 @@ namespace System.ClientModel.Internal; /// internal readonly struct ServerSentEvent { - // Gets the value of the SSE "event type" buffer, used to distinguish between event kinds. + // Gets the value of the SSE "event type" buffer, used to distinguish + // between event kinds. public string EventType { get; } - // Gets the value of the SSE "data" buffer, which holds the payload of the server-sent event. + // Gets the value of the SSE "data" buffer, which holds the payload of the + // server-sent event. public string Data { get; } - // Gets the value of the "last event ID" buffer, with which a user agent can reestablish a session. - public string? Id { get; } - - // If present, gets the defined "retry" value for the event, which represents the delay before reconnecting. - public TimeSpan? ReconnectionTime { get; } - - public ServerSentEvent(string type, string data, string? id, string? retry) + public ServerSentEvent(string type, string data) { EventType = type; Data = data; - Id = id; - ReconnectionTime = retry is null ? null : - int.TryParse(retry, out int time) ? TimeSpan.FromMilliseconds(time) : null; } } diff --git a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventEnumerable.cs b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventEnumerable.cs index 7d9dc995cc25..8c0ebca65681 100644 --- a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventEnumerable.cs +++ b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventEnumerable.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Threading; namespace System.ClientModel.Internal; @@ -16,12 +17,21 @@ internal class ServerSentEventEnumerable : IEnumerable public ServerSentEventEnumerable(Stream contentStream) { + Argument.AssertNotNull(contentStream, nameof(contentStream)); + _contentStream = contentStream; + + LastEventId = string.Empty; + ReconnectionInterval = Timeout.InfiniteTimeSpan; } + public string LastEventId { get; private set; } + + public TimeSpan ReconnectionInterval { get; private set; } + public IEnumerator GetEnumerator() { - return new ServerSentEventEnumerator(_contentStream); + return new ServerSentEventEnumerator(_contentStream, this); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); @@ -29,10 +39,12 @@ public IEnumerator GetEnumerator() private sealed class ServerSentEventEnumerator : IEnumerator { private readonly ServerSentEventReader _reader; + private readonly ServerSentEventEnumerable _enumerable; - public ServerSentEventEnumerator(Stream contentStream) + public ServerSentEventEnumerator(Stream contentStream, ServerSentEventEnumerable enumerable) { _reader = new(contentStream); + _enumerable = enumerable; } public ServerSentEvent Current { get; private set; } @@ -42,6 +54,8 @@ public ServerSentEventEnumerator(Stream contentStream) public bool MoveNext() { ServerSentEvent? nextEvent = _reader.TryGetNextEvent(); + _enumerable.LastEventId = _reader.LastEventId; + _enumerable.ReconnectionInterval= _reader.ReconnectionInterval; if (nextEvent.HasValue) { diff --git a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventReader.cs b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventReader.cs index ce19a38b56ae..e1e881743533 100644 --- a/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventReader.cs +++ b/sdk/core/System.ClientModel/src/Internal/SSE/ServerSentEventReader.cs @@ -16,18 +16,24 @@ namespace System.ClientModel.Internal; /// internal sealed class ServerSentEventReader { - private readonly Stream? _stream; - private readonly StreamReader? _reader; + private readonly StreamReader _reader; public ServerSentEventReader(Stream stream) { - // Creator of the reader has responsibility for disposing the stream - // passed to the reader constructor. + Argument.AssertNotNull(stream, nameof(stream)); - _stream = stream; + // The creator of the reader has responsibility for disposing the + // stream passed to the reader's constructor. _reader = new StreamReader(stream); + + LastEventId = string.Empty; + ReconnectionInterval = Timeout.InfiniteTimeSpan; } + public string LastEventId { get; private set; } + + public TimeSpan ReconnectionInterval { get; private set; } + /// /// Synchronously retrieves the next server-sent event from the underlying stream, blocking until a new event is /// available and returning null once no further data is present on the stream. @@ -38,11 +44,6 @@ public ServerSentEventReader(Stream stream) /// public ServerSentEvent? TryGetNextEvent(CancellationToken cancellationToken = default) { - if (_reader is null) - { - throw new ObjectDisposedException(nameof(ServerSentEventReader)); - } - PendingEvent pending = default; while (true) { @@ -77,11 +78,6 @@ public ServerSentEventReader(Stream stream) /// public async Task TryGetNextEventAsync(CancellationToken cancellationToken = default) { - if (_reader is null) - { - throw new ObjectDisposedException(nameof(ServerSentEventReader)); - } - PendingEvent pending = default; while (true) { @@ -106,7 +102,7 @@ public ServerSentEventReader(Stream stream) } } - private static void ProcessLine(string line, ref PendingEvent pending, out bool dispatch) + private void ProcessLine(string line, ref PendingEvent pending, out bool dispatch) { dispatch = false; @@ -139,10 +135,13 @@ private static void ProcessLine(string line, ref PendingEvent pending, out bool pending.DataFields.Add(field); break; case ServerSentEventFieldKind.Id: - pending.IdField = field; + LastEventId = field.Value.ToString(); break; case ServerSentEventFieldKind.Retry: - pending.RetryField = field; + if (field.Value.Length > 0 && int.TryParse(field.Value.ToString(), out int retry)) + { + ReconnectionInterval = TimeSpan.FromMilliseconds(retry); + } break; default: // Ignore @@ -160,8 +159,6 @@ private struct PendingEvent public int DataLength { get; set; } public List DataFields => _dataFields ??= new(); public ServerSentEventField? EventTypeField { get; set; } - public ServerSentEventField? IdField { get; set; } - public ServerSentEventField? RetryField { get; set; } public ServerSentEvent ToEvent() { @@ -172,12 +169,6 @@ public ServerSentEvent ToEvent() EventTypeField.Value.Value.ToString() : "message"; - string? id = IdField.HasValue && IdField.Value.Value.Length > 0 ? - IdField.Value.Value.ToString() : default; - - string? retry = RetryField.HasValue && RetryField.Value.Value.Length > 0 ? - RetryField.Value.Value.ToString() : default; - Memory buffer = new(new char[DataLength]); int curr = 0; @@ -195,7 +186,7 @@ public ServerSentEvent ToEvent() // Per spec, remove trailing LF from concatenated data fields. string data = buffer.Slice(0, buffer.Length - 1).ToString(); - return new ServerSentEvent(type, data, id, retry); + return new ServerSentEvent(type, data); } } } diff --git a/sdk/core/System.ClientModel/src/Options/RequestOptions.cs b/sdk/core/System.ClientModel/src/Options/RequestOptions.cs index f7649c0b8eab..b12167ee7343 100644 --- a/sdk/core/System.ClientModel/src/Options/RequestOptions.cs +++ b/sdk/core/System.ClientModel/src/Options/RequestOptions.cs @@ -16,6 +16,7 @@ public class RequestOptions private CancellationToken _cancellationToken = CancellationToken.None; private ClientErrorBehaviors _errorOptions = ClientErrorBehaviors.Default; + private bool _bufferResponse = true; private PipelinePolicy[]? _perCallPolicies; private PipelinePolicy[]? _perTryPolicies; @@ -23,8 +24,6 @@ public class RequestOptions private List? _headersUpdates; - private bool? _bufferResponse; - /// /// Initializes a new instance of the class /// @@ -64,15 +63,14 @@ public ClientErrorBehaviors ErrorOptions /// /// Gets or sets a value indicating whether the response content should be - /// buffered in-memory by the pipeline. If specified, this value will - /// override any client default. + /// buffered in-memory by the pipeline. This value defaults to true. /// /// Please note that setting this value to false will result /// in the obtained from /// holding a live network stream. /// It is the responsibility of the caller to ensure the stream is disposed. /// - public bool? BufferResponse + public bool BufferResponse { get => _bufferResponse; set @@ -174,11 +172,8 @@ protected internal virtual void Apply(PipelineMessage message) message.PerTryPolicies = _perTryPolicies; message.BeforeTransportPolicies = _beforeTransportPolicies; - // Override any BufferResponse value set on the message. - if (BufferResponse.HasValue) - { - message.BufferResponse = BufferResponse.Value; - } + // Tell transport whether or not to buffer response content. + message.BufferResponse = BufferResponse; // Apply adds and sets to request headers if applicable. if (_headersUpdates is not null) diff --git a/sdk/core/System.ClientModel/tests/Convenience/ClientResultTests.cs b/sdk/core/System.ClientModel/tests/Convenience/ClientResultTests.cs index 629f1ec27f2b..2c592dce0d98 100644 --- a/sdk/core/System.ClientModel/tests/Convenience/ClientResultTests.cs +++ b/sdk/core/System.ClientModel/tests/Convenience/ClientResultTests.cs @@ -8,7 +8,7 @@ namespace System.ClientModel.Tests.Results; -public class PipelineResponseTests +public class ClientResultTests { #region ClientResult diff --git a/sdk/core/System.ClientModel/tests/Convenience/PageableCollectionTests.cs b/sdk/core/System.ClientModel/tests/Convenience/PageableCollectionTests.cs new file mode 100644 index 000000000000..48092dd8b27d --- /dev/null +++ b/sdk/core/System.ClientModel/tests/Convenience/PageableCollectionTests.cs @@ -0,0 +1,271 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using ClientModel.Tests.Mocks; +using NUnit.Framework; + +namespace System.ClientModel.Tests.Results; + +public class PageableCollectionTests +{ + private static readonly string[] MockPageContents = { """ + [ + { "intValue" : 0, "stringValue" : "0" }, + { "intValue" : 1, "stringValue" : "1" }, + { "intValue" : 2, "stringValue" : "2" } + ] + """,""" + [ + { "intValue" : 3, "stringValue" : "3" }, + { "intValue" : 4, "stringValue" : "4" }, + { "intValue" : 5, "stringValue" : "5" } + ] + """,""" + [ + { "intValue" : 6, "stringValue" : "6" }, + { "intValue" : 7, "stringValue" : "7" }, + { "intValue" : 8, "stringValue" : "8" } + ] + """, + }; + + private static readonly int PageCount = MockPageContents.Length; + private static readonly int ItemCount = 9; + + [Test] + public void CanEnumerateValues() + { + MockPageableClient client = new(); + PageableCollection models = client.GetModels(MockPageContents); + + int i = 0; + foreach (MockJsonModel model in models) + { + Assert.AreEqual(i, model.IntValue); + Assert.AreEqual(i.ToString(), model.StringValue); + + i++; + } + + Assert.AreEqual(ItemCount, i); + } + + [Test] + public void CanEnumeratePages() + { + MockPageableClient client = new(); + PageableCollection models = client.GetModels(MockPageContents); + + int pageCount = 0; + int itemCount = 0; + foreach (ResultPage page in models.AsPages()) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(itemCount, model.IntValue); + Assert.AreEqual(itemCount.ToString(), model.StringValue); + + itemCount++; + } + + pageCount++; + } + + Assert.AreEqual(ItemCount, itemCount); + Assert.AreEqual(PageCount, pageCount); + } + + [Test] + public void CanStartPageEnumerationMidwayThrough() + { + MockPageableClient client = new(); + PageableCollection models = client.GetModels(MockPageContents); + + int pageCount = 0; + int i = 6; + + // Request just the last page by starting at the last seen value + // on the prior page -- i.e. item 5. + foreach (ResultPage page in models.AsPages(continuationToken: "5")) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(i, model.IntValue); + Assert.AreEqual(i.ToString(), model.StringValue); + + i++; + } + + pageCount++; + } + + Assert.AreEqual(ItemCount, i); + Assert.AreEqual(1, pageCount); + } + + [Test] + public void CanSetPageSizeHint() + { + MockPageableClient client = new(); + PageableCollection models = client.GetModels(MockPageContents); + var pages = models.AsPages(pageSizeHint: 10); + foreach (var _ in pages) + { + // page size hint is ignored in this mock + } + + Assert.AreEqual(10, client.RequestedPageSize); + } + + [Test] + public void CanGetRawResponses() + { + MockPageableClient client = new(); + PageableCollection models = client.GetModels(MockPageContents); + + int pageCount = 0; + int itemCount = 0; + foreach (ResultPage page in models.AsPages()) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(itemCount, model.IntValue); + Assert.AreEqual(itemCount.ToString(), model.StringValue); + + itemCount++; + } + + PipelineResponse collectionResponse = models.GetRawResponse(); + PipelineResponse pageResponse = page.GetRawResponse(); + + Assert.AreEqual(pageResponse, collectionResponse); + Assert.AreEqual(MockPageContents[pageCount], pageResponse.Content.ToString()); + Assert.AreEqual(MockPageContents[pageCount], collectionResponse.Content.ToString()); + + pageCount++; + } + + Assert.AreEqual(ItemCount, itemCount); + Assert.AreEqual(PageCount, pageCount); + } + + [Test] + public async Task CanEnumerateValuesAsync() + { + MockPageableClient client = new(); + AsyncPageableCollection models = client.GetModelsAsync(MockPageContents); + + int i = 0; + await foreach (MockJsonModel model in models) + { + Assert.AreEqual(i, model.IntValue); + Assert.AreEqual(i.ToString(), model.StringValue); + + i++; + } + + Assert.AreEqual(ItemCount, i); + } + + [Test] + public async Task CanEnumeratePagesAsync() + { + MockPageableClient client = new(); + AsyncPageableCollection models = client.GetModelsAsync(MockPageContents); + + int pageCount = 0; + int itemCount = 0; + await foreach (ResultPage page in models.AsPages()) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(itemCount, model.IntValue); + Assert.AreEqual(itemCount.ToString(), model.StringValue); + + itemCount++; + } + + pageCount++; + } + + Assert.AreEqual(ItemCount, itemCount); + Assert.AreEqual(PageCount, pageCount); + } + + [Test] + public async Task CanStartPageEnumerationMidwayThroughAsync() + { + MockPageableClient client = new(); + AsyncPageableCollection models = client.GetModelsAsync(MockPageContents); + + int pageCount = 0; + int i = 6; + + // Request just the last page by starting at the last seen value + // on the prior page -- i.e. item 5. + await foreach (ResultPage page in models.AsPages(continuationToken: "5")) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(i, model.IntValue); + Assert.AreEqual(i.ToString(), model.StringValue); + + i++; + } + + pageCount++; + } + + Assert.AreEqual(ItemCount, i); + Assert.AreEqual(1, pageCount); + } + + [Test] + public async Task CanSetPageSizeHintAsync() + { + MockPageableClient client = new(); + AsyncPageableCollection models = client.GetModelsAsync(MockPageContents); + var pages = models.AsPages(pageSizeHint: 10); + await foreach (var _ in pages) + { + // page size hint is ignored in this mock + } + + Assert.AreEqual(10, client.RequestedPageSize); + } + + [Test] + public async Task CanGetRawResponsesAsync() + { + MockPageableClient client = new(); + AsyncPageableCollection models = client.GetModelsAsync(MockPageContents); + + int pageCount = 0; + int itemCount = 0; + await foreach (ResultPage page in models.AsPages()) + { + foreach (MockJsonModel model in page) + { + Assert.AreEqual(itemCount, model.IntValue); + Assert.AreEqual(itemCount.ToString(), model.StringValue); + + itemCount++; + } + + PipelineResponse collectionResponse = models.GetRawResponse(); + PipelineResponse pageResponse = page.GetRawResponse(); + + Assert.AreEqual(pageResponse, collectionResponse); + Assert.AreEqual(MockPageContents[pageCount], pageResponse.Content.ToString()); + Assert.AreEqual(MockPageContents[pageCount], collectionResponse.Content.ToString()); + + pageCount++; + } + + Assert.AreEqual(ItemCount, itemCount); + Assert.AreEqual(PageCount, pageCount); + } +} diff --git a/sdk/core/System.ClientModel/tests/Options/RequestOptionsTests.cs b/sdk/core/System.ClientModel/tests/Options/RequestOptionsTests.cs index 66b9ba2f9d1d..8099080e1a2e 100644 --- a/sdk/core/System.ClientModel/tests/Options/RequestOptionsTests.cs +++ b/sdk/core/System.ClientModel/tests/Options/RequestOptionsTests.cs @@ -164,7 +164,7 @@ public void CannotModifyOptionsAfterExplicitlyFrozen() } [Test] - public void OverridesBufferResponse() + public void SetsBufferResponse() { ClientPipeline pipeline = ClientPipeline.Create(); PipelineMessage message = pipeline.CreateMessage(); @@ -181,23 +181,4 @@ public void OverridesBufferResponse() Assert.IsFalse(message.BufferResponse); } - - [Test] - public void DoesntChangeBufferResponse() - { - RequestOptions options = new() { BufferResponse = null }; - - ClientPipeline pipeline = ClientPipeline.Create(); - PipelineMessage message = pipeline.CreateMessage(); - - message.BufferResponse = false; - message.Apply(options); - - Assert.IsFalse(message.BufferResponse); - - message.BufferResponse = true; - message.Apply(options); - - Assert.IsTrue(message.BufferResponse); - } } diff --git a/sdk/core/System.ClientModel/tests/TestFramework/JsonModelList.cs b/sdk/core/System.ClientModel/tests/TestFramework/JsonModelList.cs new file mode 100644 index 000000000000..4ce5fd591436 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/TestFramework/JsonModelList.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; + +namespace ClientModel.Tests.Internal; + +internal class JsonModelList : List, IJsonModel> + where TModel : IJsonModel +{ + public JsonModelList Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JsonModelList)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeJsonModelList(document.RootElement, options); + } + + public JsonModelList Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeJsonModelList(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(JsonModelList)} does not support reading '{options.Format}' format."); + } + } + + internal static JsonModelList DeserializeJsonModelList(JsonElement element, ModelReaderWriterOptions? options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind != JsonValueKind.Array) + { + throw new InvalidOperationException("Cannot deserialize JsonModelList from JSON that is not an array."); + } + + JsonModelList list = new(); + + foreach (JsonElement item in element.EnumerateArray()) + { + // TODO: Make efficient + TModel? value = ModelReaderWriter.Read(BinaryData.FromString(item.ToString()), options) ?? + throw new InvalidOperationException("Failed to deserialized array element."); + list.Add(value); + } + + return list; + } + + public string GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JsonModelList)} does not support writing '{format}' format."); + } + + writer.WriteStartArray(); + + foreach (IJsonModel item in this) + { + item.Write(writer, options); + } + + writer.WriteEndArray(); + } + + public BinaryData Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + + return format switch + { + "J" => ModelReaderWriter.Write(this, options), + _ => throw new FormatException($"The model {nameof(JsonModelList)} does not support writing '{options.Format}' format."), + }; + } +} diff --git a/sdk/core/System.ClientModel/tests/TestFramework/Mocks/MockPageableClient.cs b/sdk/core/System.ClientModel/tests/TestFramework/Mocks/MockPageableClient.cs new file mode 100644 index 000000000000..0ad116f70c94 --- /dev/null +++ b/sdk/core/System.ClientModel/tests/TestFramework/Mocks/MockPageableClient.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using ClientModel.Tests.Internal; + +namespace ClientModel.Tests.Mocks; + +public class MockPageableClient +{ + public bool ProtocolMethodCalled { get; private set; } + public int? RequestedPageSize { get; private set; } + + // mock convenience method - async + public virtual AsyncPageableCollection GetModelsAsync(string[] pageContents) + { + PipelineResponse? lastResponse = default; + + // The contract for this pageable implementation is that the last seen + // value id (where the id is StringValue) provides the continuation token + // for the page. + + int pageNumber = 0; + JsonModelList values = new(); + + async Task> firstPageFuncAsync(int? pageSize) + { + ClientResult result = await GetModelsAsync(pageContents[pageNumber++], options: null).ConfigureAwait(false); + lastResponse = result.GetRawResponse(); + values = ModelReaderWriter.Read>(lastResponse.Content)!; + string? continuationToken = pageNumber < pageContents.Length ? values[values.Count - 1].StringValue : null; + return ResultPage.Create(values, continuationToken, lastResponse); + } + + async Task> nextPageFuncAsync(string? continuationToken, int? pageSize) + { + RequestedPageSize = pageSize; + + bool atRequestedPage = values.Count > 0 && values.Last().StringValue == continuationToken; + while (!atRequestedPage && pageNumber < pageContents.Length) + { + BinaryData content = BinaryData.FromString(pageContents[pageNumber++]); + JsonModelList pageValues = ModelReaderWriter.Read>(content)!; + atRequestedPage = pageValues[pageValues.Count - 1].StringValue == continuationToken; + } + + Debug.Assert(atRequestedPage is true); + + ClientResult result = await GetModelsAsync(pageContents[pageNumber++], options: null).ConfigureAwait(false); + lastResponse = result.GetRawResponse(); + values = ModelReaderWriter.Read>(lastResponse.Content)!; + continuationToken = pageNumber < pageContents.Length ? values[values.Count - 1].StringValue : null; + return ResultPage.Create(values, continuationToken, lastResponse); + } + + return PageableResultHelpers.Create(firstPageFuncAsync, nextPageFuncAsync); + } + + // mock convenience method - sync + public virtual PageableCollection GetModels(string[] pageContents) + { + PipelineResponse? lastResponse = default; + + // The contract for this pageable implementation is that the last seen + // value id (where the id is StringValue) provides the continuation token + // for the page. + + int pageNumber = 0; + JsonModelList values = new(); + + ResultPage firstPageFunc(int? pageSize) + { + ClientResult result = GetModels(pageContents[pageNumber++], options: null); + lastResponse = result.GetRawResponse(); + values = ModelReaderWriter.Read>(lastResponse.Content)!; + string? continuationToken = pageNumber < pageContents.Length ? values[values.Count - 1].StringValue : null; + return ResultPage.Create(values, continuationToken, lastResponse); + } + + ResultPage nextPageFunc(string? continuationToken, int? pageSize) + { + RequestedPageSize = pageSize; + + bool atRequestedPage = values.Count > 0 && values.Last().StringValue == continuationToken; + while (!atRequestedPage && pageNumber < pageContents.Length) + { + BinaryData content = BinaryData.FromString(pageContents[pageNumber++]); + JsonModelList pageValues = ModelReaderWriter.Read>(content)!; + atRequestedPage = pageValues[pageValues.Count - 1].StringValue == continuationToken; + } + + Debug.Assert(atRequestedPage is true); + + ClientResult result = GetModels(pageContents[pageNumber++], options: null); + lastResponse = result.GetRawResponse(); + values = ModelReaderWriter.Read>(lastResponse.Content)!; + continuationToken = pageNumber < pageContents.Length ? values[values.Count - 1].StringValue : null; + return ResultPage.Create(values, continuationToken, lastResponse); + } + + return PageableResultHelpers.Create(firstPageFunc, nextPageFunc); + } + + // mock protocol method - async + public virtual async Task GetModelsAsync(string pageContent, RequestOptions? options = default) + { + await Task.Delay(0); + + MockPipelineResponse response = new(200); + response.SetContent(pageContent); + + ProtocolMethodCalled = true; + + return ClientResult.FromResponse(response); + } + + // mock protocol method - sync + public virtual ClientResult GetModels(string pageContent, RequestOptions? options = default) + { + MockPipelineResponse response = new(200); + response.SetContent(pageContent); + + ProtocolMethodCalled = true; + + return ClientResult.FromResponse(response); + } +} diff --git a/sdk/core/System.ClientModel/tests/TestFramework/PageableResultHelpers.cs b/sdk/core/System.ClientModel/tests/TestFramework/PageableResultHelpers.cs new file mode 100644 index 000000000000..6013ede13cdc --- /dev/null +++ b/sdk/core/System.ClientModel/tests/TestFramework/PageableResultHelpers.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ClientModel.Tests.Internal; + +internal class PageableResultHelpers +{ + public static PageableCollection Create(Func> firstPageFunc, Func>? nextPageFunc, int? pageSize = default) where T : notnull + { + ResultPage first(string? _, int? pageSizeHint) => firstPageFunc(pageSizeHint); + return new FuncPageable(first, nextPageFunc, pageSize); + } + + public static AsyncPageableCollection Create(Func>> firstPageFunc, Func>>? nextPageFunc, int? pageSize = default) where T : notnull + { + Task> first(string? _, int? pageSizeHint) => firstPageFunc(pageSizeHint); + return new FuncAsyncPageable(first, nextPageFunc, pageSize); + } + + private class FuncAsyncPageable : AsyncPageableCollection where T : notnull + { + private readonly Func>> _firstPageFunc; + private readonly Func>>? _nextPageFunc; + private readonly int? _defaultPageSize; + + public FuncAsyncPageable(Func>> firstPageFunc, Func>>? nextPageFunc, int? defaultPageSize = default) + { + _firstPageFunc = firstPageFunc; + _nextPageFunc = nextPageFunc; + _defaultPageSize = defaultPageSize; + } + + public override async IAsyncEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) + { + Func>>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; + + if (pageFunc == null) + { + yield break; + } + + int? pageSize = pageSizeHint ?? _defaultPageSize; + do + { + ResultPage page = await pageFunc(continuationToken, pageSize).ConfigureAwait(false); + SetRawResponse(page.GetRawResponse()); + yield return page; + continuationToken = page.ContinuationToken; + pageFunc = _nextPageFunc; + } + while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); + } + } + + private class FuncPageable : PageableCollection where T : notnull + { + private readonly Func> _firstPageFunc; + private readonly Func>? _nextPageFunc; + private readonly int? _defaultPageSize; + + public FuncPageable(Func> firstPageFunc, Func>? nextPageFunc, int? defaultPageSize = default) + { + _firstPageFunc = firstPageFunc; + _nextPageFunc = nextPageFunc; + _defaultPageSize = defaultPageSize; + } + + public override IEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) + { + Func>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; + + if (pageFunc == null) + { + yield break; + } + + int? pageSize = pageSizeHint ?? _defaultPageSize; + do + { + ResultPage page = pageFunc(continuationToken, pageSize); + SetRawResponse(page.GetRawResponse()); + yield return page; + continuationToken = page.ContinuationToken; + pageFunc = _nextPageFunc; + } + while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); + } + } +} diff --git a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/AsyncServerSentEventEnumerableTests.cs b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/AsyncServerSentEventEnumerableTests.cs index 385e2fc58c84..fe511057338c 100644 --- a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/AsyncServerSentEventEnumerableTests.cs +++ b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/AsyncServerSentEventEnumerableTests.cs @@ -6,6 +6,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using ClientModel.Tests.Internal.Mocks; using NUnit.Framework; namespace System.ClientModel.Tests.Convenience; @@ -15,7 +16,7 @@ public class AsyncServerSentEventEnumerableTests [Test] public async Task EnumeratesEvents() { - using Stream contentStream = BinaryData.FromString(_mockContent).ToStream(); + using Stream contentStream = BinaryData.FromString(MockSseClient.DefaultMockContent).ToStream(); AsyncServerSentEventEnumerable enumerable = new(contentStream); List events = new(); @@ -30,7 +31,7 @@ public async Task EnumeratesEvents() for (int i = 0; i < 3; i++) { Assert.AreEqual($"event.{i}", events[i].EventType); - Assert.AreEqual($"{{ \"id\": \"{i}\", \"object\": {i} }}", events[i].Data); + Assert.AreEqual($"{{ \"IntValue\": {i}, \"StringValue\": \"{i}\" }}", events[i].Data); } } @@ -39,30 +40,10 @@ public void ThrowsIfCancelled() { CancellationToken token = new(true); - using Stream contentStream = BinaryData.FromString(_mockContent).ToStream(); + using Stream contentStream = BinaryData.FromString(MockSseClient.DefaultMockContent).ToStream(); AsyncServerSentEventEnumerable enumerable = new(contentStream); IAsyncEnumerator enumerator = enumerable.GetAsyncEnumerator(token); Assert.ThrowsAsync(async () => await enumerator.MoveNextAsync()); } - - #region Helpers - - private readonly string _mockContent = """ - event: event.0 - data: { "id": "0", "object": 0 } - - event: event.1 - data: { "id": "1", "object": 1 } - - event: event.2 - data: { "id": "2", "object": 2 } - - event: done - data: [DONE] - - - """; - - #endregion } diff --git a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ClientResultCollectionTests.cs b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ClientResultCollectionTests.cs index 16ef1d4546b3..8e2fb8d3095e 100644 --- a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ClientResultCollectionTests.cs +++ b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ClientResultCollectionTests.cs @@ -17,61 +17,11 @@ public ClientResultCollectionTests(bool isAsync) : base(isAsync) { } - [Test] - public async Task EnumeratesDataValues() - { - MockSseClient client = new(); - ClientResult result = client.GetModelsStreamingAsync(_mockContent, new RequestOptions()); - - int i = 0; - await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents()) - { - MockJsonModel model = data.ToObjectFromJson(); - - Assert.AreEqual(i, model.IntValue); - Assert.AreEqual(i.ToString(), model.StringValue); - - i++; - } - - Assert.AreEqual(3, i); - } - - [Test] - public void DataCollectionThrowsIfCancelled() - { - MockSseClient client = new(); - ClientResult result = client.GetModelsStreamingAsync(_mockContent, new RequestOptions()); - - // Set it to `cancelled: true` to validate functionality. - CancellationToken token = new(true); - - Assert.ThrowsAsync(async () => - { - await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents().WithCancellation(token)) - { - } - }); - } - - [Test] - public async Task DataCollectionDoesNotDisposeStream() - { - MockSseClient client = new(); - ClientResult result = client.GetModelsStreamingAsync(_mockContent, new RequestOptions()); - - await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents()) - { - } - - Assert.DoesNotThrow(() => { var p = result.GetRawResponse().ContentStream!.Position; }); - } - [Test] public async Task EnumeratesModelValues() { MockSseClient client = new(); - AsyncResultCollection models = client.GetModelsStreamingAsync(_mockContent); + AsyncResultCollection models = client.GetModelsStreamingAsync(); int i = 0; await foreach (MockJsonModel model in models) @@ -89,7 +39,7 @@ public async Task EnumeratesModelValues() public async Task ModelCollectionDelaysSendingRequest() { MockSseClient client = new(); - AsyncResultCollection models = client.GetModelsStreamingAsync(_mockContent); + AsyncResultCollection models = client.GetModelsStreamingAsync(); Assert.IsFalse(client.ProtocolMethodCalled); @@ -110,7 +60,7 @@ public async Task ModelCollectionDelaysSendingRequest() public void ModelCollectionThrowsIfCancelled() { MockSseClient client = new(); - AsyncResultCollection models = client.GetModelsStreamingAsync(_mockContent); + AsyncResultCollection models = client.GetModelsStreamingAsync(); // Set it to `cancelled: true` to validate functionality. CancellationToken token = new(true); @@ -127,7 +77,7 @@ public void ModelCollectionThrowsIfCancelled() public async Task ModelCollectionDisposesStream() { MockSseClient client = new(); - AsyncResultCollection models = client.GetModelsStreamingAsync(_mockContent); + AsyncResultCollection models = client.GetModelsStreamingAsync(); await foreach (MockJsonModel model in models) { @@ -141,7 +91,7 @@ public async Task ModelCollectionDisposesStream() public void ModelCollectionGetRawResponseThrowsBeforeEnumerated() { MockSseClient client = new(); - AsyncResultCollection models = client.GetModelsStreamingAsync(_mockContent); + AsyncResultCollection models = client.GetModelsStreamingAsync(); Assert.Throws(() => { PipelineResponse response = models.GetRawResponse(); }); } @@ -162,23 +112,53 @@ public async Task StopsOnStringBasedTerminalEvent() Assert.IsTrue(empty); } - #region Helpers + [Test] + public async Task EnumeratesDataValues() + { + MockSseClient client = new(); + ClientResult result = client.GetModelsStreamingAsync(MockSseClient.DefaultMockContent, new RequestOptions()); - private readonly string _mockContent = """ - event: event.0 - data: { "IntValue": 0, "StringValue": "0" } + int i = 0; + await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents()) + { + MockJsonModel model = data.ToObjectFromJson(); - event: event.1 - data: { "IntValue": 1, "StringValue": "1" } + Assert.AreEqual(i, model.IntValue); + Assert.AreEqual(i.ToString(), model.StringValue); - event: event.2 - data: { "IntValue": 2, "StringValue": "2" } + i++; + } - event: done - data: [DONE] + Assert.AreEqual(3, i); + } + [Test] + public void DataCollectionThrowsIfCancelled() + { + MockSseClient client = new(); + ClientResult result = client.GetModelsStreamingAsync(MockSseClient.DefaultMockContent, new RequestOptions()); - """; + // Set it to `cancelled: true` to validate functionality. + CancellationToken token = new(true); - #endregion + Assert.ThrowsAsync(async () => + { + await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents().WithCancellation(token)) + { + } + }); + } + + [Test] + public async Task DataCollectionDoesNotDisposeStream() + { + MockSseClient client = new(); + ClientResult result = client.GetModelsStreamingAsync(MockSseClient.DefaultMockContent, new RequestOptions()); + + await foreach (BinaryData data in result.GetRawResponse().EnumerateDataEvents()) + { + } + + Assert.DoesNotThrow(() => { var p = result.GetRawResponse().ContentStream!.Position; }); + } } diff --git a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventEnumerableTests.cs b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventEnumerableTests.cs index 0ec39af761e3..d32835fa7486 100644 --- a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventEnumerableTests.cs +++ b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventEnumerableTests.cs @@ -4,6 +4,7 @@ using System.ClientModel.Internal; using System.Collections.Generic; using System.IO; +using ClientModel.Tests.Internal.Mocks; using NUnit.Framework; namespace System.ClientModel.Tests.Convenience; @@ -13,7 +14,7 @@ public class ServerSentEventEnumerableTests [Test] public void EnumeratesEvents() { - using Stream contentStream = BinaryData.FromString(_mockContent).ToStream(); + using Stream contentStream = BinaryData.FromString(MockSseClient.DefaultMockContent).ToStream(); ServerSentEventEnumerable enumerable = new(contentStream); List events = new(); @@ -28,27 +29,7 @@ public void EnumeratesEvents() for (int i = 0; i < 3; i++) { Assert.AreEqual($"event.{i}", events[i].EventType); - Assert.AreEqual($"{{ \"id\": \"{i}\", \"object\": {i} }}", events[i].Data); + Assert.AreEqual($"{{ \"IntValue\": {i}, \"StringValue\": \"{i}\" }}", events[i].Data); } } - - #region Helpers - - private readonly string _mockContent = """ - event: event.0 - data: { "id": "0", "object": 0 } - - event: event.1 - data: { "id": "1", "object": 1 } - - event: event.2 - data: { "id": "2", "object": 2 } - - event: done - data: [DONE] - - - """; - - #endregion } diff --git a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventReaderTests.cs b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventReaderTests.cs index 07aac8f2aff2..67365117e576 100644 --- a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventReaderTests.cs +++ b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventReaderTests.cs @@ -21,7 +21,7 @@ public ServerSentEventReaderTests(bool isAsync) : base(isAsync) [Test] public async Task GetsEventsFromStream() { - Stream contentStream = BinaryData.FromString(_mockContent).ToStream(); + Stream contentStream = BinaryData.FromString(MockSseClient.DefaultMockContent).ToStream(); ServerSentEventReader reader = new(contentStream); List events = new(); @@ -38,7 +38,7 @@ public async Task GetsEventsFromStream() { ServerSentEvent sse = events[i]; Assert.AreEqual($"event.{i}", sse.EventType); - Assert.AreEqual($"{{ \"id\": \"{i}\", \"object\": {i} }}", sse.Data); + Assert.AreEqual($"{{ \"IntValue\": {i}, \"StringValue\": \"{i}\" }}", sse.Data); } Assert.AreEqual("done", events[3].EventType); @@ -89,10 +89,12 @@ public async Task HandlesDoneEvent() ServerSentEvent? sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); Assert.IsNotNull(sse); + Assert.AreEqual("stop", sse.Value.EventType); Assert.AreEqual("~stop~", sse.Value.Data); - Assert.IsNull(sse.Value.Id); - Assert.IsNull(sse.Value.ReconnectionTime); + + Assert.AreEqual(string.Empty, reader.LastEventId); + Assert.AreEqual(Timeout.InfiniteTimeSpan, reader.ReconnectionInterval); } [Test] @@ -110,9 +112,11 @@ public async Task ConcatenatesDataLines() ServerSentEvent? sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); Assert.IsNotNull(sse); + Assert.AreEqual("YHOO\n+2\n10", sse.Value.Data); - Assert.IsNull(sse.Value.Id); - Assert.IsNull(sse.Value.ReconnectionTime); + + Assert.AreEqual(string.Empty, reader.LastEventId); + Assert.AreEqual(Timeout.InfiniteTimeSpan, reader.ReconnectionInterval); } [Test] @@ -128,10 +132,9 @@ public async Task DefaultsEventTypeToMessage() ServerSentEvent? sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); Assert.IsNotNull(sse); + Assert.AreEqual("message", sse.Value.EventType); Assert.AreEqual("data", sse.Value.Data); - Assert.IsNull(sse.Value.Id); - Assert.IsNull(sse.Value.ReconnectionTime); } [Test] @@ -154,24 +157,27 @@ public async Task SecondTestCaseFromSpec() ServerSentEventReader reader = new(contentStream); List events = new(); + List ids = new(); ServerSentEvent? sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); while (sse is not null) { events.Add(sse.Value); + ids.Add(reader.LastEventId.ToString()); + sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); } Assert.AreEqual(3, events.Count); Assert.AreEqual("first event", events[0].Data); - Assert.AreEqual("1", events[0].Id); + Assert.AreEqual("1", ids[0]); Assert.AreEqual("second event", events[1].Data); - Assert.IsNull(events[1].Id); + Assert.AreEqual(string.Empty, ids[1]); Assert.AreEqual(" third event", events[2].Data); - Assert.IsNull(events[2].Id); + Assert.AreEqual(string.Empty, ids[2]); } [Test] @@ -229,35 +235,56 @@ public async Task FourthSpecTestCase() } [Test] - public void ThrowsIfCancelled() + public async Task SetsReconnectionInterval() { - CancellationToken token = new(true); + Stream contentStream = BinaryData.FromString(""" + data: test - using Stream contentStream = BinaryData.FromString(_mockContent).ToStream(); + data: test + retry: 2500 + + data: test + retry: + + + """).ToStream(); ServerSentEventReader reader = new(contentStream); - Assert.ThrowsAsync(async () - => await reader.TryGetNextEventAsync(token)); - } + List events = new(); + List retryValues = new(); - #region Helpers + ServerSentEvent? sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); + while (sse is not null) + { + events.Add(sse.Value); + retryValues.Add(reader.ReconnectionInterval); - // Note: raw string literal quirk removes \n from final line. - private readonly string _mockContent = """ - event: event.0 - data: { "id": "0", "object": 0 } + sse = await reader.TryGetNextEventSyncOrAsync(IsAsync); + } + + Assert.AreEqual(3, events.Count); - event: event.1 - data: { "id": "1", "object": 1 } + // Defaults to infinite timespan + Assert.AreEqual("test", events[0].Data); + Assert.AreEqual(Timeout.InfiniteTimeSpan, retryValues[0]); - event: event.2 - data: { "id": "2", "object": 2 } + Assert.AreEqual("test", events[1].Data); + Assert.AreEqual(new TimeSpan(0, 0, 0, 2, 500), retryValues[1]); - event: done - data: [DONE] + // Ignores invalid values + Assert.AreEqual("test", events[2].Data); + Assert.AreEqual(new TimeSpan(0, 0, 0, 2, 500), retryValues[2]); + } + [Test] + public void ThrowsIfCancelled() + { + CancellationToken token = new(true); - """; + using Stream contentStream = BinaryData.FromString(MockSseClient.DefaultMockContent).ToStream(); + ServerSentEventReader reader = new(contentStream); - #endregion + Assert.ThrowsAsync(async () + => await reader.TryGetNextEventAsync(token)); + } } diff --git a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventTests.cs b/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventTests.cs deleted file mode 100644 index 2c4e13f2695d..000000000000 --- a/sdk/core/System.ClientModel/tests/internal/Convenience/SSE/ServerSentEventTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System.ClientModel.Internal; -using NUnit.Framework; - -namespace System.ClientModel.Tests.Convenience; - -public class ServerSentEventTests -{ - [Test] - public void ParsesReconnectionTime() - { - string retryTimeInMillis = "2500"; - ServerSentEvent sse = new("message", "data", id: default, retryTimeInMillis); - - Assert.AreEqual("message", sse.EventType); - Assert.AreEqual("data", sse.Data); - Assert.IsNull(sse.Id); - Assert.AreEqual(new TimeSpan(0, 0, 0, 2, 500), sse.ReconnectionTime); - } -} diff --git a/sdk/core/System.ClientModel/tests/internal/TestFramework/Mocks/MockSseClient.cs b/sdk/core/System.ClientModel/tests/internal/TestFramework/Mocks/MockSseClient.cs index 9461b0b52f18..2113d2acb047 100644 --- a/sdk/core/System.ClientModel/tests/internal/TestFramework/Mocks/MockSseClient.cs +++ b/sdk/core/System.ClientModel/tests/internal/TestFramework/Mocks/MockSseClient.cs @@ -21,10 +21,27 @@ namespace ClientModel.Tests.Internal.Mocks; // will no longer be needed. public class MockSseClient { + // Note: raw string literal removes \n from final line. + internal const string DefaultMockContent = """ + event: event.0 + data: { "IntValue": 0, "StringValue": "0" } + + event: event.1 + data: { "IntValue": 1, "StringValue": "1" } + + event: event.2 + data: { "IntValue": 2, "StringValue": "2" } + + event: done + data: [DONE] + + + """; + public bool ProtocolMethodCalled { get; private set; } // mock convenience method - public virtual AsyncResultCollection GetModelsStreamingAsync(string content) + public virtual AsyncResultCollection GetModelsStreamingAsync(string content = DefaultMockContent) { return new AsyncMockJsonModelCollection(content, GetModelsStreamingAsync); } @@ -114,7 +131,7 @@ async ValueTask IAsyncEnumerator.MoveNextAsync() } BinaryData data = BinaryData.FromString(_events.Current.Data); - MockJsonModel? model = ModelReaderWriter.Read(data) ?? + MockJsonModel model = ModelReaderWriter.Read(data) ?? throw new JsonException($"Failed to deserialize expected type MockJsonModel from sse data payload '{_events.Current.Data}'."); _current = model; diff --git a/sdk/documentintelligence/Azure.AI.DocumentIntelligence/tests/Infrastructure/DocumentIntelligenceLiveTestBase.cs b/sdk/documentintelligence/Azure.AI.DocumentIntelligence/tests/Infrastructure/DocumentIntelligenceLiveTestBase.cs index 751d9e56d5d4..4aaa1076cc8e 100644 --- a/sdk/documentintelligence/Azure.AI.DocumentIntelligence/tests/Infrastructure/DocumentIntelligenceLiveTestBase.cs +++ b/sdk/documentintelligence/Azure.AI.DocumentIntelligence/tests/Infrastructure/DocumentIntelligenceLiveTestBase.cs @@ -15,7 +15,7 @@ public DocumentIntelligenceLiveTestBase(bool isAsync, RecordedTestMode? mode = n : base(isAsync, mode) { JsonPathSanitizers.Add("$..accessToken"); - BodyKeySanitizers.Add(new BodyKeySanitizer("https://sanitized.blob.core.windows.net") { JsonPath = "$..containerUrl" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("$..containerUrl") { Value = "https://sanitized.blob.core.windows.net" }); SanitizedHeaders.Add("Ocp-Apim-Subscription-Key"); } diff --git a/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Customization/ReceiveDetails.cs b/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Customization/ReceiveDetails.cs index 2a9f26803f8b..75054c104369 100644 --- a/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Customization/ReceiveDetails.cs +++ b/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Customization/ReceiveDetails.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -14,7 +15,7 @@ public partial class ReceiveDetails public Azure.Messaging.CloudEvent Event { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteEvent(Utf8JsonWriter writer) + internal void WriteEvent(Utf8JsonWriter writer, ModelReaderWriterOptions options) { JsonSerializer.Serialize(writer, Event); } diff --git a/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Generated/ReceiveDetails.Serialization.cs b/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Generated/ReceiveDetails.Serialization.cs index 22f640e45609..8ca7b782f788 100644 --- a/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Generated/ReceiveDetails.Serialization.cs +++ b/sdk/eventgrid/Azure.Messaging.EventGrid.Namespaces/src/Generated/ReceiveDetails.Serialization.cs @@ -29,7 +29,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOp writer.WritePropertyName("brokerProperties"u8); writer.WriteObjectValue(BrokerProperties, options); writer.WritePropertyName("event"u8); - WriteEvent(writer); + WriteEvent(writer, options); if (options.Format != "W" && _serializedAdditionalRawData != null) { foreach (var item in _serializedAdditionalRawData) diff --git a/sdk/formrecognizer/Azure.AI.FormRecognizer/tests/Infrastructure/DocumentAnalysisLiveTestBase.cs b/sdk/formrecognizer/Azure.AI.FormRecognizer/tests/Infrastructure/DocumentAnalysisLiveTestBase.cs index e3de8620497b..7594aec2e501 100644 --- a/sdk/formrecognizer/Azure.AI.FormRecognizer/tests/Infrastructure/DocumentAnalysisLiveTestBase.cs +++ b/sdk/formrecognizer/Azure.AI.FormRecognizer/tests/Infrastructure/DocumentAnalysisLiveTestBase.cs @@ -34,7 +34,7 @@ public DocumentAnalysisLiveTestBase(bool isAsync, DocumentAnalysisClientOptions. }; JsonPathSanitizers.Add("$..accessToken"); - BodyKeySanitizers.Add(new BodyKeySanitizer("https://sanitized.blob.core.windows.net") { JsonPath = "$..containerUrl" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("$..containerUrl") { Value = "https://sanitized.blob.core.windows.net" }); SanitizedHeaders.Add(Constants.AuthorizationHeader); } diff --git a/sdk/healthcareapis/Azure.ResourceManager.HealthcareApis/tests/HealthcareApisManagementTestBase.cs b/sdk/healthcareapis/Azure.ResourceManager.HealthcareApis/tests/HealthcareApisManagementTestBase.cs index 1e3c8461d384..cdc8f8dc9e3e 100644 --- a/sdk/healthcareapis/Azure.ResourceManager.HealthcareApis/tests/HealthcareApisManagementTestBase.cs +++ b/sdk/healthcareapis/Azure.ResourceManager.HealthcareApis/tests/HealthcareApisManagementTestBase.cs @@ -24,16 +24,32 @@ protected HealthcareApisManagementTestBase(bool isAsync, RecordedTestMode mode) : base(isAsync, mode) { JsonPathSanitizers.Add("$..authority"); - UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+api-version=(?[a-z0-9-]+)", "**") { GroupForReplace = "group" }); - UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+/eventhubs/[^/]+api-version=(?[a-z0-9-]+)", "**") { GroupForReplace = "group" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+api-version=(?[a-z0-9-]+)") + { + GroupForReplace = "group", + Value = "**" + }); + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+/eventhubs/[^/]+api-version=(?[a-z0-9-]+)") + { + GroupForReplace = "group", + Value = "**" + }); } protected HealthcareApisManagementTestBase(bool isAsync) : base(isAsync) { JsonPathSanitizers.Add("$..authority"); - UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+api-version=(?[a-z0-9-]+)", "**") { GroupForReplace = "group" }); - UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+/eventhubs/[^/]+api-version=(?[a-z0-9-]+)", "**") { GroupForReplace = "group" }); + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+api-version=(?[a-z0-9-]+)") + { + GroupForReplace = "group", + Value = "**" + }); + UriRegexSanitizers.Add(new UriRegexSanitizer(@"/Microsoft.EventHub/namespaces/[^/]+/eventhubs/[^/]+api-version=(?[a-z0-9-]+)") + { + GroupForReplace = "group", + Value = "**" + }); } [SetUp] diff --git a/sdk/identity/Azure.Identity/README.md b/sdk/identity/Azure.Identity/README.md index 2dd125963d19..854c8fc2653e 100644 --- a/sdk/identity/Azure.Identity/README.md +++ b/sdk/identity/Azure.Identity/README.md @@ -237,7 +237,7 @@ Not all credentials require this configuration. Credentials which authenticate t |Credential | Usage | Reference |-|-|- -|`AzurePipelinesCredential`|Supports [Microsoft Entra Workload ID](https://learn.microsoft.com/azure/devops/pipelines/release/configure-workload-identity?view=azure-devops) on Azure Pipelines.| [example](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/OtherCredentialSamples.md#AzurePipelinesCredential_example) +|[`AzurePipelinesCredential`][ref_AzurePipelinesCredential]|Supports [Microsoft Entra Workload ID](https://learn.microsoft.com/azure/devops/pipelines/release/configure-workload-identity?view=azure-devops) on Azure Pipelines.| [example](https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/identity/Azure.Identity/samples/OtherCredentialSamples.md#AzurePipelinesCredential_example) |[`ClientAssertionCredential`][ref_ClientAssertionCredential]|Authenticates a service principal using a signed client assertion. | |[`ClientCertificateCredential`][ref_ClientCertificateCredential]|Authenticates a service principal using a certificate. | [Service principal authentication](https://learn.microsoft.com/entra/identity-platform/app-objects-and-service-principals) |[`ClientSecretCredential`][ref_ClientSecretCredential]|Authenticates a service principal using a secret. | [Service principal authentication](https://learn.microsoft.com/entra/identity-platform/app-objects-and-service-principals) @@ -448,6 +448,7 @@ This project has adopted the [Microsoft Open Source Code of Conduct][code_of_con [ref_AuthorizationCodeCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.authorizationcodecredential?view=azure-dotnet [ref_AzureCliCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.azureclicredential?view=azure-dotnet [ref_AzureDeveloperCliCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.azuredeveloperclicredential?view=azure-dotnet +[ref_AzurePipelinesCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.azurepipelinescredential?view=azure-dotnet [ref_AzurePowerShellCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.azurepowershellcredential?view=azure-dotnet [ref_ChainedTokenCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.chainedtokencredential?view=azure-dotnet [ref_ClientAssertionCredential]: https://learn.microsoft.com/dotnet/api/azure.identity.clientassertioncredential?view=azure-dotnet diff --git a/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs b/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs index 6d04b1eb31d4..535a08859ddd 100644 --- a/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs +++ b/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs @@ -115,6 +115,7 @@ public BrowserCustomizationOptions() { } } public partial class ChainedTokenCredential : Azure.Core.TokenCredential { + protected ChainedTokenCredential() { } public ChainedTokenCredential(params Azure.Core.TokenCredential[] sources) { } public override Azure.Core.AccessToken GetToken(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override System.Threading.Tasks.ValueTask GetTokenAsync(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -180,6 +181,7 @@ public CredentialUnavailableException(string message, System.Exception innerExce } public partial class DefaultAzureCredential : Azure.Core.TokenCredential { + protected DefaultAzureCredential() { } public DefaultAzureCredential(Azure.Identity.DefaultAzureCredentialOptions options) { } public DefaultAzureCredential(bool includeInteractiveCredentials = false) { } public override Azure.Core.AccessToken GetToken(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } diff --git a/sdk/identity/Azure.Identity/src/Credentials/AuthorizationCodeCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/AuthorizationCodeCredential.cs index cfa97718e60a..4eb1bf6ed984 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/AuthorizationCodeCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/AuthorizationCodeCredential.cs @@ -29,7 +29,7 @@ public class AuthorizationCodeCredential : TokenCredential internal TenantIdResolverBase TenantIdResolver { get; } /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected AuthorizationCodeCredential() { diff --git a/sdk/identity/Azure.Identity/src/Credentials/AzurePipelinesCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/AzurePipelinesCredential.cs index a7e1865ff3a5..346384d5a177 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/AzurePipelinesCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/AzurePipelinesCredential.cs @@ -25,7 +25,7 @@ public class AzurePipelinesCredential : TokenCredential private const string OIDC_API_VERSION = "7.1"; /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected AzurePipelinesCredential() { } diff --git a/sdk/identity/Azure.Identity/src/Credentials/ChainedTokenCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/ChainedTokenCredential.cs index 731fc68056c1..9c9952ee56aa 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/ChainedTokenCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/ChainedTokenCredential.cs @@ -37,9 +37,9 @@ public class ChainedTokenCredential : TokenCredential private readonly TokenCredential[] _sources; /// - /// Constructor for instrumenting in tests + /// Protected constructor for mocking. /// - internal ChainedTokenCredential() + protected ChainedTokenCredential() { _sources = Array.Empty(); } diff --git a/sdk/identity/Azure.Identity/src/Credentials/ClientAssertionCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/ClientAssertionCredential.cs index 99dd14402b1e..dc6db0723335 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/ClientAssertionCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/ClientAssertionCredential.cs @@ -25,7 +25,7 @@ public class ClientAssertionCredential : TokenCredential internal TenantIdResolverBase TenantIdResolver { get; } /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected ClientAssertionCredential() { } diff --git a/sdk/identity/Azure.Identity/src/Credentials/ClientCertificateCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/ClientCertificateCredential.cs index c45c2b2ca123..37d5473bc71c 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/ClientCertificateCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/ClientCertificateCredential.cs @@ -41,7 +41,7 @@ public class ClientCertificateCredential : TokenCredential internal TenantIdResolverBase TenantIdResolver { get; } /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected ClientCertificateCredential() { } diff --git a/sdk/identity/Azure.Identity/src/Credentials/ClientSecretCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/ClientSecretCredential.cs index 9109eae22f5e..d703d750f4f1 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/ClientSecretCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/ClientSecretCredential.cs @@ -40,7 +40,7 @@ public class ClientSecretCredential : TokenCredential internal TenantIdResolverBase TenantIdResolver { get; } /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected ClientSecretCredential() { diff --git a/sdk/identity/Azure.Identity/src/Credentials/DefaultAzureCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/DefaultAzureCredential.cs index 16b1c6bc547b..cfea7989d1b8 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/DefaultAzureCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/DefaultAzureCredential.cs @@ -64,7 +64,10 @@ public class DefaultAzureCredential : TokenCredential internal TokenCredential[] _sources; - internal DefaultAzureCredential() : this(false) { } + /// + /// Protected constructor for mocking. + /// + protected DefaultAzureCredential() : this(false) { } /// /// Creates an instance of the DefaultAzureCredential class. diff --git a/sdk/identity/Azure.Identity/src/Credentials/ManagedIdentityCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/ManagedIdentityCredential.cs index b533817542f0..c5665314c25d 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/ManagedIdentityCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/ManagedIdentityCredential.cs @@ -27,7 +27,7 @@ public class ManagedIdentityCredential : TokenCredential "See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot"; /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected ManagedIdentityCredential() { } diff --git a/sdk/identity/Azure.Identity/src/Credentials/OnBehalfOfCredential.cs b/sdk/identity/Azure.Identity/src/Credentials/OnBehalfOfCredential.cs index 2af8a645310e..e92895a5a871 100644 --- a/sdk/identity/Azure.Identity/src/Credentials/OnBehalfOfCredential.cs +++ b/sdk/identity/Azure.Identity/src/Credentials/OnBehalfOfCredential.cs @@ -26,7 +26,7 @@ public class OnBehalfOfCredential : TokenCredential internal TenantIdResolverBase TenantIdResolver { get; } /// - /// Protected constructor for mocking. + /// Protected constructor for mocking. /// protected OnBehalfOfCredential() { } diff --git a/sdk/identity/Azure.Identity/tests/AzurePipelinesCredentialTests.cs b/sdk/identity/Azure.Identity/tests/AzurePipelinesCredentialTests.cs index d56ff1de76ab..2c38e3daa795 100644 --- a/sdk/identity/Azure.Identity/tests/AzurePipelinesCredentialTests.cs +++ b/sdk/identity/Azure.Identity/tests/AzurePipelinesCredentialTests.cs @@ -40,7 +40,8 @@ public override TokenCredential GetTokenCredential(CommonCredentialTestConfig co PlanId = "myplan", JobId = "myjob", TeamProjectId = "myteamproject", - SystemAccessToken = "mytoken" + SystemAccessToken = "mytoken", + HubName = "myhub", }; if (config.Transport != null) { diff --git a/sdk/identity/Azure.Identity/tests/IdentityRecordedTestBase.cs b/sdk/identity/Azure.Identity/tests/IdentityRecordedTestBase.cs index a005f4500850..711800a04833 100644 --- a/sdk/identity/Azure.Identity/tests/IdentityRecordedTestBase.cs +++ b/sdk/identity/Azure.Identity/tests/IdentityRecordedTestBase.cs @@ -37,14 +37,14 @@ private void InitializeRecordingSettings() SanitizedHeaders.Add("secret"); JsonPathSanitizers.Add("$..refresh_token"); JsonPathSanitizers.Add("$..access_token"); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"=[^&|}|""]+", "=" + SanitizeValue) + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"=[^&|}|""]+") { - Condition = new Condition { UriRegex = ".*/token([?].*)?$" } + Condition = new Condition { UriRegex = ".*/token([?].*)?$" }, + Value = "=" + SanitizeValue }); - HeaderTransforms.Add(new HeaderTransform( - "WWW-Authenticate", - $"Basic realm={Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "mock-arc-mi-key.key")}") + HeaderTransforms.Add(new HeaderTransform("WWW-Authenticate") { + Value = $"Basic realm={Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "mock-arc-mi-key.key")}", Condition = new Condition { ResponseHeader = new HeaderCondition diff --git a/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/LoadTestTestsBase.cs b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/LoadTestTestsBase.cs index e340544586b1..66d94e03b28e 100644 --- a/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/LoadTestTestsBase.cs +++ b/sdk/loadtestservice/Azure.Developer.LoadTesting/tests/LoadTestTestsBase.cs @@ -68,10 +68,9 @@ public LoadTestTestsBase(bool isAsync) : base(isAsync) _testRunId = "test-run-id-from-csharp-sdk"; _testHelper = new TestHelper(); - BodyKeySanitizers.Add(new BodyKeySanitizer(SanitizeValue) + BodyKeySanitizers.Add(new BodyKeySanitizer("$..url") { GroupForReplace = "group", - JsonPath = "$..url", Regex = @"sig=(?.*?)(?=$|&)" }); } diff --git a/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Custom/Models/MaintenanceConfigurationData.cs b/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Custom/Models/MaintenanceConfigurationData.cs index 59778e77190f..066dc0e41f7e 100644 --- a/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Custom/Models/MaintenanceConfigurationData.cs +++ b/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Custom/Models/MaintenanceConfigurationData.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -12,13 +13,13 @@ namespace Azure.ResourceManager.Maintenance public partial class MaintenanceConfigurationData { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void SerializeStartOn(Utf8JsonWriter writer) + internal void SerializeStartOn(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStringValue(StartOn.Value, "yyyy-MM-dd HH:mm"); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void SerializeExpireOn(Utf8JsonWriter writer) + internal void SerializeExpireOn(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStringValue(ExpireOn.Value, "yyyy-MM-dd HH:mm"); } diff --git a/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Generated/MaintenanceConfigurationData.Serialization.cs b/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Generated/MaintenanceConfigurationData.Serialization.cs index 8efc805cfa00..e573d220c723 100644 --- a/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Generated/MaintenanceConfigurationData.Serialization.cs +++ b/sdk/maintenance/Azure.ResourceManager.Maintenance/src/Generated/MaintenanceConfigurationData.Serialization.cs @@ -99,12 +99,12 @@ void IJsonModel.Write(Utf8JsonWriter writer, Model if (Optional.IsDefined(StartOn)) { writer.WritePropertyName("startDateTime"u8); - SerializeStartOn(writer); + SerializeStartOn(writer, options); } if (Optional.IsDefined(ExpireOn)) { writer.WritePropertyName("expirationDateTime"u8); - SerializeExpireOn(writer); + SerializeExpireOn(writer, options); } if (Optional.IsDefined(Duration)) { diff --git a/sdk/maps/Azure.Maps.Rendering/CHANGELOG.md b/sdk/maps/Azure.Maps.Rendering/CHANGELOG.md index 9c99e8d2398b..35b260804eca 100644 --- a/sdk/maps/Azure.Maps.Rendering/CHANGELOG.md +++ b/sdk/maps/Azure.Maps.Rendering/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 1.0.0-beta.4 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 1.0.0-beta.3 (2024-05-07) ### Bugs Fixed diff --git a/sdk/maps/Azure.Maps.Rendering/src/Azure.Maps.Rendering.csproj b/sdk/maps/Azure.Maps.Rendering/src/Azure.Maps.Rendering.csproj index 0433df609d6e..e923e7afc18b 100644 --- a/sdk/maps/Azure.Maps.Rendering/src/Azure.Maps.Rendering.csproj +++ b/sdk/maps/Azure.Maps.Rendering/src/Azure.Maps.Rendering.csproj @@ -2,7 +2,7 @@ Azure Maps Azure.Maps.Rendering Azure Maps Azure.Maps.Rendering - 1.0.0-beta.3 + 1.0.0-beta.4 Azure;Azure Maps;Maps Azure.Maps.Rendering $(RequiredTargetFrameworks) $(NoWarn);AZC0012 diff --git a/sdk/maps/Azure.Maps.Search/CHANGELOG.md b/sdk/maps/Azure.Maps.Search/CHANGELOG.md index 58271a2bef5e..f9ab74aae114 100644 --- a/sdk/maps/Azure.Maps.Search/CHANGELOG.md +++ b/sdk/maps/Azure.Maps.Search/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 1.0.0-beta.6 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 1.0.0-beta.5 (2024-05-07) ### Bugs Fixed diff --git a/sdk/maps/Azure.Maps.Search/src/Azure.Maps.Search.csproj b/sdk/maps/Azure.Maps.Search/src/Azure.Maps.Search.csproj index c9cc8fc462d0..7480472f03fb 100644 --- a/sdk/maps/Azure.Maps.Search/src/Azure.Maps.Search.csproj +++ b/sdk/maps/Azure.Maps.Search/src/Azure.Maps.Search.csproj @@ -2,7 +2,7 @@ Azure Maps Azure.Maps.Search Azure Maps Azure.Maps.Search - 1.0.0-beta.5 + 1.0.0-beta.6 Azure;Azure Maps;Maps Azure.Maps.Search true $(RequiredTargetFrameworks) diff --git a/sdk/metricsadvisor/Azure.AI.MetricsAdvisor/tests/MetricsAdvisorLiveTestBase.cs b/sdk/metricsadvisor/Azure.AI.MetricsAdvisor/tests/MetricsAdvisorLiveTestBase.cs index 441276c37c1c..1770a4328bad 100644 --- a/sdk/metricsadvisor/Azure.AI.MetricsAdvisor/tests/MetricsAdvisorLiveTestBase.cs +++ b/sdk/metricsadvisor/Azure.AI.MetricsAdvisor/tests/MetricsAdvisorLiveTestBase.cs @@ -31,7 +31,7 @@ public MetricsAdvisorLiveTestBase(bool isAsync, RecordedTestMode? mode = default JsonPathSanitizers.Add("$..accountKey"); JsonPathSanitizers.Add("$..authHeader"); JsonPathSanitizers.Add("$..httpHeader"); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"\w+@microsoft.com", "foo@contoso.com")); + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"\w+@microsoft.com") { Value = "foo@contoso.com" }); } internal const string DetectionConfigurationId = "78f3a4e7-fe53-4a05-9f4d-d724ab6c23a7"; diff --git a/sdk/migrationdiscoverysap/Azure.ResourceManager.MigrationDiscoverySap/tests/Tests/MigrationSapDiscoveryTests.cs b/sdk/migrationdiscoverysap/Azure.ResourceManager.MigrationDiscoverySap/tests/Tests/MigrationSapDiscoveryTests.cs index 166d66ca11d7..d38d4fe00ac9 100644 --- a/sdk/migrationdiscoverysap/Azure.ResourceManager.MigrationDiscoverySap/tests/Tests/MigrationSapDiscoveryTests.cs +++ b/sdk/migrationdiscoverysap/Azure.ResourceManager.MigrationDiscoverySap/tests/Tests/MigrationSapDiscoveryTests.cs @@ -25,7 +25,7 @@ public class MigrationSapDiscoveryTests : MigrationDiscoverySapManagementTestBas { public MigrationSapDiscoveryTests(bool isAsync) : base(isAsync) { - BodyKeySanitizers.Add(new BodyKeySanitizer(SanitizeValue) { JsonPath = "properties.discoveryExcelSasUri" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.discoveryExcelSasUri")); } [TestCase] diff --git a/sdk/monitor/Azure.ResourceManager.Monitor/src/Customized/Models/MonitorScaleCapacity.Serialization.cs b/sdk/monitor/Azure.ResourceManager.Monitor/src/Customized/Models/MonitorScaleCapacity.Serialization.cs index 52256490dd0d..d16ce26ce475 100644 --- a/sdk/monitor/Azure.ResourceManager.Monitor/src/Customized/Models/MonitorScaleCapacity.Serialization.cs +++ b/sdk/monitor/Azure.ResourceManager.Monitor/src/Customized/Models/MonitorScaleCapacity.Serialization.cs @@ -4,6 +4,7 @@ #nullable disable using System; +using System.ClientModel.Primitives; using System.Globalization; using System.Runtime.CompilerServices; using System.Text.Json; @@ -17,7 +18,7 @@ namespace Azure.ResourceManager.Monitor.Models public partial class MonitorScaleCapacity : IUtf8JsonSerializable { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteMinimum(Utf8JsonWriter writer) + internal void WriteMinimum(Utf8JsonWriter writer, ModelReaderWriterOptions options) { WriteIntToString(writer, Minimum); } @@ -29,7 +30,7 @@ internal static void ReadMinimum(JsonProperty property, ref int minimum) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteMaximum(Utf8JsonWriter writer) + internal void WriteMaximum(Utf8JsonWriter writer, ModelReaderWriterOptions options) { WriteIntToString(writer, Maximum); } @@ -41,7 +42,7 @@ internal static void ReadMaximum(JsonProperty property, ref int maximum) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteDefault(Utf8JsonWriter writer) + internal void WriteDefault(Utf8JsonWriter writer, ModelReaderWriterOptions options) { WriteIntToString(writer, Default); } diff --git a/sdk/monitor/Azure.ResourceManager.Monitor/src/Generated/Models/MonitorScaleCapacity.Serialization.cs b/sdk/monitor/Azure.ResourceManager.Monitor/src/Generated/Models/MonitorScaleCapacity.Serialization.cs index 6ec9c4434881..fb15104e841b 100644 --- a/sdk/monitor/Azure.ResourceManager.Monitor/src/Generated/Models/MonitorScaleCapacity.Serialization.cs +++ b/sdk/monitor/Azure.ResourceManager.Monitor/src/Generated/Models/MonitorScaleCapacity.Serialization.cs @@ -27,11 +27,11 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWr writer.WriteStartObject(); writer.WritePropertyName("minimum"u8); - WriteMinimum(writer); + WriteMinimum(writer, options); writer.WritePropertyName("maximum"u8); - WriteMaximum(writer); + WriteMaximum(writer, options); writer.WritePropertyName("default"u8); - WriteDefault(writer); + WriteDefault(writer, options); if (options.Format != "W" && _serializedAdditionalRawData != null) { foreach (var item in _serializedAdditionalRawData) diff --git a/sdk/mysql/Azure.ResourceManager.MySql/tests/Scenario/MySqlFlexibleServerTests.cs b/sdk/mysql/Azure.ResourceManager.MySql/tests/Scenario/MySqlFlexibleServerTests.cs index 9d482f619836..6467f6158fb2 100644 --- a/sdk/mysql/Azure.ResourceManager.MySql/tests/Scenario/MySqlFlexibleServerTests.cs +++ b/sdk/mysql/Azure.ResourceManager.MySql/tests/Scenario/MySqlFlexibleServerTests.cs @@ -18,8 +18,8 @@ public class MySqlFlexibleServerTests: MySqlManagementTestBase public MySqlFlexibleServerTests(bool isAsync) : base(isAsync)//,RecordedTestMode.Record) { - BodyKeySanitizers.Add(new BodyKeySanitizer("https://fakeaccout.blob.windows.core.net/fakecontainer") { JsonPath = "properties.importSourceProperties.storageUrl" }); - BodyKeySanitizers.Add(new BodyKeySanitizer(SanitizeValue) { JsonPath = "properties.importSourceProperties.sasToken" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.importSourceProperties.storageUrl") { Value = "https://fakeaccout.blob.windows.core.net/fakecontainer" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.importSourceProperties.sasToken")); } [TestCase] diff --git a/sdk/networkcloud/Azure.ResourceManager.NetworkCloud/tests/NetworkCloudManagementTestBase.cs b/sdk/networkcloud/Azure.ResourceManager.NetworkCloud/tests/NetworkCloudManagementTestBase.cs index c81d6469fff4..381ed35cf20e 100644 --- a/sdk/networkcloud/Azure.ResourceManager.NetworkCloud/tests/NetworkCloudManagementTestBase.cs +++ b/sdk/networkcloud/Azure.ResourceManager.NetworkCloud/tests/NetworkCloudManagementTestBase.cs @@ -20,13 +20,13 @@ public class NetworkCloudManagementTestBase : ManagementRecordedTestBase instead of a IDictionary. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SerializeTokenSelectionBiases(Utf8JsonWriter writer) + private void SerializeTokenSelectionBiases(Utf8JsonWriter writer, ModelReaderWriterOptions options) { writer.WriteStartObject(); foreach (var item in TokenSelectionBiases) diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscription.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscription.Serialization.cs index eabfacbebfd9..3bb16dae6e78 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscription.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscription.Serialization.cs @@ -41,7 +41,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWrit if (Optional.IsDefined(Duration)) { writer.WritePropertyName("duration"u8); - writer.WriteNumberValue(Convert.ToDouble(Duration.Value.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(Duration.Value.ToString("s\\.FFF"))); } if (Optional.IsCollectionDefined(Segments)) { diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionSegment.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionSegment.Serialization.cs index a5ce0e2469f6..a5782a864796 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionSegment.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionSegment.Serialization.cs @@ -29,9 +29,9 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelRea writer.WritePropertyName("id"u8); writer.WriteNumberValue(Id); writer.WritePropertyName("start"u8); - writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.FFF"))); writer.WritePropertyName("end"u8); - writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.FFF"))); writer.WritePropertyName("text"u8); writer.WriteStringValue(Text); writer.WritePropertyName("temperature"u8); diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionWord.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionWord.Serialization.cs index 4c1842e25805..5d28770f0eed 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionWord.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranscriptionWord.Serialization.cs @@ -29,9 +29,9 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReader writer.WritePropertyName("word"u8); writer.WriteStringValue(Word); writer.WritePropertyName("start"u8); - writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.FFF"))); writer.WritePropertyName("end"u8); - writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.FFF"))); if (options.Format != "W" && _serializedAdditionalRawData != null) { foreach (var item in _serializedAdditionalRawData) diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslation.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslation.Serialization.cs index aae34c20f9b8..96e394233a74 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslation.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslation.Serialization.cs @@ -41,7 +41,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriter if (Optional.IsDefined(Duration)) { writer.WritePropertyName("duration"u8); - writer.WriteNumberValue(Convert.ToDouble(Duration.Value.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(Duration.Value.ToString("s\\.FFF"))); } if (Optional.IsCollectionDefined(Segments)) { diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslationSegment.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslationSegment.Serialization.cs index dd996762e970..e8ec35cffb1b 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslationSegment.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/AudioTranslationSegment.Serialization.cs @@ -29,9 +29,9 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReade writer.WritePropertyName("id"u8); writer.WriteNumberValue(Id); writer.WritePropertyName("start"u8); - writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(Start.ToString("s\\.FFF"))); writer.WritePropertyName("end"u8); - writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.fff"))); + writer.WriteNumberValue(Convert.ToDouble(End.ToString("s\\.FFF"))); writer.WritePropertyName("text"u8); writer.WriteStringValue(Text); writer.WritePropertyName("temperature"u8); diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/ChatRequestUserMessage.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/ChatRequestUserMessage.Serialization.cs index 45ce48d2682c..378fd36b9989 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/ChatRequestUserMessage.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/ChatRequestUserMessage.Serialization.cs @@ -27,7 +27,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReader writer.WriteStartObject(); writer.WritePropertyName("content"u8); - SerializeContent(writer); + SerializeContent(writer, options); if (Optional.IsDefined(Name)) { writer.WritePropertyName("name"u8); diff --git a/sdk/openai/Azure.AI.OpenAI/src/Generated/CompletionsOptions.Serialization.cs b/sdk/openai/Azure.AI.OpenAI/src/Generated/CompletionsOptions.Serialization.cs index d16a906f6c5a..a854278cacab 100644 --- a/sdk/openai/Azure.AI.OpenAI/src/Generated/CompletionsOptions.Serialization.cs +++ b/sdk/openai/Azure.AI.OpenAI/src/Generated/CompletionsOptions.Serialization.cs @@ -51,7 +51,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWrit if (Optional.IsCollectionDefined(TokenSelectionBiases)) { writer.WritePropertyName("logit_bias"u8); - SerializeTokenSelectionBiases(writer); + SerializeTokenSelectionBiases(writer, options); } if (Optional.IsDefined(User)) { diff --git a/sdk/openai/Azure.AI.OpenAI/tests/OpenAITestBase.cs b/sdk/openai/Azure.AI.OpenAI/tests/OpenAITestBase.cs index 034c4e2bfa4a..ea843cd0ecbf 100644 --- a/sdk/openai/Azure.AI.OpenAI/tests/OpenAITestBase.cs +++ b/sdk/openai/Azure.AI.OpenAI/tests/OpenAITestBase.cs @@ -37,10 +37,10 @@ protected OpenAITestBase(Scenario defaultScenario, bool isAsync, RecordedTestMod protected OpenAITestBase(bool isAsync, RecordedTestMode? mode = null) : base(isAsync, mode) { - BodyRegexSanitizers.Add(new BodyRegexSanitizer("sig=[^\"]*", "sig=Sanitized")); - BodyRegexSanitizers.Add(new BodyRegexSanitizer("(\"key\" *: *\")[^ \n\"]*(\")", "$1placeholder$2")); - HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("api-key", "***********")); - UriRegexSanitizers.Add(new UriRegexSanitizer("sig=[^\"]*", "sig=Sanitized")); + BodyRegexSanitizers.Add(new BodyRegexSanitizer("sig=[^\"]*") { Value = "sig=Sanitized" }); + BodyRegexSanitizers.Add(new BodyRegexSanitizer("(\"key\" *: *\")[^ \n\"]*(\")") { Value = "$1placeholder$2" }); + HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("api-key") { Value = "***********" }); + UriRegexSanitizers.Add(new UriRegexSanitizer("sig=[^\"]*") { Value = "sig=Sanitized" }); JsonPathSanitizers.Add("$.messages[*].content[*].image_url.url"); SanitizedQueryParameters.Add("sig"); } diff --git a/sdk/provisioning/Azure.Provisioning.AppConfiguration/assets.json b/sdk/provisioning/Azure.Provisioning.AppConfiguration/assets.json index e3f4df5312cb..2828777cee70 100644 --- a/sdk/provisioning/Azure.Provisioning.AppConfiguration/assets.json +++ b/sdk/provisioning/Azure.Provisioning.AppConfiguration/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/provisioning/Azure.Provisioning.AppConfiguration", - "Tag": "net/provisioning/Azure.Provisioning.AppConfiguration_3c7936e93e" + "Tag": "net/provisioning/Azure.Provisioning.AppConfiguration_55fde9399d" } diff --git a/sdk/provisioning/Azure.Provisioning.KeyVault/assets.json b/sdk/provisioning/Azure.Provisioning.KeyVault/assets.json index fd9293b8fee5..5fe6a9c00d53 100644 --- a/sdk/provisioning/Azure.Provisioning.KeyVault/assets.json +++ b/sdk/provisioning/Azure.Provisioning.KeyVault/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/provisioning/Azure.Provisioning.KeyVault", - "Tag": "net/provisioning/Azure.Provisioning.KeyVault_cb7a21a215" + "Tag": "net/provisioning/Azure.Provisioning.KeyVault_7cbe7ccb75" } \ No newline at end of file diff --git a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/AddingOutputs/main.bicep b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/AddingOutputs/main.bicep index c985be0e51db..e68f042d4e2d 100644 --- a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/AddingOutputs/main.bicep +++ b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/AddingOutputs/main.bicep @@ -7,11 +7,11 @@ param location string = resourceGroup().location param enableSoftDelete bool = true -resource keyVault_7LloDNJK5 'Microsoft.KeyVault/vaults@2022-07-01' = { +resource keyVault_NEuaN7OeP 'Microsoft.KeyVault/vaults@2022-07-01' = { name: toLower(take('kv${uniqueString(resourceGroup().id)}', 24)) location: location properties: { - tenantId: '00000000-0000-0000-0000-000000000000' + tenantId: tenant().tenantId sku: { family: 'A' name: 'standard' @@ -21,4 +21,4 @@ resource keyVault_7LloDNJK5 'Microsoft.KeyVault/vaults@2022-07-01' = { } } -output VAULT_URI string = keyVault_7LloDNJK5.properties.vaultUri +output VAULT_URI string = keyVault_NEuaN7OeP.properties.vaultUri diff --git a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/Sample_HelloWorld/main.bicep b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/Sample_HelloWorld/main.bicep index 7cdc3b22636b..ffc8366edcd9 100644 --- a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/Sample_HelloWorld/main.bicep +++ b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/Sample_HelloWorld/main.bicep @@ -4,11 +4,11 @@ targetScope = 'resourceGroup' param location string = resourceGroup().location -resource keyVault_7LloDNJK5 'Microsoft.KeyVault/vaults@2022-07-01' = { +resource keyVault_NEuaN7OeP 'Microsoft.KeyVault/vaults@2022-07-01' = { name: toLower(take('kv${uniqueString(resourceGroup().id)}', 24)) location: location properties: { - tenantId: '00000000-0000-0000-0000-000000000000' + tenantId: tenant().tenantId sku: { family: 'A' name: 'standard' diff --git a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/UsingParameters/main.bicep b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/UsingParameters/main.bicep index bf85cff53d60..f61af2bf4dad 100644 --- a/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/UsingParameters/main.bicep +++ b/sdk/provisioning/Azure.Provisioning.KeyVault/tests/Infrastructure/UsingParameters/main.bicep @@ -7,11 +7,11 @@ param location string = resourceGroup().location param enableSoftDelete bool = true -resource keyVault_7LloDNJK5 'Microsoft.KeyVault/vaults@2022-07-01' = { +resource keyVault_NEuaN7OeP 'Microsoft.KeyVault/vaults@2022-07-01' = { name: toLower(take('kv${uniqueString(resourceGroup().id)}', 24)) location: location properties: { - tenantId: '00000000-0000-0000-0000-000000000000' + tenantId: tenant().tenantId sku: { family: 'A' name: 'standard' diff --git a/sdk/provisioning/Azure.Provisioning.Search/assets.json b/sdk/provisioning/Azure.Provisioning.Search/assets.json index f8e83ac2077d..491bc8c899db 100644 --- a/sdk/provisioning/Azure.Provisioning.Search/assets.json +++ b/sdk/provisioning/Azure.Provisioning.Search/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/provisioning/Azure.Provisioning.Search", - "Tag": "net/provisioning/Azure.Provisioning.Search_0f74a99f10" + "Tag": "net/provisioning/Azure.Provisioning.Search_3d009da219" } \ No newline at end of file diff --git a/sdk/provisioning/Azure.Provisioning.SignalR/assets.json b/sdk/provisioning/Azure.Provisioning.SignalR/assets.json index d4ca065f396b..9f46d7ce83e8 100644 --- a/sdk/provisioning/Azure.Provisioning.SignalR/assets.json +++ b/sdk/provisioning/Azure.Provisioning.SignalR/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/provisioning/Azure.Provisioning.SignalR", - "Tag": "" + "Tag": "net/provisioning/Azure.Provisioning.SignalR_a88305db5e" } \ No newline at end of file diff --git a/sdk/provisioning/Azure.Provisioning.Storage/assets.json b/sdk/provisioning/Azure.Provisioning.Storage/assets.json index 65ae1ebda2e0..a41e36aa7f7c 100644 --- a/sdk/provisioning/Azure.Provisioning.Storage/assets.json +++ b/sdk/provisioning/Azure.Provisioning.Storage/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/provisioning/Azure.Provisioning.Storage", - "Tag": "net/provisioning/Azure.Provisioning.Storage_bcaeab9180" + "Tag": "net/provisioning/Azure.Provisioning.Storage_13a772dbd6" } \ No newline at end of file diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/CHANGELOG.md b/sdk/provisioning/Azure.Provisioning.WebPubSub/CHANGELOG.md new file mode 100644 index 000000000000..75713709e7d2 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/CHANGELOG.md @@ -0,0 +1,7 @@ +# Release History + +## 0.1.0-beta.1 (2024-05-10) + +### Features Added + +- Initial beta release of Azure.Provisioning.WebPubSub. diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/README.md b/sdk/provisioning/Azure.Provisioning.WebPubSub/README.md new file mode 100644 index 000000000000..438df373bb06 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/README.md @@ -0,0 +1,84 @@ +# Azure Provisioning client library for .NET + +Azure.Provisioning.WebPubSub simplifies declarative resource provisioning in .NET for Azure Web PubSub. + +## Getting started + +### Install the package + +Install the client library for .NET with [NuGet](https://www.nuget.org/ ): + +```dotnetcli +dotnet add package Azure.Provisioning.WebPubSub --prerelease +``` + +### Prerequisites + +> You must have an [Azure subscription](https://azure.microsoft.com/free/dotnet/). + +### Authenticate the Client + +## Key concepts + +This library allows you to specify your infrastructure in a declarative style using dotnet. You can then use azd to deploy your infrastructure to Azure diretly without needing to write or maintain bicep or arm templates. + +## Examples + +Here is a simple example which creates a KeyVault. + +First create your Infrastructure class. + +```C# Snippet:SampleInfrastructure +public class SampleInfrastructure : Infrastructure +{ + public SampleInfrastructure() : base(envName: "Sample", tenantId: Guid.Empty, subscriptionId: Guid.Empty, configuration: new Configuration { UseInteractiveMode = true }) + { + } +} +``` + +Next add your resources into your infrastructure and then Build. + +```C# Snippet:KeyVaultOnly +// Create a new infrastructure +var infrastructure = new SampleInfrastructure(); + +// Add a new key vault +var keyVault = infrastructure.AddKeyVault(); + +// You can call Build to convert the infrastructure into bicep files. +infrastructure.Build(); +``` + +## Troubleshooting + +- File an issue via [GitHub Issues](https://github.com/Azure/azure-sdk-for-net/issues). +- Check [previous questions](https://stackoverflow.com/questions/tagged/azure+.net) or ask new ones on Stack Overflow using Azure and .NET tags. + +## Next steps + +## Contributing + +For details on contributing to this repository, see the [contributing +guide][cg]. + +This project welcomes contributions and suggestions. Most contributions +require you to agree to a Contributor License Agreement (CLA) declaring +that you have the right to, and actually do, grant us the rights to use +your contribution. For details, visit . + +When you submit a pull request, a CLA-bot will automatically determine +whether you need to provide a CLA and decorate the PR appropriately +(for example, label, comment). Follow the instructions provided by the +bot. You'll only need to do this action once across all repositories +using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For +more information, see the [Code of Conduct FAQ][coc_faq] or contact + with any other questions or comments. + + +[cg]: https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/resourcemanager/Azure.ResourceManager/docs/CONTRIBUTING.md +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ + diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/api/Azure.Provisioning.WebPubSub.netstandard2.0.cs b/sdk/provisioning/Azure.Provisioning.WebPubSub/api/Azure.Provisioning.WebPubSub.netstandard2.0.cs new file mode 100644 index 000000000000..b8af4abe56e9 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/api/Azure.Provisioning.WebPubSub.netstandard2.0.cs @@ -0,0 +1,15 @@ +namespace Azure.Provisioning.WebPubSub +{ + public partial class WebPubSubHub : Azure.Provisioning.Resource + { + public WebPubSubHub(Azure.Provisioning.IConstruct scope, Azure.ResourceManager.WebPubSub.Models.WebPubSubHubProperties properties, Azure.Provisioning.WebPubSub.WebPubSubService? parent = null, string name = "hub", string version = "2021-10-01") : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func), default(bool)) { } + protected override Azure.Provisioning.Resource? FindParentInScope(Azure.Provisioning.IConstruct scope) { throw null; } + public static Azure.Provisioning.WebPubSub.WebPubSubHub FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.WebPubSub.WebPubSubService? parent = null) { throw null; } + } + public partial class WebPubSubService : Azure.Provisioning.Resource + { + public WebPubSubService(Azure.Provisioning.IConstruct scope, Azure.ResourceManager.WebPubSub.Models.BillingInfoSku? sku = null, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null, string name = "webpubsub", string version = "2021-10-01", Azure.Core.AzureLocation? location = default(Azure.Core.AzureLocation?)) : base (default(Azure.Provisioning.IConstruct), default(Azure.Provisioning.Resource), default(string), default(Azure.Core.ResourceType), default(string), default(System.Func), default(bool)) { } + public static Azure.Provisioning.WebPubSub.WebPubSubService FromExisting(Azure.Provisioning.IConstruct scope, string name, Azure.Provisioning.ResourceManager.ResourceGroup? parent = null) { throw null; } + protected override string GetAzureName(Azure.Provisioning.IConstruct scope, string resourceName) { throw null; } + } +} diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/assets.json b/sdk/provisioning/Azure.Provisioning.WebPubSub/assets.json new file mode 100644 index 000000000000..81f5b60480e2 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/assets.json @@ -0,0 +1,6 @@ +{ + "AssetsRepo": "Azure/azure-sdk-assets", + "AssetsRepoPrefixPath": "net", + "TagPrefix": "net/provisioning/Azure.Provisioning.WebPubSub", + "Tag": "net/provisioning/Azure.Provisioning.WebPubSub_ee1c01a8d9" +} \ No newline at end of file diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Azure.Provisioning.WebPubSub.csproj b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Azure.Provisioning.WebPubSub.csproj new file mode 100644 index 000000000000..29b011d81e12 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Azure.Provisioning.WebPubSub.csproj @@ -0,0 +1,14 @@ + + + + Azure.Provisioning.WebPubSub simplifies declarative resource provisioning in .NET for Azure Web PubSub. + 0.1.0-beta.1 + $(RequiredTargetFrameworks) + $(NoWarn);AZC0001 + + + + + + + diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Properties/AssemblyInfo.cs b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Properties/AssemblyInfo.cs new file mode 100644 index 000000000000..15a940a47a16 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Diagnostics.CodeAnalysis; + +[assembly: Experimental("AZPROVISION001")] diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubHub.cs b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubHub.cs new file mode 100644 index 000000000000..1c8f39b67fd7 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubHub.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.ResourceManager.WebPubSub; +using Azure.ResourceManager.WebPubSub.Models; + +namespace Azure.Provisioning.WebPubSub +{ + /// + /// Represents a hub setting for WebPubSub. + /// + public class WebPubSubHub : Resource + { + // https://learn.microsoft.com/azure/templates/microsoft.signalrservice/2023-02-01/webPubSub/hubs?pivots=deployment-language-bicep + private const string ResourceTypeName = "Microsoft.SignalRService/webPubSub/hubs"; + + private static WebPubSubHubData Empty(string name) => ArmWebPubSubModelFactory.WebPubSubHubData(); + + /// + /// Creates a new instance of the class. + /// + /// The scope. + /// The properties of the hub settings. + /// The parent. + /// The name. + /// The version. + public WebPubSubHub(IConstruct scope, + WebPubSubHubProperties properties, + WebPubSubService? parent = null, + string name = "hub", + string version = WebPubSubService.DefaultVersion) + : this(scope, parent, name, version, false, (name) => ArmWebPubSubModelFactory.WebPubSubHubData( + name: name, + properties: properties)) + { + } + + private WebPubSubHub( + IConstruct scope, + WebPubSubService? parent, + string name, + string version = WebPubSubService.DefaultVersion, + bool isExisting = false, + Func? creator = null) + : base(scope, parent, name, ResourceTypeName, version, creator ?? Empty, isExisting) + { + } + + /// + /// Creates a new instance of the class referencing an existing instance. + /// + /// The scope. + /// The resource name. + /// The resource group. + /// The WebPubSub service instance. + public static WebPubSubHub FromExisting(IConstruct scope, string name, WebPubSubService? parent = null) + => new WebPubSubHub(scope, parent: parent, name: name, isExisting: true); + + /// + protected override Resource? FindParentInScope(IConstruct scope) + { + return scope.GetSingleResource() ?? new WebPubSubService(scope); + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubService.cs b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubService.cs new file mode 100644 index 000000000000..98671498c9e3 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/src/WebPubSubService.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Core; +using Azure.Provisioning.ResourceManager; +using Azure.ResourceManager.WebPubSub; +using Azure.ResourceManager.WebPubSub.Models; + +namespace Azure.Provisioning.WebPubSub +{ + /// + /// Represents a WebPubSub. + /// + public class WebPubSubService : Resource + { + // https://learn.microsoft.com/azure/templates/microsoft.signalrservice/2023-02-01/webPubSub?pivots=deployment-language-bicep + private const string ResourceTypeName = "Microsoft.SignalRService/webPubSub"; + // https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/webpubsub/Azure.ResourceManager.WebPubSub/src/Generated/RestOperations/WebPubSubRestOperations.cs#L36 + internal const string DefaultVersion = "2021-10-01"; + + private static WebPubSubData Empty(string name) => ArmWebPubSubModelFactory.WebPubSubData(); + + /// + /// Creates a new instance of the class. + /// + /// The scope. + /// The SKU. + /// The parent. + /// The name. + /// The version. + /// The location. + public WebPubSubService( + IConstruct scope, + BillingInfoSku? sku = default, + ResourceGroup? parent = default, + string name = "webpubsub", + string version = DefaultVersion, + AzureLocation? location = default) + : this(scope, parent, name, version, false, (name) => ArmWebPubSubModelFactory.WebPubSubData( + name: name, + location: location ?? Environment.GetEnvironmentVariable("AZURE_LOCATION") ?? AzureLocation.WestUS, + sku: sku ?? new BillingInfoSku("Free_F1") { Capacity = 1 })) + { + AssignProperty(data => data.Name, GetAzureName(scope, name)); + } + + private WebPubSubService( + IConstruct scope, + ResourceGroup? parent, + string name, + string version = DefaultVersion, + bool isExisting = false, + Func? creator = null) + : base(scope, parent, name, ResourceTypeName, version, creator ?? Empty, isExisting) + { + } + + /// + /// Creates a new instance of the class referencing an existing instance. + /// + /// The scope. + /// The resource name. + /// The resource group. + /// The WebPubSub service instance. + public static WebPubSubService FromExisting(IConstruct scope, string name, ResourceGroup? parent = null) + => new WebPubSubService(scope, parent: parent, name: name, isExisting: true); + + /// + protected override string GetAzureName(IConstruct scope, string resourceName) => GetGloballyUniqueName(resourceName); + } +} diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Azure.Provisioning.WebPubSub.Tests.csproj b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Azure.Provisioning.WebPubSub.Tests.csproj new file mode 100644 index 000000000000..b4677b92e932 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Azure.Provisioning.WebPubSub.Tests.csproj @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/main.bicep b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/main.bicep new file mode 100644 index 000000000000..136bc7020567 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/main.bicep @@ -0,0 +1,15 @@ +targetScope = 'subscription' + + +resource resourceGroup_I6QNkoPsb 'Microsoft.Resources/resourceGroups@2023-07-01' = { + name: 'rg-TEST' + location: 'westus' + tags: { + 'azd-env-name': 'TEST' + } +} + +module rg_TEST_module './resources/rg_TEST_module/rg_TEST_module.bicep' = { + name: 'rg_TEST_module' + scope: resourceGroup_I6QNkoPsb +} diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/resources/rg_TEST_module/rg_TEST_module.bicep b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/resources/rg_TEST_module/rg_TEST_module.bicep new file mode 100644 index 000000000000..30e8a98512f1 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/ExistingWebPubSubResources/resources/rg_TEST_module/rg_TEST_module.bicep @@ -0,0 +1,4 @@ + +resource webPubSubService_f0nsipxGj 'Microsoft.SignalRService/webPubSub@2021-10-01' existing = { + name: 'existingWebPubSub' +} diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSub/main.bicep b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSub/main.bicep new file mode 100644 index 000000000000..a2a5554476ea --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSub/main.bicep @@ -0,0 +1,40 @@ +targetScope = 'resourceGroup' + +@description('') +param location string = resourceGroup().location + + +resource webPubSubService_EAdO6ICWi 'Microsoft.SignalRService/webPubSub@2021-10-01' = { + name: toLower(take('webpubsub${uniqueString(resourceGroup().id)}', 24)) + location: location + sku: { + name: 'Standard_S1' + } + properties: { + } +} + +resource roleAssignment_eQVZzvRPP 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: webPubSubService_EAdO6ICWi + name: guid(webPubSubService_EAdO6ICWi.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12cf5a90-567b-43ae-8102-96cf46c7d9b4')) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12cf5a90-567b-43ae-8102-96cf46c7d9b4') + principalId: '00000000-0000-0000-0000-000000000000' + principalType: 'ServicePrincipal' + } +} + +resource webPubSubHub_tKhq1vFqb 'Microsoft.SignalRService/webPubSub/hubs@2021-10-01' = { + parent: webPubSubService_EAdO6ICWi + name: 'hub' + properties: { + eventHandlers: [ + { + urlTemplate: 'tunnel:///eventhandler' + userEventPattern: '*' + } + ] + } +} + +output hostName string = webPubSubService_EAdO6ICWi.properties.hostName diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSubResources/main.bicep b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSubResources/main.bicep new file mode 100644 index 000000000000..a098516a8380 --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/Infrastructure/WebPubSubResources/main.bicep @@ -0,0 +1,38 @@ +targetScope = 'resourceGroup' + +@description('') +param location string = resourceGroup().location + + +resource signalRService_TvD5y8AYq 'Microsoft.SignalRService/signalR@2022-02-01' = { + name: toLower(take('signalr${uniqueString(resourceGroup().id)}', 24)) + location: location + sku: { + name: 'Standard_S1' + } + properties: { + features: [ + { + flag: 'ServiceMode' + value: 'Serverless' + } + ] + cors: { + allowedOrigins: [ + '*' + ] + } + } +} + +resource roleAssignment_hFSNN5tl8 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + scope: signalRService_TvD5y8AYq + name: guid(signalRService_TvD5y8AYq.id, '00000000-0000-0000-0000-000000000000', subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '420fcaa2-552c-430f-98ca-3264be4806c7')) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '420fcaa2-552c-430f-98ca-3264be4806c7') + principalId: '00000000-0000-0000-0000-000000000000' + principalType: 'ServicePrincipal' + } +} + +output hostName string = signalRService_TvD5y8AYq.properties.hostName diff --git a/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/WebPubSubTests.cs b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/WebPubSubTests.cs new file mode 100644 index 000000000000..26d2ecf82e1a --- /dev/null +++ b/sdk/provisioning/Azure.Provisioning.WebPubSub/tests/WebPubSubTests.cs @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.Provisioning.ResourceManager; +using Azure.Provisioning.Tests; +using Azure.ResourceManager.WebPubSub.Models; + +namespace Azure.Provisioning.WebPubSub.Tests +{ + public class WebPubSubTests : ProvisioningTestBase + { + public WebPubSubTests(bool isAsync) : base(isAsync) + { + } + + [RecordedTest] + public async Task WebPubSub() + { + TestInfrastructure infrastructure = new TestInfrastructure(configuration: new Configuration { UseInteractiveMode = true }); + var wps = new WebPubSubService(infrastructure, sku: new BillingInfoSku("Standard_S1")); + wps.AssignRole(RoleDefinition.WebPubSubServiceOwner, Guid.Empty); + var properties = new WebPubSubHubProperties(); + properties.EventHandlers.Add(new WebPubSubEventHandler("tunnel:///eventhandler") { UserEventPattern = "*" }); + _ = new WebPubSubHub(infrastructure, properties, parent: wps); + wps.AddOutput("hostName", data => data.HostName); + infrastructure.Build(GetOutputPath()); + + await ValidateBicepAsync(interactiveMode: true); + } + + [RecordedTest] + public async Task ExistingWebPubSubResources() + { + var infra = new TestInfrastructure(); + var rg = infra.AddResourceGroup(); + infra.AddResource(WebPubSubService.FromExisting(infra, "'existingWebPubSub'", rg)); + + infra.Build(GetOutputPath()); + + await ValidateBicepAsync(); + } + } +} diff --git a/sdk/provisioning/Azure.Provisioning.sln b/sdk/provisioning/Azure.Provisioning.sln index 0cca2265a50f..19b53d56f5a5 100644 --- a/sdk/provisioning/Azure.Provisioning.sln +++ b/sdk/provisioning/Azure.Provisioning.sln @@ -69,6 +69,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.Storage. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Core.TestFramework", "..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{C2778320-ADC6-4EEE-A1D8-98590CD1223D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.WebPubSub", "Azure.Provisioning.WebPubSub\src\Azure.Provisioning.WebPubSub.csproj", "{1ABD7C57-D9A1-4CB5-BE6F-9E9F02E2886D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Azure.Provisioning.WebPubSub.Tests", "Azure.Provisioning.WebPubSub\tests\Azure.Provisioning.WebPubSub.Tests.csproj", "{AF6AAD6F-FD2D-4480-8194-0CB5E0083065}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{822797CC-9E24-4BB1-AF93-2F2716C3C274}" ProjectSection(SolutionItems) = preProject README.md = README.md @@ -212,6 +216,14 @@ Global {C2778320-ADC6-4EEE-A1D8-98590CD1223D}.Debug|Any CPU.Build.0 = Debug|Any CPU {C2778320-ADC6-4EEE-A1D8-98590CD1223D}.Release|Any CPU.ActiveCfg = Release|Any CPU {C2778320-ADC6-4EEE-A1D8-98590CD1223D}.Release|Any CPU.Build.0 = Release|Any CPU + {1ABD7C57-D9A1-4CB5-BE6F-9E9F02E2886D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1ABD7C57-D9A1-4CB5-BE6F-9E9F02E2886D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1ABD7C57-D9A1-4CB5-BE6F-9E9F02E2886D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1ABD7C57-D9A1-4CB5-BE6F-9E9F02E2886D}.Release|Any CPU.Build.0 = Release|Any CPU + {AF6AAD6F-FD2D-4480-8194-0CB5E0083065}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF6AAD6F-FD2D-4480-8194-0CB5E0083065}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF6AAD6F-FD2D-4480-8194-0CB5E0083065}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AF6AAD6F-FD2D-4480-8194-0CB5E0083065}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net461.cs b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net461.cs index e58830d0a27c..47109581fd8b 100644 --- a/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net461.cs +++ b/sdk/provisioning/Azure.Provisioning/api/Azure.Provisioning.net461.cs @@ -161,6 +161,7 @@ public partial class RoleAssignment : Azure.Provisioning.Resource public static RoleDefinition SignalRAppServer { get; } = new RoleDefinition("420fcaa2-552c-430f-98ca-3264be4806c7"); + /// + /// Web PubSub Service Owner - Full access to Azure Web PubSub Service REST APIs + /// + public static RoleDefinition WebPubSubServiceOwner { get; } = new RoleDefinition("12cf5a90-567b-43ae-8102-96cf46c7d9b4"); + /// Converts a string to a . public static implicit operator RoleDefinition(string value) => new RoleDefinition(value); diff --git a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTestBase.cs b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTestBase.cs index ae44e3ba1e3a..e296db9e6731 100644 --- a/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTestBase.cs +++ b/sdk/provisioning/Azure.Provisioning/tests/ProvisioningTestBase.cs @@ -18,17 +18,24 @@ namespace Azure.Provisioning.Tests [AsyncOnly] public class ProvisioningTestBase : ManagementRecordedTestBase { + private DateTime _testStartTime; + protected override DateTime TestStartTime => _testStartTime; + public ProvisioningTestBase(bool async) : base(async) { + // Ignore the version of the AZ CLI used to generate the ARM template as this will differ based on the environment + JsonPathSanitizers.Add("$.._generator.version"); + JsonPathSanitizers.Add("$.._generator.templateHash"); } - protected async Task ValidateBicepAsync(BinaryData? parameters = null, bool interactiveMode = false) + [SetUp] + public void Setup() { - if (CoreTestEnvironment.GlobalIsRunningInCI) - { - return; - } + _testStartTime = base.TestStartTime; + } + protected async Task ValidateBicepAsync(BinaryData? parameters = null, bool interactiveMode = false) + { var testPath = GetOutputPath(); var client = GetArmClient(); ResourceGroupResource? rg = null; @@ -44,7 +51,7 @@ protected async Task ValidateBicepAsync(BinaryData? parameters = null, bool inte "eng", "scripts", $"Validate-Bicep.ps1 {bicepPath}"); - var processInfo = new ProcessStartInfo("pwsh.exe", args) + var processInfo = new ProcessStartInfo("pwsh", args) { UseShellExecute = false, RedirectStandardOutput = true, RedirectStandardError = true, }; @@ -59,6 +66,9 @@ protected async Task ValidateBicepAsync(BinaryData? parameters = null, bool inte } } + // exclude the time taken to validate the bicep file + _testStartTime = DateTime.UtcNow; + ResourceIdentifier scope; if (interactiveMode) { @@ -99,33 +109,6 @@ protected async Task ValidateBicepAsync(BinaryData? parameters = null, bool inte } } - private static string GetGitRoot() - { - ProcessStartInfo startInfo = new ProcessStartInfo - { - FileName = "git", - Arguments = "rev-parse --show-toplevel", - RedirectStandardOutput = true, - UseShellExecute = false, - CreateNoWindow = true - }; - - using (Process process = Process.Start(startInfo)!) - { - process.WaitForExit(); - - if (process.ExitCode == 0) - { - string gitRoot = process.StandardOutput.ReadToEnd().Trim(); - return gitRoot; - } - else - { - throw new Exception("Failed to get the root of the Git repository."); - } - } - } - protected string GetOutputPath() { var output = Path.Combine(CoreTestEnvironment.GetSourcePath(GetType().Assembly), "Infrastructure", diff --git a/sdk/provisioning/ci.yml b/sdk/provisioning/ci.yml index 913c4d2d1435..a143292c7fbe 100644 --- a/sdk/provisioning/ci.yml +++ b/sdk/provisioning/ci.yml @@ -59,3 +59,5 @@ extends: safeName: AzureProvisioningSql - name: Azure.Provisioning.Storage safeName: AzureProvisioningStorage + - name: Azure.Provisioning.WebPubSub + safeName: AzureProvisioningWebPubSub diff --git a/sdk/purview/Azure.Analytics.Purview.Sharing/tests/ReceivedSharesClientTestBase.cs b/sdk/purview/Azure.Analytics.Purview.Sharing/tests/ReceivedSharesClientTestBase.cs index 5d3b4094030a..a52bcf65484f 100644 --- a/sdk/purview/Azure.Analytics.Purview.Sharing/tests/ReceivedSharesClientTestBase.cs +++ b/sdk/purview/Azure.Analytics.Purview.Sharing/tests/ReceivedSharesClientTestBase.cs @@ -5,6 +5,7 @@ using Azure.Core.Pipeline; using Azure.Core.TestFramework; using Azure.Analytics.Purview.Tests; +using Azure.Core.TestFramework.Models; namespace Azure.Analytics.Purview.Sharing.Tests { @@ -13,10 +14,24 @@ public class ReceivedSharesClientTestBase : RecordedTestBase { [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteRdbBackupMaxSnapshotCount(Utf8JsonWriter writer) + internal void WriteRdbBackupMaxSnapshotCount(Utf8JsonWriter writer, ModelReaderWriterOptions options) { if (RdbBackupMaxSnapshotCount == null) return; diff --git a/sdk/redis/Azure.ResourceManager.Redis/src/Generated/Models/RedisCommonConfiguration.Serialization.cs b/sdk/redis/Azure.ResourceManager.Redis/src/Generated/Models/RedisCommonConfiguration.Serialization.cs index 93a61c4eca86..086f72f799e1 100644 --- a/sdk/redis/Azure.ResourceManager.Redis/src/Generated/Models/RedisCommonConfiguration.Serialization.cs +++ b/sdk/redis/Azure.ResourceManager.Redis/src/Generated/Models/RedisCommonConfiguration.Serialization.cs @@ -40,7 +40,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelRead if (Optional.IsDefined(RdbBackupMaxSnapshotCount)) { writer.WritePropertyName("rdb-backup-max-snapshot-count"u8); - WriteRdbBackupMaxSnapshotCount(writer); + WriteRdbBackupMaxSnapshotCount(writer, options); } if (Optional.IsDefined(RdbStorageConnectionString)) { diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ResourceData.cs b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/ResourceData.cs similarity index 77% rename from sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ResourceData.cs rename to sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/ResourceData.cs index 7f9781ad3109..841b931f4459 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/ResourceData.cs +++ b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/ResourceData.cs @@ -1,27 +1,28 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// + #nullable disable using Azure.Core; -[assembly: CodeGenSuppressType("ArmResourceData")] namespace Azure.ResourceManager.Models { /// Common fields that are returned in the response for all Azure Resource Manager resources. - [ReferenceType(new string[]{"SystemData"})] + [ReferenceType(new string[] { "SystemData" })] public abstract partial class ResourceData { - /// Initializes a new instance of Resource. + /// Initializes a new instance of . [InitializationConstructor] protected ResourceData() { } - /// Initializes a new instance of Resource. + /// Initializes a new instance of . /// Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. /// The name of the resource. - /// The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". + /// The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". /// Azure Resource Manager metadata containing createdBy and modifiedBy information. [SerializationConstructor] protected ResourceData(ResourceIdentifier id, string name, ResourceType resourceType, SystemData systemData) @@ -36,7 +37,7 @@ protected ResourceData(ResourceIdentifier id, string name, ResourceType resource public ResourceIdentifier Id { get; } /// The name of the resource. public string Name { get; } - /// The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". + /// The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". public ResourceType ResourceType { get; } /// Azure Resource Manager metadata containing createdBy and modifiedBy information. public SystemData SystemData { get; } diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/TrackedResourceData.cs b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/TrackedResourceData.cs similarity index 56% rename from sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/TrackedResourceData.cs rename to sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/TrackedResourceData.cs index 7b533848633a..741469301da7 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/Common/Custom/Models/TrackedResourceData.cs +++ b/sdk/resourcemanager/Azure.ResourceManager/src/Common/Generated/Models/TrackedResourceData.cs @@ -1,19 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +// + #nullable disable using System.Collections.Generic; using Azure.Core; -[assembly: CodeGenSuppressType("TrackedResource")] namespace Azure.ResourceManager.Models { - /// The resource model definition for an Azure Resource Manager tracked top level resource which has 'tags' and a 'location'. - [ReferenceType(new string[]{"SystemData"})] + /// The resource model definition for an Azure Resource Manager tracked top level resource which has 'tags' and a 'location'. + [ReferenceType(new string[] { "SystemData" })] public abstract partial class TrackedResourceData : ResourceData { - /// Initializes a new instance of TrackedResource. + /// Initializes a new instance of . /// The geo-location where the resource lives. [InitializationConstructor] protected TrackedResourceData(AzureLocation location) @@ -22,11 +23,11 @@ protected TrackedResourceData(AzureLocation location) Location = location; } - /// Initializes a new instance of TrackedResource. - /// Fully qualified resource ID for the resource. Ex - /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}. - /// The name of the resource. - /// The type of the resource. E.g. "Microsoft.Compute/virtualMachines" or "Microsoft.Storage/storageAccounts". - /// Azure Resource Manager metadata containing createdBy and modifiedBy information. + /// Initializes a new instance of . + /// The id. + /// The name. + /// The resourceType. + /// The systemData. /// Resource tags. /// The geo-location where the resource lives. [SerializationConstructor] @@ -36,9 +37,7 @@ protected TrackedResourceData(ResourceIdentifier id, string name, ResourceType r Location = location; } - /// - /// Initializes a new instance of for deserialization. - /// + /// Initializes a new instance of for deserialization. protected TrackedResourceData() { } diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Custom/Models/LocationMetadata.cs b/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Custom/Models/LocationMetadata.cs index 2f06cf4bb08b..470d7b6d52a3 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Custom/Models/LocationMetadata.cs +++ b/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Custom/Models/LocationMetadata.cs @@ -3,6 +3,7 @@ #nullable disable +using System.ClientModel.Primitives; using System.Runtime.CompilerServices; using System.Text.Json; using Azure.Core; @@ -19,7 +20,7 @@ public partial class LocationMetadata public double? Latitude { get; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteLongitude(Utf8JsonWriter writer) + internal void WriteLongitude(Utf8JsonWriter writer, ModelReaderWriterOptions options) { if (Longitude != null) writer.WriteStringValue(Longitude.ToString()); @@ -35,7 +36,7 @@ internal static void ReadLongitude(JsonProperty property, ref double? longitude) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void WriteLatitude(Utf8JsonWriter writer) + internal void WriteLatitude(Utf8JsonWriter writer, ModelReaderWriterOptions options) { if (Latitude != null) writer.WriteStringValue(Latitude.ToString()); diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Generated/Models/LocationMetadata.Serialization.cs b/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Generated/Models/LocationMetadata.Serialization.cs index af9fdb1262c9..aaf304ef5f97 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Generated/Models/LocationMetadata.Serialization.cs +++ b/sdk/resourcemanager/Azure.ResourceManager/src/Resources/Generated/Models/LocationMetadata.Serialization.cs @@ -51,12 +51,12 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriter if (options.Format != "W" && Optional.IsDefined(Longitude)) { writer.WritePropertyName("longitude"u8); - WriteLongitude(writer); + WriteLongitude(writer, options); } if (options.Format != "W" && Optional.IsDefined(Latitude)) { writer.WritePropertyName("latitude"u8); - WriteLatitude(writer); + WriteLatitude(writer, options); } if (options.Format != "W" && Optional.IsDefined(PhysicalLocation)) { diff --git a/sdk/resourcemanager/Azure.ResourceManager/src/autorest.md b/sdk/resourcemanager/Azure.ResourceManager/src/autorest.md index 84df38f95d5a..e09d55ab8512 100644 --- a/sdk/resourcemanager/Azure.ResourceManager/src/autorest.md +++ b/sdk/resourcemanager/Azure.ResourceManager/src/autorest.md @@ -72,25 +72,22 @@ directive: - from: types.json where: $.definitions.Resource transform: > - $["x-ms-mgmt-referenceType"] = true; - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; + $["x-ms-client-name"] = "ResourceData"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; $["x-csharp-usage"] = "model,input,output"; - from: types.json where: $.definitions.TrackedResource transform: > - $["x-ms-mgmt-referenceType"] = true; - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; + $["x-ms-client-name"] = "TrackedResourceData"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; $["x-csharp-usage"] = "model,input,output"; - from: types.json where: $.definitions.Plan transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -98,7 +95,6 @@ directive: - from: types.json where: $.definitions.Sku transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -106,7 +102,6 @@ directive: - from: types.json where: $.definitions.systemData transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -119,7 +114,6 @@ directive: - from: types.json where: $.definitions.encryptionProperties transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -127,7 +121,6 @@ directive: - from: types.json where: $.definitions.KeyVaultProperties transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -140,8 +133,6 @@ directive: - from: types.json where: $.definitions.OperationStatusResult transform: > - $["x-ms-mgmt-propertyReferenceType"] = false; - $["x-ms-mgmt-typeReferenceType"] = true; $["x-csharp-formats"] = "json"; $["x-csharp-usage"] = "model,input,output"; - from: types.json @@ -151,7 +142,6 @@ directive: - from: managedidentity.json where: $.definitions.SystemAssignedServiceIdentity transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -160,7 +150,6 @@ directive: - from: managedidentity.json where: $.definitions.UserAssignedIdentity transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; $["x-namespace"] = "Azure.ResourceManager.Models"; $["x-accessibility"] = "public"; $["x-csharp-formats"] = "json"; @@ -302,6 +291,8 @@ rename-mapping: ResourceName: ResourceNameValidationContent ResourceName.type: ResourceType|resource-type ResourceNameStatus: ResourceNameValidationStatus + Resource: ResourceData + TrackedResource: TrackedResourceData directive: # These methods can be replaced by using other methods in the same operation group, remove for Preview. @@ -332,10 +323,6 @@ directive: - remove-operation: Providers_RegisterAtManagementGroupScope - remove-operation: Subscriptions_CheckZonePeers - remove-operation: AuthorizationOperations_List - - from: swagger-document - where: $.definitions.ExtendedLocation - transform: > - $["x-ms-mgmt-propertyReferenceType"] = true; # Deduplicate - from: subscriptions.json where: '$.paths["/providers/Microsoft.Resources/operations"].get' @@ -593,10 +580,6 @@ directive: $.GenericResource.properties["changedTime"] = $.GenericResourceExpanded.properties["changedTime"]; $.GenericResource.properties["provisioningState"] = $.GenericResourceExpanded.properties["provisioningState"]; delete $.GenericResourceExpanded; -# - from: resources.json -# where: $.definitions['Provider'] -# transform: > -# $["x-ms-mgmt-propertyReferenceType"] = true # not supported with ResourceData yet, use custom code first - from: locks.json where: $.definitions.ManagementLockObject transform: $["x-ms-client-name"] = "ManagementLock" diff --git a/sdk/search/Azure.ResourceManager.Search/src/Customization/ArmSearchModelFactory.cs b/sdk/search/Azure.ResourceManager.Search/src/Customization/ArmSearchModelFactory.cs index 58689b403d3f..3e4cb4020038 100644 --- a/sdk/search/Azure.ResourceManager.Search/src/Customization/ArmSearchModelFactory.cs +++ b/sdk/search/Azure.ResourceManager.Search/src/Customization/ArmSearchModelFactory.cs @@ -47,12 +47,14 @@ public static SearchServiceData SearchServiceData(ResourceIdentifier id = null, systemData, tags, location, - skuName.ToString(), + // ternary operator must use a nullable instance of the type to avoid triggering the implicit cast on the null + skuName.HasValue ? new SearchServiceSkuName?(skuName.Value.ToSerialString()) : null, identity, replicaCount, partitionCount, hostingMode, - publicNetworkAccess.ToString(), + // ternary operator must use a nullable instance of the type to avoid triggering the implicit cast on the null + publicNetworkAccess.HasValue ? new SearchServicePublicInternetAccess?(publicNetworkAccess.Value.ToSerialString()) : null, status, statusDetails, provisioningState, diff --git a/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/AzDevOpsTests.cs b/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/AzDevOpsTests.cs index 4dc1160cbbd5..aa162247d34e 100644 --- a/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/AzDevOpsTests.cs +++ b/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/AzDevOpsTests.cs @@ -26,7 +26,7 @@ public AzDevOpsTests(bool async) : base(async)//, RecordedTestMode.Record) { // Sanitize Azure DevOps OAuth code for Connector creation - BodyKeySanitizers.Add(new BodyKeySanitizer("Sanitized") { JsonPath = "properties.authorization.code" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.authorization.code")); } [Test] diff --git a/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/GitHubTests.cs b/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/GitHubTests.cs index 9399cdf73d7d..d79b8e28b4f5 100644 --- a/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/GitHubTests.cs +++ b/sdk/securitydevops/Azure.ResourceManager.SecurityDevOps/tests/Tests/GitHubTests.cs @@ -26,7 +26,7 @@ public GitHubTests(bool async) : base(async)//, RecordedTestMode.Record) { // Sanitize GitHub OAuth code for Connector creation - BodyKeySanitizers.Add(new BodyKeySanitizer("Sanitized") { JsonPath = "properties.code" }); + BodyKeySanitizers.Add(new BodyKeySanitizer("properties.code")); } [Test] diff --git a/sdk/selfhelp/Azure.ResourceManager.SelfHelp/CHANGELOG.md b/sdk/selfhelp/Azure.ResourceManager.SelfHelp/CHANGELOG.md index 619762a01823..dd8cb5d19d80 100644 --- a/sdk/selfhelp/Azure.ResourceManager.SelfHelp/CHANGELOG.md +++ b/sdk/selfhelp/Azure.ResourceManager.SelfHelp/CHANGELOG.md @@ -1,5 +1,15 @@ # Release History +## 1.1.0-beta.4 (Unreleased) + +### Features Added + +### Breaking Changes + +### Bugs Fixed + +### Other Changes + ## 1.1.0-beta.3 (2024-05-10) ### Features Added @@ -65,4 +75,4 @@ This package follows the [new Azure SDK guidelines](https://azure.github.io/azur This package is a Public Preview version, so expect incompatible changes in subsequent releases as we improve the product. To provide feedback, submit an issue in our [Azure SDK for .NET GitHub repo](https://github.com/Azure/azure-sdk-for-net/issues). -> NOTE: For more information about unified authentication, please refer to [Microsoft Azure Identity documentation for .NET](https://docs.microsoft.com//dotnet/api/overview/azure/identity-readme?view=azure-dotnet). \ No newline at end of file +> NOTE: For more information about unified authentication, please refer to [Microsoft Azure Identity documentation for .NET](https://docs.microsoft.com//dotnet/api/overview/azure/identity-readme?view=azure-dotnet). diff --git a/sdk/selfhelp/Azure.ResourceManager.SelfHelp/src/Azure.ResourceManager.SelfHelp.csproj b/sdk/selfhelp/Azure.ResourceManager.SelfHelp/src/Azure.ResourceManager.SelfHelp.csproj index 067b216043ec..0ab435cc230c 100644 --- a/sdk/selfhelp/Azure.ResourceManager.SelfHelp/src/Azure.ResourceManager.SelfHelp.csproj +++ b/sdk/selfhelp/Azure.ResourceManager.SelfHelp/src/Azure.ResourceManager.SelfHelp.csproj @@ -1,6 +1,6 @@ - 1.1.0-beta.3 + 1.1.0-beta.4 1.0.0 Azure.ResourceManager.SelfHelp diff --git a/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Administration/ServiceBusManagementClientLiveTests.cs b/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Administration/ServiceBusManagementClientLiveTests.cs index 88465ef4effa..204cd319d664 100644 --- a/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Administration/ServiceBusManagementClientLiveTests.cs +++ b/sdk/servicebus/Azure.Messaging.ServiceBus/tests/Administration/ServiceBusManagementClientLiveTests.cs @@ -33,18 +33,22 @@ public ServiceBusManagementClientLiveTests(bool isAsync, ServiceBusAdministratio SanitizedHeaders.Add("ServiceBusSupplementaryAuthorization"); BodyRegexSanitizers.Add( new BodyRegexSanitizer( - "\\u003CPrimaryKey\\u003E.*\\u003C/PrimaryKey\\u003E", - $"\u003CPrimaryKey\u003E{SanitizedKeyValue}\u003C/PrimaryKey\u003E")); + "\\u003CPrimaryKey\\u003E.*\\u003C/PrimaryKey\\u003E") + { + Value = $"\u003CPrimaryKey\u003E{SanitizedKeyValue}\u003C/PrimaryKey\u003E" + }); BodyRegexSanitizers.Add( new BodyRegexSanitizer( - "\\u003CSecondaryKey\\u003E.*\\u003C/SecondaryKey\\u003E", - $"\u003CSecondaryKey\u003E{SanitizedKeyValue}\u003C/SecondaryKey\u003E")); + "\\u003CSecondaryKey\\u003E.*\\u003C/SecondaryKey\\u003E") + { + Value = $"\u003CSecondaryKey\u003E{SanitizedKeyValue}\u003C/SecondaryKey\u003E" + }); BodyRegexSanitizers.Add( new BodyRegexSanitizer( - "[^\\r](?\\n)", - "\r\n") + "[^\\r](?\\n)") { - GroupForReplace = "break" + GroupForReplace = "break", + Value = "\r\n" }); _serviceVersion = serviceVersion; } diff --git a/sdk/servicelinker/Azure.ResourceManager.ServiceLinker/tests/Tests/WebAppWebPubSubConnectionTests.cs b/sdk/servicelinker/Azure.ResourceManager.ServiceLinker/tests/Tests/WebAppWebPubSubConnectionTests.cs index 74de0290100b..039d919a6466 100644 --- a/sdk/servicelinker/Azure.ResourceManager.ServiceLinker/tests/Tests/WebAppWebPubSubConnectionTests.cs +++ b/sdk/servicelinker/Azure.ResourceManager.ServiceLinker/tests/Tests/WebAppWebPubSubConnectionTests.cs @@ -17,7 +17,7 @@ public class WebAppWebPubSubConnectionTests : ServiceLinkerTestBase { public WebAppWebPubSubConnectionTests() : base(true) { - BodyKeySanitizers.Add(new Core.TestFramework.Models.BodyKeySanitizer("Sanitized") { JsonPath = "$..value", Regex = "AccessKey=.*" }); + BodyKeySanitizers.Add(new Core.TestFramework.Models.BodyKeySanitizer("$..value") { Regex = "AccessKey=.*" }); } [SetUp] diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md index 9851e3714e8b..2fd0b61d267f 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History -## 12.17.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +## 12.17.0 (2024-05-15) +- Includes all features from 12.17.0-beta.1 and 12.17.0-beta.2. ## 12.17.0-beta.2 (2024-04-15) - Added support for service version 2023-05-04. diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj b/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj index f2dfdc69cfd6..ebae152d082e 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj +++ b/sdk/storage/Azure.Storage.Blobs.Batch/src/Azure.Storage.Blobs.Batch.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Blobs.Batch client library - 12.17.0-beta.3 + 12.17.0 12.16.1 BlobSDK;$(DefineConstants) diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/swagger/readme.md b/sdk/storage/Azure.Storage.Blobs.Batch/swagger/readme.md index 8fc0379033d6..b23373d4fbbc 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/swagger/readme.md +++ b/sdk/storage/Azure.Storage.Blobs.Batch/swagger/readme.md @@ -4,7 +4,7 @@ ## Configuration ``` yaml # Generate blob storage -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/storage-dataplane-preview/specification/storage/data-plane/Microsoft.BlobStorage/preview/2020-06-12/blob.json +input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5da3c08b92d05858b728b013b69502dc93485373/specification/storage/data-plane/Microsoft.BlobStorage/stable/2021-12-02/blob.json output-folder: ../src/Generated clear-output-folder: false diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/tests/BlobBatchClientTests.cs b/sdk/storage/Azure.Storage.Blobs.Batch/tests/BlobBatchClientTests.cs index ac5d9e0d3cc3..e846382d5ead 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/tests/BlobBatchClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs.Batch/tests/BlobBatchClientTests.cs @@ -30,9 +30,10 @@ public BlobBatchClientTests(bool async, BlobClientOptions.ServiceVersion service { // Batch delimiters are random so disable body comparison CompareBodies = false; - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"sig=(?.*?)(?=\s+)", SanitizeValue) + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"sig=(?.*?)(?=\s+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = SanitizeValue }); } diff --git a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md index b59efc79a11f..a045b9d7446c 100644 --- a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History -## 12.0.0-preview.44 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +## 12.0.0-preview.44 (2024-05-13) +- This release contains bug fixes to improve quality. ## 12.0.0-preview.43 (2024-04-15) - Added support for service version 2024-05-04. diff --git a/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md index e759d86f7e9a..b1fd81b70d50 100644 --- a/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md @@ -1,16 +1,9 @@ # Release History -## 12.20.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed +## 12.20.0 (2024-05-13) +- Includes all features from 12.20.0-beta.1 and 12.20.0-beta.2. - Fixed bug where `BlobContainerClient` and `BlobBaseClient` did not throw an exception on empty/null container names and blob names, respectively, when constructing a client. -### Other Changes - ## 12.20.0-beta.2 (2024-04-15) - Added support for service version 2024-05-04. - Fixed bug where BlockBlobClient.Upload() and .UploadAsync() would throw an exception if BlobUploadOptions was null. diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs index d147d6336789..2e1a79f257e4 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs @@ -56,8 +56,8 @@ public BlobClientOptions(Azure.Storage.Blobs.BlobClientOptions.ServiceVersion ve public Azure.Storage.Blobs.Models.CustomerProvidedKey? CustomerProvidedKey { get { throw null; } set { } } public bool EnableTenantDiscovery { get { throw null; } set { } } public string EncryptionScope { get { throw null; } set { } } - public Azure.Storage.ExpectContinueOptions ExpectContinueBehavior { get { throw null; } set { } } public System.Uri GeoRedundantSecondaryUri { get { throw null; } set { } } + public Azure.Storage.Request100ContinueOptions Request100ContinueOptions { get { throw null; } set { } } public Azure.Storage.TransferValidationOptions TransferValidation { get { throw null; } } public bool TrimBlobNameSlashes { get { throw null; } set { } } public Azure.Storage.Blobs.BlobClientOptions.ServiceVersion Version { get { throw null; } } diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs index d147d6336789..2e1a79f257e4 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs @@ -56,8 +56,8 @@ public BlobClientOptions(Azure.Storage.Blobs.BlobClientOptions.ServiceVersion ve public Azure.Storage.Blobs.Models.CustomerProvidedKey? CustomerProvidedKey { get { throw null; } set { } } public bool EnableTenantDiscovery { get { throw null; } set { } } public string EncryptionScope { get { throw null; } set { } } - public Azure.Storage.ExpectContinueOptions ExpectContinueBehavior { get { throw null; } set { } } public System.Uri GeoRedundantSecondaryUri { get { throw null; } set { } } + public Azure.Storage.Request100ContinueOptions Request100ContinueOptions { get { throw null; } set { } } public Azure.Storage.TransferValidationOptions TransferValidation { get { throw null; } } public bool TrimBlobNameSlashes { get { throw null; } set { } } public Azure.Storage.Blobs.BlobClientOptions.ServiceVersion Version { get { throw null; } } diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs index d147d6336789..2e1a79f257e4 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs @@ -56,8 +56,8 @@ public BlobClientOptions(Azure.Storage.Blobs.BlobClientOptions.ServiceVersion ve public Azure.Storage.Blobs.Models.CustomerProvidedKey? CustomerProvidedKey { get { throw null; } set { } } public bool EnableTenantDiscovery { get { throw null; } set { } } public string EncryptionScope { get { throw null; } set { } } - public Azure.Storage.ExpectContinueOptions ExpectContinueBehavior { get { throw null; } set { } } public System.Uri GeoRedundantSecondaryUri { get { throw null; } set { } } + public Azure.Storage.Request100ContinueOptions Request100ContinueOptions { get { throw null; } set { } } public Azure.Storage.TransferValidationOptions TransferValidation { get { throw null; } } public bool TrimBlobNameSlashes { get { throw null; } set { } } public Azure.Storage.Blobs.BlobClientOptions.ServiceVersion Version { get { throw null; } } diff --git a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj index 39656e6b502a..ac79c4b47277 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj +++ b/sdk/storage/Azure.Storage.Blobs/src/Azure.Storage.Blobs.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Blobs client library - 12.20.0-beta.3 + 12.20.0 12.19.1 BlobSDK;$(DefineConstants) diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs index a8f8ba8b6aef..c2dae15976fa 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs @@ -191,7 +191,7 @@ public enum ServiceVersion /// /// Behavior options for setting HTTP header Expect: 100-continue on requests. /// - public ExpectContinueOptions ExpectContinueBehavior { get; set; } + public Request100ContinueOptions Request100ContinueOptions { get; set; } #region Advanced Options internal ClientSideEncryptionOptions _clientSideEncryptionOptions; @@ -344,7 +344,7 @@ private void AddHeadersAndQueryParameters() /// An HttpPipeline to use for Storage requests. internal HttpPipeline Build(HttpPipelinePolicy authentication = null) { - return this.Build(authentication, GeoRedundantSecondaryUri, ExpectContinueBehavior); + return this.Build(authentication, GeoRedundantSecondaryUri, Request100ContinueOptions); } /// @@ -354,7 +354,7 @@ internal HttpPipeline Build(HttpPipelinePolicy authentication = null) /// An HttpPipeline to use for Storage requests. internal HttpPipeline Build(object credentials) { - return this.Build(credentials, GeoRedundantSecondaryUri, ExpectContinueBehavior); + return this.Build(credentials, GeoRedundantSecondaryUri, Request100ContinueOptions); } /// diff --git a/sdk/storage/Azure.Storage.Blobs/tests/BlobClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/BlobClientTests.cs index 283b3a175e02..2d9d9478d2ef 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/BlobClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/BlobClientTests.cs @@ -1337,7 +1337,7 @@ public async Task UploadAsync_ExpectContinue() }); BlobClientOptions options = GetOptions(); - options.ExpectContinueBehavior = new() { Mode = ExpectContinueMode.On }; + options.Request100ContinueOptions = new() { Mode = Request100ContinueMode.Always }; options.AddPolicy(assertPolicy, Core.HttpPipelinePosition.BeforeTransport); await using DisposingContainer test = await GetTestContainerAsync( BlobsClientBuilder.GetServiceClient_SharedKey(options)); diff --git a/sdk/storage/Azure.Storage.Common/CHANGELOG.md b/sdk/storage/Azure.Storage.Common/CHANGELOG.md index 675473ab7da9..cb3d169bdb43 100644 --- a/sdk/storage/Azure.Storage.Common/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Common/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History -## 12.19.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +## 12.19.0 (2024-05-13) +- This release contains bug fixes to improve quality. ## 12.19.0-beta.2 (2024-04-15) - This release contains bug fixes to improve quality. diff --git a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs index b5359ef52877..a50804a78c8b 100644 --- a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs +++ b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs @@ -20,18 +20,18 @@ public DownloadTransferValidationOptions() { } public bool AutoValidateChecksum { get { throw null; } set { } } public Azure.Storage.StorageChecksumAlgorithm ChecksumAlgorithm { get { throw null; } set { } } } - public enum ExpectContinueMode + public enum Request100ContinueMode { - ApplyOnThrottle = 0, - On = 1, - Off = 2, + Auto = 0, + Always = 1, + Never = 2, } - public partial class ExpectContinueOptions + public partial class Request100ContinueOptions { - public ExpectContinueOptions() { } + public Request100ContinueOptions() { } + public System.TimeSpan AutoInterval { get { throw null; } set { } } public long? ContentLengthThreshold { get { throw null; } set { } } - public Azure.Storage.ExpectContinueMode Mode { get { throw null; } set { } } - public System.TimeSpan ThrottleInterval { get { throw null; } set { } } + public Azure.Storage.Request100ContinueMode Mode { get { throw null; } set { } } } public enum StorageChecksumAlgorithm { diff --git a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs index d89a33a1426c..38656a564b12 100644 --- a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs @@ -20,18 +20,18 @@ public DownloadTransferValidationOptions() { } public bool AutoValidateChecksum { get { throw null; } set { } } public Azure.Storage.StorageChecksumAlgorithm ChecksumAlgorithm { get { throw null; } set { } } } - public enum ExpectContinueMode + public enum Request100ContinueMode { - ApplyOnThrottle = 0, - On = 1, - Off = 2, + Auto = 0, + Always = 1, + Never = 2, } - public partial class ExpectContinueOptions + public partial class Request100ContinueOptions { - public ExpectContinueOptions() { } + public Request100ContinueOptions() { } + public System.TimeSpan AutoInterval { get { throw null; } set { } } public long? ContentLengthThreshold { get { throw null; } set { } } - public Azure.Storage.ExpectContinueMode Mode { get { throw null; } set { } } - public System.TimeSpan ThrottleInterval { get { throw null; } set { } } + public Azure.Storage.Request100ContinueMode Mode { get { throw null; } set { } } } public enum StorageChecksumAlgorithm { diff --git a/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj b/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj index 857c440a9645..adfc4c475383 100644 --- a/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj +++ b/sdk/storage/Azure.Storage.Common/src/Azure.Storage.Common.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Common client library - 12.19.0-beta.3 + 12.19.0 12.18.1 CommonSDK;$(DefineConstants) diff --git a/sdk/storage/Azure.Storage.Common/src/ExpectContinueMode.cs b/sdk/storage/Azure.Storage.Common/src/Request100ContinueMode.cs similarity index 91% rename from sdk/storage/Azure.Storage.Common/src/ExpectContinueMode.cs rename to sdk/storage/Azure.Storage.Common/src/Request100ContinueMode.cs index f48d5ed3aac0..8809f7fe1ffb 100644 --- a/sdk/storage/Azure.Storage.Common/src/ExpectContinueMode.cs +++ b/sdk/storage/Azure.Storage.Common/src/Request100ContinueMode.cs @@ -6,7 +6,7 @@ namespace Azure.Storage /// /// Mode for applying expect-continue to a PUT request. /// - public enum ExpectContinueMode + public enum Request100ContinueMode { /// /// If no options are provided, this is the default behavior. @@ -19,17 +19,17 @@ public enum ExpectContinueMode /// Response codes that trigger this behavior are 429, 500, and 503. /// /// - ApplyOnThrottle = 0, + Auto = 0, /// /// Expect-continue will be applied regardless of recent error status. There may be /// some additionally defined thresholds for applying the header. /// - On = 1, + Always = 1, /// /// Expect-Continue will never be applied. /// - Off = 2, + Never = 2, } } diff --git a/sdk/storage/Azure.Storage.Common/src/ExpectContinueOptions.cs b/sdk/storage/Azure.Storage.Common/src/Request100ContinueOptions.cs similarity index 70% rename from sdk/storage/Azure.Storage.Common/src/ExpectContinueOptions.cs rename to sdk/storage/Azure.Storage.Common/src/Request100ContinueOptions.cs index 727c57f63bf5..ec9cf6df5d0e 100644 --- a/sdk/storage/Azure.Storage.Common/src/ExpectContinueOptions.cs +++ b/sdk/storage/Azure.Storage.Common/src/Request100ContinueOptions.cs @@ -8,12 +8,12 @@ namespace Azure.Storage /// /// Options for applying HTTP header Expect: 100-continue to PUT operations. /// - public class ExpectContinueOptions + public class Request100ContinueOptions { /// /// Mode for these options. /// - public ExpectContinueMode Mode { get; set; } + public Request100ContinueMode Mode { get; set; } /// /// The minimum value of HTTP request Content-Length for applying expect-continue. @@ -21,9 +21,9 @@ public class ExpectContinueOptions public long? ContentLengthThreshold { get; set; } /// - /// In mode , the time interval to apply the header + /// In mode , the time interval to apply the header /// after recieving a triggering error. The default time is one minute. /// - public TimeSpan ThrottleInterval { get; set; } = TimeSpan.FromMinutes(1); + public TimeSpan AutoInterval { get; set; } = TimeSpan.FromMinutes(1); } } diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/CompatSwitches.cs b/sdk/storage/Azure.Storage.Common/src/Shared/CompatSwitches.cs index 05a3d8567f78..04e4f7cd4cf9 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/CompatSwitches.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/CompatSwitches.cs @@ -11,5 +11,10 @@ internal static class CompatSwitches public static bool DisableRequestConditionsValidation => _disableRequestConditionsValidation ??= AppContextSwitchHelper.GetConfigValue(Constants.DisableRequestConditionsValidationSwitchName, Constants.DisableRequestConditionsValidationEnvVar); + + private static bool? _disableExpectContinueHeader; + + public static bool DisableExpectContinueHeader => _disableExpectContinueHeader + ??= AppContextSwitchHelper.GetConfigValue(Constants.DisableExpectContinueHeaderSwitchName, Constants.DisableExpectContinueHeaderEnvVar); } } diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs b/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs index e0c721ed2466..c8ce04f6f4e4 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs @@ -123,6 +123,9 @@ internal static class Constants public const string DisableRequestConditionsValidationSwitchName = "Azure.Storage.DisableRequestConditionsValidation"; public const string DisableRequestConditionsValidationEnvVar = "AZURE_STORAGE_DISABLE_REQUEST_CONDITIONS_VALIDATION"; + public const string DisableExpectContinueHeaderSwitchName = "Azure.Storage.DisableExpectContinueHeader"; + public const string DisableExpectContinueHeaderEnvVar = "AZURE_STORAGE_DISABLE_EXPECT_CONTINUE_HEADER"; + public const string DefaultScope = "/.default"; /// diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinueOnThrottlePolicy.cs b/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinueOnThrottlePolicy.cs index 57bcb6abb62d..5d3c60d61aec 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinueOnThrottlePolicy.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinueOnThrottlePolicy.cs @@ -24,7 +24,8 @@ public TimeSpan ThrottleInterval public override void OnSendingRequest(HttpMessage message) { if (message.Request.Content == null || - (message.Request.Content.TryComputeLength(out long contentLength) && contentLength < ContentLengthThreshold)) + (message.Request.Content.TryComputeLength(out long contentLength) && contentLength < ContentLengthThreshold) || + CompatSwitches.DisableExpectContinueHeader) { return; } diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinuePolicy.cs b/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinuePolicy.cs index dfe8afd71fd7..fdd2dcfb143a 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinuePolicy.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/ExpectContinuePolicy.cs @@ -12,7 +12,7 @@ internal class ExpectContinuePolicy : HttpPipelineSynchronousPolicy public override void OnSendingRequest(HttpMessage message) { - if (message.Request.Content == null) + if (message.Request.Content == null || CompatSwitches.DisableExpectContinueHeader) { return; } diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/StorageClientOptions.cs b/sdk/storage/Azure.Storage.Common/src/Shared/StorageClientOptions.cs index 71cd25307245..e839e6042ef8 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/StorageClientOptions.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/StorageClientOptions.cs @@ -109,7 +109,7 @@ public static HttpPipeline Build( this ClientOptions options, HttpPipelinePolicy authentication = null, Uri geoRedundantSecondaryStorageUri = null, - ExpectContinueOptions expectContinue = null) + Request100ContinueOptions expectContinue = null) { StorageResponseClassifier classifier = new(); var pipelineOptions = new HttpPipelineOptions(options) @@ -131,20 +131,20 @@ public static HttpPipeline Build( { switch (expectContinue.Mode) { - case ExpectContinueMode.ApplyOnThrottle: + case Request100ContinueMode.Auto: pipelineOptions.PerCallPolicies.Add(new ExpectContinueOnThrottlePolicy() { - ThrottleInterval = expectContinue.ThrottleInterval, + ThrottleInterval = expectContinue.AutoInterval, ContentLengthThreshold = expectContinue.ContentLengthThreshold ?? 0, }); break; - case ExpectContinueMode.On: + case Request100ContinueMode.Always: pipelineOptions.PerCallPolicies.Add(new ExpectContinuePolicy() { ContentLengthThreshold = expectContinue.ContentLengthThreshold ?? 0, }); break; - case ExpectContinueMode.Off: + case Request100ContinueMode.Never: break; } } @@ -172,7 +172,7 @@ public static HttpPipeline Build( this ClientOptions options, object credentials, Uri geoRedundantSecondaryStorageUri = null, - ExpectContinueOptions expectContinue = null) => + Request100ContinueOptions expectContinue = null) => Build(options, GetAuthenticationPolicy(credentials), geoRedundantSecondaryStorageUri, expectContinue); } } diff --git a/sdk/storage/Azure.Storage.Common/tests/Azure.Storage.Common.Tests.csproj b/sdk/storage/Azure.Storage.Common/tests/Azure.Storage.Common.Tests.csproj index 3d9f099791c8..5db86ebee984 100644 --- a/sdk/storage/Azure.Storage.Common/tests/Azure.Storage.Common.Tests.csproj +++ b/sdk/storage/Azure.Storage.Common/tests/Azure.Storage.Common.Tests.csproj @@ -29,6 +29,7 @@ + diff --git a/sdk/storage/Azure.Storage.Common/tests/Shared/StorageTestBase.cs b/sdk/storage/Azure.Storage.Common/tests/Shared/StorageTestBase.cs index 15f71f1b63c0..a2050b43d996 100644 --- a/sdk/storage/Azure.Storage.Common/tests/Shared/StorageTestBase.cs +++ b/sdk/storage/Azure.Storage.Common/tests/Shared/StorageTestBase.cs @@ -49,26 +49,31 @@ public StorageTestBase(bool async, RecordedTestMode? mode = null) #if NETFRAMEWORK // Uri uses different escaping for some special characters between .NET Framework and Core. Because the Test Proxy runs on .NET // Core, we need to normalize to the .NET Core escaping when matching and storing the recordings when running tests on NetFramework. - UriRegexSanitizers.Add(new UriRegexSanitizer("\\(", "%28")); - UriRegexSanitizers.Add(new UriRegexSanitizer("\\)", "%29")); - UriRegexSanitizers.Add(new UriRegexSanitizer("\\!", "%21")); - UriRegexSanitizers.Add(new UriRegexSanitizer("\\'", "%27")); - UriRegexSanitizers.Add(new UriRegexSanitizer("\\*", "%2A")); + UriRegexSanitizers.Add(new UriRegexSanitizer("\\("){ Value = "%28" }); + UriRegexSanitizers.Add(new UriRegexSanitizer("\\)"){ Value = "%29" }); + UriRegexSanitizers.Add(new UriRegexSanitizer("\\!"){ Value = "%21" }); + UriRegexSanitizers.Add(new UriRegexSanitizer("\\'"){ Value = "%27" }); + UriRegexSanitizers.Add(new UriRegexSanitizer("\\*"){ Value = "%2A" }); // Encode any colons in the Uri except for the one in the scheme - UriRegexSanitizers.Add(new UriRegexSanitizer("(?:)[^//]", "%3A") {GroupForReplace = "group"}); + UriRegexSanitizers.Add(new UriRegexSanitizer("(?:)[^//]") + { + GroupForReplace = "group", + Value = "%3A" + }); #endif - HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("x-ms-encryption-key", SanitizeValue)); - HeaderRegexSanitizers.Add(new HeaderRegexSanitizer(CopySourceAuthorization, SanitizeValue)); + HeaderRegexSanitizers.Add(new HeaderRegexSanitizer("x-ms-encryption-key")); + HeaderRegexSanitizers.Add(new HeaderRegexSanitizer(CopySourceAuthorization)); SanitizedQueryParametersInHeaders.Add((CopySourceName, SignatureQueryName)); SanitizedQueryParametersInHeaders.Add((RenameSource, SignatureQueryName)); SanitizedQueryParametersInHeaders.Add((PreviousSnapshotUrl, SignatureQueryName)); SanitizedQueryParametersInHeaders.Add((FileRenameSource, SignatureQueryName)); - BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"client_secret=(?.*?)(?=&|$)", SanitizeValue) + BodyRegexSanitizers.Add(new BodyRegexSanitizer(@"client_secret=(?.*?)(?=&|$)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = SanitizeValue }); Tenants = new TenantConfigurationBuilder(this); diff --git a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md index 6175bd08b06f..a7f369d727d9 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md @@ -1,16 +1,9 @@ # Release History -## 12.18.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed +## 12.18.0 (2024-05-13) +- Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. - Fixed bug where `DataLakeFileSystemClient` and `DatalakeFileClient` did not throw an exception on empty/null filesystem names and file names, respectively, when constructing a client. -### Other Changes - ## 12.18.0-beta.2 (2024-04-15) - Added support for service version 2024-05-04. - Added ability to retrieve path ACL with DataLakePath/File/DirectoryClient.GetProperties(), .GetPropertiesAsync(), DataLakeFileClient.Read(), and .ReadAsync(). diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj b/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj index b4fc225d46fe..84ed7dd77fd8 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/Azure.Storage.Files.DataLake.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Files.DataLake client library - 12.18.0-beta.3 + 12.18.0 12.17.1 DataLakeSDK;$(DefineConstants) diff --git a/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md b/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md index a255af79bc66..f7bdc241c8c2 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md @@ -1,16 +1,9 @@ # Release History -## 12.18.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed +## 12.18.0 (2024-05-13) +- Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. - Fixed bug where `ShareClient` and `ShareFileClient` did not throw an exception on empty/null share container names and file names, respectively, when constructing a client. -### Other Changes - ## 12.18.0-beta.2 (2024-04-15) - Added support for service version 2024-05-04. - Added ability to retrieve file handle client name with ShareFile/DirectoryClient.GetHandles() and .GetHandlesAsync(). diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj index 9ea30b62c236..1d84847c7189 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Files.Shares client library - 12.18.0-beta.3 + 12.18.0 12.17.1 FileSDK;$(DefineConstants) diff --git a/sdk/storage/Azure.Storage.Queues/CHANGELOG.md b/sdk/storage/Azure.Storage.Queues/CHANGELOG.md index fed9958fc254..12216fa5bf05 100644 --- a/sdk/storage/Azure.Storage.Queues/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Queues/CHANGELOG.md @@ -1,16 +1,9 @@ # Release History -## 12.18.0-beta.3 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed +## 12.18.0 (2024-05-13) +- Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. - Fixed bug where `QueueClient` did not throw an exception on empty/null queue names when constructing a client. -### Other Changes - ## 12.18.0-beta.2 (2024-04-15) - Added support for service version 2024-05-04. diff --git a/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj b/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj index 7205eca20f4d..d14210ad9921 100644 --- a/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj +++ b/sdk/storage/Azure.Storage.Queues/src/Azure.Storage.Queues.csproj @@ -4,7 +4,7 @@ Microsoft Azure.Storage.Queues client library - 12.18.0-beta.3 + 12.18.0 12.17.1 QueueSDK;$(DefineConstants) diff --git a/sdk/subscription/Azure.ResourceManager.Subscription/tests/SubscriptionManagementTestBase.cs b/sdk/subscription/Azure.ResourceManager.Subscription/tests/SubscriptionManagementTestBase.cs index b7240ff41e08..44c0b5eee619 100644 --- a/sdk/subscription/Azure.ResourceManager.Subscription/tests/SubscriptionManagementTestBase.cs +++ b/sdk/subscription/Azure.ResourceManager.Subscription/tests/SubscriptionManagementTestBase.cs @@ -45,17 +45,17 @@ private void IgnoreApiVersionInTagOperations() { // Ignore the api-version of tagNames operations including list UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/subscriptions/[^/]+/tagNames[/]?[^/]*api-version=(?[a-z0-9-]+)", "**" - ) + @"/subscriptions/[^/]+/tagNames[/]?[^/]*api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); // Ignore the api-version of tagValues operations UriRegexSanitizers.Add(new UriRegexSanitizer( - @"/subscriptions/[^/]+/tagNames/[^/]+/tagValues/[^/]+api-version=(?[a-z0-9-]+)", "**" - ) + @"/subscriptions/[^/]+/tagNames/[^/]+/tagValues/[^/]+api-version=(?[a-z0-9-]+)") { - GroupForReplace = "group" + GroupForReplace = "group", + Value = "**" }); } } diff --git a/sdk/tables/Azure.Data.Tables/tests/TableServiceLiveTestsBase.cs b/sdk/tables/Azure.Data.Tables/tests/TableServiceLiveTestsBase.cs index f681204d7c9c..fa450ac6dd1b 100644 --- a/sdk/tables/Azure.Data.Tables/tests/TableServiceLiveTestsBase.cs +++ b/sdk/tables/Azure.Data.Tables/tests/TableServiceLiveTestsBase.cs @@ -31,7 +31,7 @@ public TableServiceLiveTestsBase(bool isAsync, TableEndpointType endpointType, R _enableTenantDiscovery = enableTenantDiscovery; SanitizedHeaders.Add("My-Custom-Auth-Header"); UriRegexSanitizers.Add( - new UriRegexSanitizer(@"([\x0026|&|?]sig=)(?[\w\d%]+)", SanitizeValue) + new UriRegexSanitizer(@"([\x0026|&|?]sig=)(?[\w\d%]+)") { GroupForReplace = "group" }); diff --git a/sdk/vision/Azure.AI.Vision.ImageAnalysis/tests/ImageAnalysisTestBase.cs b/sdk/vision/Azure.AI.Vision.ImageAnalysis/tests/ImageAnalysisTestBase.cs index bcc9873b0f0a..5c231dcabb94 100644 --- a/sdk/vision/Azure.AI.Vision.ImageAnalysis/tests/ImageAnalysisTestBase.cs +++ b/sdk/vision/Azure.AI.Vision.ImageAnalysis/tests/ImageAnalysisTestBase.cs @@ -20,8 +20,8 @@ public abstract class ImageAnalysisTestBase : RecordedTestBase Get(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetAllConfigurationData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetAllConfigurationDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsAsync` instead", false)] public virtual Azure.Response GetAllHybridConnectionData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsAsync` instead", false)] public virtual System.Threading.Tasks.Task> GetAllHybridConnectionDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response GetAllPremierAddOnData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAllPremierAddOnDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -4383,6 +4387,8 @@ protected WebSiteResource() { } public virtual Azure.AsyncPageable GetHistoryForWebAppRecommendationsAsync(bool? expiredOnly = default(bool?), string filter = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response GetHostKeys(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetHostKeysAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetHybridConnections(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetHybridConnectionsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.ResourceManager.AppService.LogsSiteConfigResource GetLogsSiteConfig() { throw null; } public virtual Azure.Response GetMetadata(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetMetadataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -4919,7 +4925,11 @@ protected WebSiteSlotResource() { } public virtual Azure.Response Get(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetAllConfigurationSlotData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetAllConfigurationSlotDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsSlot` instead", false)] public virtual Azure.Response GetAllHybridConnectionSlotData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsSlotAsync` instead", false)] public virtual System.Threading.Tasks.Task> GetAllHybridConnectionSlotDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response GetAllPremierAddOnSlotData(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAllPremierAddOnSlotDataAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -4946,6 +4956,8 @@ protected WebSiteSlotResource() { } public virtual System.Threading.Tasks.Task> GetFunctionsAdminTokenSlotAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response GetHostKeysSlot(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetHostKeysSlotAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetHybridConnectionsSlot(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetHybridConnectionsSlotAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.ResourceManager.AppService.LogsSiteSlotConfigResource GetLogsSiteSlotConfig() { throw null; } public virtual Azure.Response GetMetadataSlot(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetMetadataSlotAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } diff --git a/sdk/websites/Azure.ResourceManager.AppService/assets.json b/sdk/websites/Azure.ResourceManager.AppService/assets.json index 436139cad36a..236be26a781b 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/assets.json +++ b/sdk/websites/Azure.ResourceManager.AppService/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/websites/Azure.ResourceManager.AppService", - "Tag": "net/websites/Azure.ResourceManager.AppService_438b9596a0" + "Tag": "net/websites/Azure.ResourceManager.AppService_9137631a43" } diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteResource.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteResource.cs index 7f0bc0f8f8e0..5780a9bae44d 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteResource.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteResource.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Threading; @@ -140,20 +141,12 @@ Page NextPageFunc(string nextLink, int? pageSizeHint) /// /// /// The cancellation token to use. - public virtual async Task> GetAllHybridConnectionDataAsync(CancellationToken cancellationToken = default) + /// due to this isssue https://github.com/Azure/azure-sdk-for-net/issues/43813, and this method doesn't work,so just throw Exception. + [Obsolete("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsAsync` instead", false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task> GetAllHybridConnectionDataAsync(CancellationToken cancellationToken = default) { - using var scope = _webSiteWebAppsClientDiagnostics.CreateScope("WebSiteResource.GetAllHybridConnectionData"); - scope.Start(); - try - { - var response = await _webSiteWebAppsRestClient.ListHybridConnectionsAsync(Id.SubscriptionId, Id.ResourceGroupName, Id.Name, cancellationToken).ConfigureAwait(false); - return response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } + throw new Exception("Obsolete method, Use GetHybridConnectionsAsync instead."); } /// @@ -166,24 +159,17 @@ public virtual async Task> GetAllHybridConnection /// /// Operation Id /// WebApps_ListHybridConnections + /// WebApps_ListHybridConnections /// /// /// /// The cancellation token to use. + ///due to this isssue https://github.com/Azure/azure-sdk-for-net/issues/43813, and this method doesn't work,so just throw Exception. + [Obsolete("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsAsync` instead", false)] + [EditorBrowsable(EditorBrowsableState.Never)] public virtual Response GetAllHybridConnectionData(CancellationToken cancellationToken = default) { - using var scope = _webSiteWebAppsClientDiagnostics.CreateScope("WebSiteResource.GetAllHybridConnectionData"); - scope.Start(); - try - { - var response = _webSiteWebAppsRestClient.ListHybridConnections(Id.SubscriptionId, Id.ResourceGroupName, Id.Name, cancellationToken); - return response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } + throw new Exception("Obsolete method, Use GetHybridConnectionsAsync instead."); } /// diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteSlotResource.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteSlotResource.cs index 3e32c59f01c5..0da91a7f2cf4 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteSlotResource.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Customization/WebSiteSlotResource.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Threading; @@ -139,20 +140,12 @@ Page NextPageFunc(string nextLink, int? pageSizeHint) /// /// /// The cancellation token to use. - public virtual async Task> GetAllHybridConnectionSlotDataAsync(CancellationToken cancellationToken = default) + ///due to this isssue https://github.com/Azure/azure-sdk-for-net/issues/43813, and this method doesn't work,so just throw Exception. + [Obsolete("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsSlotAsync` instead", false)] + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task> GetAllHybridConnectionSlotDataAsync(CancellationToken cancellationToken = default) { - using var scope = _webSiteSlotWebAppsClientDiagnostics.CreateScope("WebSiteSlotResource.GetAllHybridConnectionSlotData"); - scope.Start(); - try - { - var response = await _webSiteSlotWebAppsRestClient.ListHybridConnectionsSlotAsync(Id.SubscriptionId, Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken).ConfigureAwait(false); - return response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } + throw new Exception("Obsolete method, Use GetHybridConnectionsSlotAsync instead."); } /// @@ -169,20 +162,12 @@ public virtual async Task> GetAllHybridConnection /// /// /// The cancellation token to use. + /// due to this isssue https://github.com/Azure/azure-sdk-for-net/issues/43813, and this method doesn't work,so just throw Exception. + [Obsolete("This method is obsolete and will be removed in a future release, please use `GetHybridConnectionsSlot` instead", false)] + [EditorBrowsable(EditorBrowsableState.Never)] public virtual Response GetAllHybridConnectionSlotData(CancellationToken cancellationToken = default) { - using var scope = _webSiteSlotWebAppsClientDiagnostics.CreateScope("WebSiteSlotResource.GetAllHybridConnectionSlotData"); - scope.Start(); - try - { - var response = _webSiteSlotWebAppsRestClient.ListHybridConnectionsSlot(Id.SubscriptionId, Id.ResourceGroupName, Id.Parent.Name, Id.Name, cancellationToken); - return response; - } - catch (Exception e) - { - scope.Failed(e); - throw; - } + throw new Exception("Obsolete method, Use GetHybridConnectionsSlot instead."); } /// diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/Models/HybridConnectionListResult.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/Models/HybridConnectionListResult.cs index 57fb40575898..166cf09ecb96 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/Models/HybridConnectionListResult.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/Models/HybridConnectionListResult.cs @@ -73,8 +73,10 @@ internal HybridConnectionListResult() } /// Collection of resources. + [WirePath("value")] public IReadOnlyList Value { get; } /// Link to next page of resources. + [WirePath("nextLink")] public string NextLink { get; } } } diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/RestOperations/WebAppsRestOperations.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/RestOperations/WebAppsRestOperations.cs index 1678e84299a7..ab4f5df2008c 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/RestOperations/WebAppsRestOperations.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/RestOperations/WebAppsRestOperations.cs @@ -9369,7 +9369,7 @@ internal HttpMessage CreateListHybridConnectionsRequest(string subscriptionId, s /// The cancellation token to use. /// , or is null. /// , or is an empty string, and was expected to be non-empty. - public async Task> ListHybridConnectionsAsync(string subscriptionId, string resourceGroupName, string name, CancellationToken cancellationToken = default) + public async Task> ListHybridConnectionsAsync(string subscriptionId, string resourceGroupName, string name, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(subscriptionId, nameof(subscriptionId)); Argument.AssertNotNullOrEmpty(resourceGroupName, nameof(resourceGroupName)); @@ -9381,9 +9381,9 @@ public async Task> ListHybridConnectionsAsync(str { case 200: { - HybridConnectionData value = default; + HybridConnectionListResult value = default; using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); - value = HybridConnectionData.DeserializeHybridConnectionData(document.RootElement); + value = HybridConnectionListResult.DeserializeHybridConnectionListResult(document.RootElement); return Response.FromValue(value, message.Response); } default: @@ -9398,7 +9398,7 @@ public async Task> ListHybridConnectionsAsync(str /// The cancellation token to use. /// , or is null. /// , or is an empty string, and was expected to be non-empty. - public Response ListHybridConnections(string subscriptionId, string resourceGroupName, string name, CancellationToken cancellationToken = default) + public Response ListHybridConnections(string subscriptionId, string resourceGroupName, string name, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(subscriptionId, nameof(subscriptionId)); Argument.AssertNotNullOrEmpty(resourceGroupName, nameof(resourceGroupName)); @@ -9410,9 +9410,9 @@ public Response ListHybridConnections(string subscriptionI { case 200: { - HybridConnectionData value = default; + HybridConnectionListResult value = default; using var document = JsonDocument.Parse(message.Response.ContentStream); - value = HybridConnectionData.DeserializeHybridConnectionData(document.RootElement); + value = HybridConnectionListResult.DeserializeHybridConnectionListResult(document.RootElement); return Response.FromValue(value, message.Response); } default: @@ -26324,7 +26324,7 @@ internal HttpMessage CreateListHybridConnectionsSlotRequest(string subscriptionI /// The cancellation token to use. /// , , or is null. /// , , or is an empty string, and was expected to be non-empty. - public async Task> ListHybridConnectionsSlotAsync(string subscriptionId, string resourceGroupName, string name, string slot, CancellationToken cancellationToken = default) + public async Task> ListHybridConnectionsSlotAsync(string subscriptionId, string resourceGroupName, string name, string slot, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(subscriptionId, nameof(subscriptionId)); Argument.AssertNotNullOrEmpty(resourceGroupName, nameof(resourceGroupName)); @@ -26337,9 +26337,9 @@ public async Task> ListHybridConnectionsSlotAsync { case 200: { - HybridConnectionData value = default; + HybridConnectionListResult value = default; using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); - value = HybridConnectionData.DeserializeHybridConnectionData(document.RootElement); + value = HybridConnectionListResult.DeserializeHybridConnectionListResult(document.RootElement); return Response.FromValue(value, message.Response); } default: @@ -26355,7 +26355,7 @@ public async Task> ListHybridConnectionsSlotAsync /// The cancellation token to use. /// , , or is null. /// , , or is an empty string, and was expected to be non-empty. - public Response ListHybridConnectionsSlot(string subscriptionId, string resourceGroupName, string name, string slot, CancellationToken cancellationToken = default) + public Response ListHybridConnectionsSlot(string subscriptionId, string resourceGroupName, string name, string slot, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(subscriptionId, nameof(subscriptionId)); Argument.AssertNotNullOrEmpty(resourceGroupName, nameof(resourceGroupName)); @@ -26368,9 +26368,9 @@ public Response ListHybridConnectionsSlot(string subscript { case 200: { - HybridConnectionData value = default; + HybridConnectionListResult value = default; using var document = JsonDocument.Parse(message.Response.ContentStream); - value = HybridConnectionData.DeserializeHybridConnectionData(document.RootElement); + value = HybridConnectionListResult.DeserializeHybridConnectionListResult(document.RootElement); return Response.FromValue(value, message.Response); } default: diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteResource.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteResource.cs index 549fff15c273..9deca7c3d854 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteResource.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteResource.cs @@ -4564,6 +4564,64 @@ public virtual Response DeleteHostSecret(string keyType, string keyName, Cancell } } + /// + /// Description for Retrieves all Service Bus Hybrid Connections used by this Web App. + /// + /// + /// Request Path + /// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/hybridConnectionRelays + /// + /// + /// Operation Id + /// WebApps_ListHybridConnections + /// + /// + /// Default Api Version + /// 2021-02-01 + /// + /// + /// Resource + /// + /// + /// + /// + /// The cancellation token to use. + /// An async collection of that may take multiple service requests to iterate over. + public virtual AsyncPageable GetHybridConnectionsAsync(CancellationToken cancellationToken = default) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => _webSiteWebAppsRestClient.CreateListHybridConnectionsRequest(Id.SubscriptionId, Id.ResourceGroupName, Id.Name); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, null, e => HybridConnectionData.DeserializeHybridConnectionData(e), _webSiteWebAppsClientDiagnostics, Pipeline, "WebSiteResource.GetHybridConnections", "value", null, cancellationToken); + } + + /// + /// Description for Retrieves all Service Bus Hybrid Connections used by this Web App. + /// + /// + /// Request Path + /// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/hybridConnectionRelays + /// + /// + /// Operation Id + /// WebApps_ListHybridConnections + /// + /// + /// Default Api Version + /// 2021-02-01 + /// + /// + /// Resource + /// + /// + /// + /// + /// The cancellation token to use. + /// A collection of that may take multiple service requests to iterate over. + public virtual Pageable GetHybridConnections(CancellationToken cancellationToken = default) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => _webSiteWebAppsRestClient.CreateListHybridConnectionsRequest(Id.SubscriptionId, Id.ResourceGroupName, Id.Name); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, null, e => HybridConnectionData.DeserializeHybridConnectionData(e), _webSiteWebAppsClientDiagnostics, Pipeline, "WebSiteResource.GetHybridConnections", "value", null, cancellationToken); + } + /// /// Description for Shows whether an app can be cloned to another resource group or subscription. /// diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteSlotResource.cs b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteSlotResource.cs index 46bc822c36fa..e3da142f6e66 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteSlotResource.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/src/Generated/WebSiteSlotResource.cs @@ -4226,6 +4226,64 @@ public virtual Response DeleteHostSecretSlot(string keyType, string keyName, Can } } + /// + /// Description for Retrieves all Service Bus Hybrid Connections used by this Web App. + /// + /// + /// Request Path + /// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/slots/{slot}/hybridConnectionRelays + /// + /// + /// Operation Id + /// WebApps_ListHybridConnectionsSlot + /// + /// + /// Default Api Version + /// 2021-02-01 + /// + /// + /// Resource + /// + /// + /// + /// + /// The cancellation token to use. + /// An async collection of that may take multiple service requests to iterate over. + public virtual AsyncPageable GetHybridConnectionsSlotAsync(CancellationToken cancellationToken = default) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => _webSiteSlotWebAppsRestClient.CreateListHybridConnectionsSlotRequest(Id.SubscriptionId, Id.ResourceGroupName, Id.Parent.Name, Id.Name); + return GeneratorPageableHelpers.CreateAsyncPageable(FirstPageRequest, null, e => HybridConnectionData.DeserializeHybridConnectionData(e), _webSiteSlotWebAppsClientDiagnostics, Pipeline, "WebSiteSlotResource.GetHybridConnectionsSlot", "value", null, cancellationToken); + } + + /// + /// Description for Retrieves all Service Bus Hybrid Connections used by this Web App. + /// + /// + /// Request Path + /// /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/slots/{slot}/hybridConnectionRelays + /// + /// + /// Operation Id + /// WebApps_ListHybridConnectionsSlot + /// + /// + /// Default Api Version + /// 2021-02-01 + /// + /// + /// Resource + /// + /// + /// + /// + /// The cancellation token to use. + /// A collection of that may take multiple service requests to iterate over. + public virtual Pageable GetHybridConnectionsSlot(CancellationToken cancellationToken = default) + { + HttpMessage FirstPageRequest(int? pageSizeHint) => _webSiteSlotWebAppsRestClient.CreateListHybridConnectionsSlotRequest(Id.SubscriptionId, Id.ResourceGroupName, Id.Parent.Name, Id.Name); + return GeneratorPageableHelpers.CreatePageable(FirstPageRequest, null, e => HybridConnectionData.DeserializeHybridConnectionData(e), _webSiteSlotWebAppsClientDiagnostics, Pipeline, "WebSiteSlotResource.GetHybridConnectionsSlot", "value", null, cancellationToken); + } + /// /// Description for Shows whether an app can be cloned to another resource group or subscription. /// diff --git a/sdk/websites/Azure.ResourceManager.AppService/src/autorest.md b/sdk/websites/Azure.ResourceManager.AppService/src/autorest.md index bbb6b83ae95f..18fe5253d7f0 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/src/autorest.md +++ b/sdk/websites/Azure.ResourceManager.AppService/src/autorest.md @@ -119,12 +119,12 @@ override-operation-name: ResourceHealthMetadata_ListByResourceGroup: GetAllResourceHealthMetadataData ListSiteIdentifiersAssignedToHostName: GetAllSiteIdentifierData WebApps_ListConfigurations: GetAllConfigurationData - WebApps_ListHybridConnections: GetAllHybridConnectionData + WebApps_ListHybridConnections: GetHybridConnections WebApps_ListPremierAddOns: GetAllPremierAddOnData WebApps_ListRelayServiceConnections: GetAllRelayServiceConnectionData WebApps_ListSiteBackups: GetAllSiteBackupData WebApps_ListConfigurationsSlot: GetAllConfigurationSlotData - WebApps_ListHybridConnectionsSlot: GetAllHybridConnectionSlotData + WebApps_ListHybridConnectionsSlot: GetHybridConnectionsSlot WebApps_ListPremierAddOnsSlot: GetAllPremierAddOnSlotData WebApps_ListRelayServiceConnectionsSlot: GetAllRelayServiceConnectionSlotData WebApps_ListSiteBackupsSlot: GetAllSiteBackupSlotData @@ -849,4 +849,12 @@ directive: "Aborted", "Running" ] + - from: WebApps.json + where: $.paths['/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/hybridConnectionRelays'].get + transform: > + $['responses']['200']['schema']['$ref'] = "./AppServicePlans.json#/definitions/HybridConnectionCollection"; + - from: WebApps.json + where: $.paths['/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{name}/slots/{slot}/hybridConnectionRelays'].get + transform: > + $['responses']['200']['schema']['$ref'] = "./AppServicePlans.json#/definitions/HybridConnectionCollection"; ``` diff --git a/sdk/websites/Azure.ResourceManager.AppService/tests/TestsCase/SiteOperationsTests.cs b/sdk/websites/Azure.ResourceManager.AppService/tests/TestsCase/SiteOperationsTests.cs index ffc8e1d44ad8..a8b82f1efe99 100644 --- a/sdk/websites/Azure.ResourceManager.AppService/tests/TestsCase/SiteOperationsTests.cs +++ b/sdk/websites/Azure.ResourceManager.AppService/tests/TestsCase/SiteOperationsTests.cs @@ -3,7 +3,10 @@ using System.Threading.Tasks; using Azure.Core.TestFramework; +using Azure.Identity; +using Azure.ResourceManager.AppService.Models; using Azure.ResourceManager.AppService.Tests.Helpers; +using Azure.ResourceManager.Resources; using NUnit.Framework; namespace Azure.ResourceManager.AppService.Tests.TestsCase @@ -42,5 +45,38 @@ public async Task Get() ResourceDataHelper.AssertSite(site1.Data, site2.Data); } + + //Manual operation needed to create website/hybridconnection resource, get it from existing one. + [TestCase] + [RecordedTest] + public async Task GetHybridConnections() + { + ResourceGroupCollection rgCollection = DefaultSubscription.GetResourceGroups(); + ResourceGroupResource rg = await rgCollection.GetAsync("Rg_Lwm"); + WebSiteCollection webSiteCollection = rg.GetWebSites(); + WebSiteResource webSiteResource = await webSiteCollection.GetAsync("sitelwm01"); + var hybridConnectionDataCollection = webSiteResource.GetHybridConnectionsAsync(); + int count = 0; + await foreach (HybridConnectionData item in hybridConnectionDataCollection) + { + count++; + } + Assert.AreEqual(2, count); + } + //Manual operation needed to create website/hybridconnection resource, get it from existing one. + [TestCase] + [RecordedTest] + public async Task GetHybridConnectionsSlot() + { + var wbSiteSlotID = WebSiteSlotResource.CreateResourceIdentifier(DefaultSubscription.Data.SubscriptionId, "Rg_Lwm", "sitelwm01", "slotsitelwm01"); + WebSiteSlotResource wsSlotResource = Client.GetWebSiteSlotResource(wbSiteSlotID); + var hybridConnectionDataCollection = wsSlotResource.GetHybridConnectionsSlotAsync(); + int count = 0; + await foreach (HybridConnectionData item in hybridConnectionDataCollection) + { + count++; + } + Assert.AreEqual(2, count); + } } }