diff --git a/eng/versioning/version_client.txt b/eng/versioning/version_client.txt
index bb19e5b0c9e8..28bb87f95ed4 100644
--- a/eng/versioning/version_client.txt
+++ b/eng/versioning/version_client.txt
@@ -80,6 +80,7 @@ com.azure.resourcemanager:azure-resourcemanager-redis;2.0.0-beta.3;2.0.0-beta.4
com.azure.resourcemanager:azure-resourcemanager-samples;2.0.0-beta.3;2.0.0-beta.4
com.azure.resourcemanager:azure-resourcemanager-sql;2.0.0-beta.3;2.0.0-beta.4
com.azure.resourcemanager:azure-resourcemanager-storage;2.0.0-beta.3;2.0.0-beta.4
+com.azure.resourcemanager:azure-resourcemanager-test;2.0.0-beta.4;2.0.0-beta.4
com.microsoft.azure:azure-active-directory-b2c-spring-boot-starter;2.3.3;2.4.0-beta.1
com.microsoft.azure:azure-active-directory-spring-boot-starter;2.3.3;2.4.0-beta.1
com.microsoft.azure:azure-cosmosdb-spring-boot-starter;2.3.3;2.4.0-beta.1
diff --git a/sdk/resourcemanager/azure-resourcemanager-test/CHANGELOG.md b/sdk/resourcemanager/azure-resourcemanager-test/CHANGELOG.md
new file mode 100644
index 000000000000..003c434ede62
--- /dev/null
+++ b/sdk/resourcemanager/azure-resourcemanager-test/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Release History
+
+## 2.0.0-beta.4 (Unreleased)
+
+- TODO
diff --git a/sdk/resourcemanager/azure-resourcemanager-test/README.md b/sdk/resourcemanager/azure-resourcemanager-test/README.md
new file mode 100644
index 000000000000..cfdf9153d622
--- /dev/null
+++ b/sdk/resourcemanager/azure-resourcemanager-test/README.md
@@ -0,0 +1,42 @@
+# Azure Resource Manager Test shared library for Java
+
+Azure Resource Manager test library for Java
+
+For documentation on how to use this package, please see [Azure Management Libraries for Java](https://aka.ms/azure-sdk-java-mgmt).
+
+## Getting started
+
+### Prerequisites
+
+- Java Development Kit (JDK) with version 8 or above
+
+### Adding the package to your product
+
+[//]: # ({x-version-update-start;com.azure.resourcemanager:azure-resourcemanager-test;current})
+```xml
+
+ com.azure.resourcemanager
+ azure-resourcemanager-test
+ 2.0.0-beta.4
+
+```
+[//]: # ({x-version-update-end})
+
+## Key concepts
+
+## Examples
+
+## Troubleshooting
+
+## Next steps
+
+## Contributing
+
+If you would like to become an active contributor to this project please follow the instructions provided in [Microsoft
+Azure Projects Contribution Guidelines](http://azure.github.io/guidelines.html).
+
+1. Fork it
+1. Create your feature branch (`git checkout -b my-new-feature`)
+1. Commit your changes (`git commit -am 'Add some feature'`)
+1. Push to the branch (`git push origin my-new-feature`)
+1. Create new Pull Request
diff --git a/sdk/resourcemanager/azure-resourcemanager-test/pom.xml b/sdk/resourcemanager/azure-resourcemanager-test/pom.xml
new file mode 100644
index 000000000000..067124d963fe
--- /dev/null
+++ b/sdk/resourcemanager/azure-resourcemanager-test/pom.xml
@@ -0,0 +1,124 @@
+
+
+ 4.0.0
+
+ com.azure
+ azure-client-sdk-parent
+ 1.7.0
+ ../../parents/azure-client-sdk-parent
+
+
+ com.azure.resourcemanager
+ azure-resourcemanager-test
+ 2.0.0-beta.4
+ jar
+
+ Microsoft Azure Resource Manager Test Library
+ This package contains test types for Azure Resource Manager SDK. For documentation on how to use this package, please see https://aka.ms/azure-sdk-java-mgmt
+ https://github.com/Azure/azure-sdk-for-java
+
+
+
+ The MIT License (MIT)
+ http://opensource.org/licenses/MIT
+ repo
+
+
+
+
+ https://github.com/Azure/azure-sdk-for-java
+ scm:git:git@github.com:Azure/azure-sdk-for-java.git
+ HEAD
+
+
+
+
+ 0.10
+ 0.10
+
+
+
+
+ microsoft
+ Microsoft
+
+
+
+
+
+ com.azure
+ azure-core-test
+ 1.4.0
+
+
+ com.azure
+ azure-core-management
+ 1.0.0-beta.3
+
+
+ com.azure
+ azure-identity
+ 1.1.0
+
+
+ com.azure
+ azure-core-http-netty
+ 1.5.4
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.1.2
+
+
+
+ test-jar
+
+
+
+
+
+
+ true
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+ 3.0.0-M3
+
+
+
+
+ com.github.spotbugs:spotbugs-annotations:[4.0.2]
+
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.5
+
+
+ com/azure/resourcemanager/**/fluent/**/*
+ com/azure/resourcemanager/**/models/**/*
+
+
+
+
+
+
+
diff --git a/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/ResourceManagerTestBase.java b/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/ResourceManagerTestBase.java
new file mode 100644
index 000000000000..852ef36a4772
--- /dev/null
+++ b/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/ResourceManagerTestBase.java
@@ -0,0 +1,286 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+package com.azure.resourcemanager.test;
+
+import com.azure.core.credential.TokenCredential;
+import com.azure.core.http.HttpClient;
+import com.azure.core.http.HttpPipeline;
+import com.azure.core.http.ProxyOptions;
+import com.azure.core.http.netty.NettyAsyncHttpClientBuilder;
+import com.azure.core.http.policy.CookiePolicy;
+import com.azure.core.http.policy.HttpLogDetailLevel;
+import com.azure.core.http.policy.HttpLogOptions;
+import com.azure.core.http.policy.HttpPipelinePolicy;
+import com.azure.core.http.policy.TimeoutPolicy;
+import com.azure.core.management.AzureEnvironment;
+import com.azure.core.management.profile.AzureProfile;
+import com.azure.core.test.TestBase;
+import com.azure.core.test.TestMode;
+import com.azure.core.test.utils.ResourceNamer;
+import com.azure.core.util.Configuration;
+import com.azure.core.util.logging.ClientLogger;
+import com.azure.identity.ClientSecretCredentialBuilder;
+import com.azure.resourcemanager.test.policy.TextReplacementPolicy;
+import com.azure.resourcemanager.test.utils.AuthFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Test base for resource manager SDK.
+ */
+public abstract class ResourceManagerTestBase extends TestBase {
+ private static final String ZERO_SUBSCRIPTION = "00000000-0000-0000-0000-000000000000";
+ private static final String ZERO_TENANT = "00000000-0000-0000-0000-000000000000";
+ private static final String PLAYBACK_URI_BASE = "http://localhost:";
+ private static final String AZURE_AUTH_LOCATION = "AZURE_AUTH_LOCATION";
+ private static final String HTTPS_PROXY_HOST = "https.proxyHost";
+ private static final String HTTPS_PROXY_PORT = "https.proxyPort";
+ private static final String HTTP_PROXY_HOST = "http.proxyHost";
+ private static final String HTTP_PROXY_PORT = "http.proxyPort";
+ private static final String USE_SYSTEM_PROXY = "java.net.useSystemProxies";
+ private static final String VALUE_TRUE = "true";
+ private static final String PLAYBACK_URI = PLAYBACK_URI_BASE + "1234";
+ private static final AzureProfile PLAYBACK_PROFILE = new AzureProfile(
+ ZERO_TENANT,
+ ZERO_SUBSCRIPTION,
+ new AzureEnvironment(
+ new HashMap() {
+ {
+ put("managementEndpointUrl", PLAYBACK_URI);
+ put("resourceManagerEndpointUrl", PLAYBACK_URI);
+ put("sqlManagementEndpointUrl", PLAYBACK_URI);
+ put("galleryEndpointUrl", PLAYBACK_URI);
+ put("activeDirectoryEndpointUrl", PLAYBACK_URI);
+ put("activeDirectoryResourceId", PLAYBACK_URI);
+ put("activeDirectoryGraphResourceId", PLAYBACK_URI);
+ }}));
+ private static final OutputStream EMPTY_OUTPUT_STREAM = new OutputStream() {
+ @Override
+ public void write(int b) {
+ }
+ };
+
+ private final ClientLogger logger = new ClientLogger(ResourceManagerTestBase.class);
+ private AzureProfile testProfile;
+ private AuthFile testAuthFile;
+ private boolean isSkipInPlayback;
+
+ protected String generateRandomResourceName(String prefix, int maxLen) {
+ return testResourceNamer.randomName(prefix, maxLen);
+ }
+
+ protected String generateRandomUuid() {
+ return testResourceNamer.randomUuid();
+ }
+
+ /**
+ * @return random password
+ */
+ public static String password() {
+ // do not record
+ String password = new ResourceNamer("").randomName("Pa5$", 12);
+ new ClientLogger(ResourceManagerTestBase.class).info("Password: %s%n", password);
+ return password;
+ }
+
+ protected TokenCredential credentialFromFile() {
+ return testAuthFile.getCredential();
+ }
+
+ protected String clientIdFromFile() {
+ return testAuthFile.getClientId();
+ }
+
+ protected AzureProfile profile() {
+ return testProfile;
+ }
+
+ protected boolean isPlaybackMode() {
+ return getTestMode() == TestMode.PLAYBACK;
+ }
+
+ protected boolean skipInPlayback() {
+ if (isPlaybackMode()) {
+ isSkipInPlayback = true;
+ }
+ return isSkipInPlayback;
+ }
+
+ @Override
+ protected void beforeTest() {
+ TokenCredential credential;
+ HttpPipeline httpPipeline;
+ Map textReplacementRules = new HashMap<>();
+ String logLevel = Configuration.getGlobalConfiguration().get(Configuration.PROPERTY_AZURE_LOG_LEVEL);
+ HttpLogDetailLevel httpLogDetailLevel;
+
+ try {
+ httpLogDetailLevel = HttpLogDetailLevel.valueOf(logLevel);
+ } catch (Exception e) {
+ if (isPlaybackMode()) {
+ httpLogDetailLevel = HttpLogDetailLevel.NONE;
+ logger.error("Environment variable '{}' has not been set yet. Using 'NONE' for PLAYBACK.", new Object[]{"AZURE_LOG_LEVEL"});
+ } else {
+ httpLogDetailLevel = HttpLogDetailLevel.BODY_AND_HEADERS;
+ logger.error("Environment variable '{}' has not been set yet. Using 'BODY_AND_HEADERS' for RECORD/LIVE.", new Object[]{"AZURE_LOG_LEVEL"});
+ }
+ }
+
+
+ if (httpLogDetailLevel == HttpLogDetailLevel.NONE) {
+ try {
+ System.setOut(new PrintStream(EMPTY_OUTPUT_STREAM, false, Charset.defaultCharset().name()));
+ System.setErr(new PrintStream(EMPTY_OUTPUT_STREAM, false, Charset.defaultCharset().name()));
+ } catch (UnsupportedEncodingException e) {
+ }
+ }
+
+ if (isPlaybackMode()) {
+ if (interceptorManager.getRecordedData() == null) {
+ skipInPlayback();
+ return;
+ }
+
+ testProfile = PLAYBACK_PROFILE;
+ List policies = new ArrayList<>();
+ policies.add(new TextReplacementPolicy(interceptorManager.getRecordedData(), textReplacementRules));
+ policies.add(new CookiePolicy());
+ httpPipeline = buildHttpPipeline(
+ null,
+ testProfile,
+ new HttpLogOptions().setLogLevel(httpLogDetailLevel),
+ policies,
+ interceptorManager.getPlaybackClient());
+ textReplacementRules.put(PLAYBACK_URI_BASE + "1234", PLAYBACK_URI);
+ addTextReplacementRules(textReplacementRules);
+ } else {
+ if (System.getenv(AZURE_AUTH_LOCATION) != null) { // Record mode
+ final File credFile = new File(System.getenv(AZURE_AUTH_LOCATION));
+ try {
+ testAuthFile = AuthFile.parse(credFile);
+ } catch (IOException e) {
+ throw logger.logExceptionAsError(new RuntimeException("Cannot parse auth file. Please check file format."));
+ }
+ credential = testAuthFile.getCredential();
+ testProfile = new AzureProfile(testAuthFile.getTenantId(), testAuthFile.getSubscriptionId(), testAuthFile.getEnvironment());
+ } else {
+ Configuration configuration = Configuration.getGlobalConfiguration();
+ String clientId = configuration.get(Configuration.PROPERTY_AZURE_CLIENT_ID);
+ String tenantId = configuration.get(Configuration.PROPERTY_AZURE_TENANT_ID);
+ String clientSecret = configuration.get(Configuration.PROPERTY_AZURE_CLIENT_SECRET);
+ String subscriptionId = configuration.get(Configuration.PROPERTY_AZURE_SUBSCRIPTION_ID);
+ if (clientId == null || tenantId == null || clientSecret == null || subscriptionId == null) {
+ throw logger.logExceptionAsError(
+ new IllegalArgumentException("When running tests in record mode either 'AZURE_AUTH_LOCATION' or 'AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET and AZURE_SUBSCRIPTION_ID' needs to be set"));
+ }
+
+ credential = new ClientSecretCredentialBuilder()
+ .tenantId(tenantId)
+ .clientId(clientId)
+ .clientSecret(clientSecret)
+ .authorityHost(AzureEnvironment.AZURE.getActiveDirectoryEndpoint())
+ .build();
+ testProfile = new AzureProfile(tenantId, subscriptionId, AzureEnvironment.AZURE);
+ }
+
+ List policies = new ArrayList<>();
+ policies.add(new TimeoutPolicy(Duration.ofMinutes(1)));
+ policies.add(new CookiePolicy());
+ if (!interceptorManager.isLiveMode()) {
+ policies.add(new TextReplacementPolicy(interceptorManager.getRecordedData(), textReplacementRules));
+ }
+ httpPipeline = buildHttpPipeline(
+ credential,
+ testProfile,
+ new HttpLogOptions().setLogLevel(httpLogDetailLevel),
+ policies,
+ generateHttpClientWithProxy(null));
+
+ textReplacementRules.put(testProfile.getSubscriptionId(), ZERO_SUBSCRIPTION);
+ textReplacementRules.put(testProfile.getTenantId(), ZERO_TENANT);
+ textReplacementRules.put(AzureEnvironment.AZURE.getResourceManagerEndpoint(), PLAYBACK_URI + "/");
+ textReplacementRules.put(AzureEnvironment.AZURE.getGraphEndpoint(), PLAYBACK_URI + "/");
+ addTextReplacementRules(textReplacementRules);
+ }
+ initializeClients(httpPipeline, testProfile);
+ }
+
+ private HttpClient generateHttpClientWithProxy(ProxyOptions proxyOptions) {
+ NettyAsyncHttpClientBuilder clientBuilder = new NettyAsyncHttpClientBuilder();
+ if (proxyOptions != null) {
+ clientBuilder.proxy(proxyOptions);
+ } else {
+ try {
+ System.setProperty(USE_SYSTEM_PROXY, VALUE_TRUE);
+ List proxies = ProxySelector.getDefault().select(new URI(AzureEnvironment.AZURE.getResourceManagerEndpoint()));
+ if (!proxies.isEmpty()) {
+ for (Proxy proxy : proxies) {
+ if (proxy.address() instanceof InetSocketAddress) {
+ String host = ((InetSocketAddress) proxy.address()).getHostName();
+ int port = ((InetSocketAddress) proxy.address()).getPort();
+ switch (proxy.type()) {
+ case HTTP:
+ return clientBuilder.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress(host, port))).build();
+ case SOCKS:
+ return clientBuilder.proxy(new ProxyOptions(ProxyOptions.Type.SOCKS5, new InetSocketAddress(host, port))).build();
+ default:
+ }
+ }
+ }
+ }
+ String host = null;
+ int port = 0;
+ if (System.getProperty(HTTPS_PROXY_HOST) != null && System.getProperty(HTTPS_PROXY_PORT) != null) {
+ host = System.getProperty(HTTPS_PROXY_HOST);
+ port = Integer.parseInt(System.getProperty(HTTPS_PROXY_PORT));
+ } else if (System.getProperty(HTTP_PROXY_HOST) != null && System.getProperty(HTTP_PROXY_PORT) != null) {
+ host = System.getProperty(HTTP_PROXY_HOST);
+ port = Integer.parseInt(System.getProperty(HTTP_PROXY_PORT));
+ }
+ if (host != null) {
+ clientBuilder.proxy(new ProxyOptions(ProxyOptions.Type.HTTP, new InetSocketAddress(host, port)));
+ }
+ } catch (URISyntaxException e) { }
+ }
+ return clientBuilder.build();
+ }
+
+ @Override
+ protected void afterTest() {
+ if (!isSkipInPlayback) {
+ cleanUpResources();
+ }
+ }
+
+ private void addTextReplacementRules(Map rules) {
+ for (Map.Entry entry : rules.entrySet()) {
+ interceptorManager.addTextReplacementRule(entry.getKey(), entry.getValue());
+ }
+ }
+
+ protected abstract HttpPipeline buildHttpPipeline(
+ TokenCredential credential,
+ AzureProfile profile,
+ HttpLogOptions httpLogOptions,
+ List policies,
+ HttpClient httpClient);
+
+ protected abstract void initializeClients(HttpPipeline httpPipeline, AzureProfile profile);
+
+ protected abstract void cleanUpResources();
+}
diff --git a/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/policy/TextReplacementPolicy.java b/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/policy/TextReplacementPolicy.java
new file mode 100644
index 000000000000..e964245a6484
--- /dev/null
+++ b/sdk/resourcemanager/azure-resourcemanager-test/src/main/java/com/azure/resourcemanager/test/policy/TextReplacementPolicy.java
@@ -0,0 +1,215 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+package com.azure.resourcemanager.test.policy;
+
+import com.azure.core.http.ContentType;
+import com.azure.core.http.HttpHeader;
+import com.azure.core.http.HttpHeaders;
+import com.azure.core.http.HttpPipelineCallContext;
+import com.azure.core.http.HttpPipelineNextPolicy;
+import com.azure.core.http.HttpResponse;
+import com.azure.core.http.policy.HttpPipelinePolicy;
+import com.azure.core.test.models.NetworkCallError;
+import com.azure.core.test.models.NetworkCallRecord;
+import com.azure.core.test.models.RecordedData;
+import com.azure.core.test.models.RecordingRedactor;
+import com.azure.core.util.UrlBuilder;
+import com.azure.core.util.logging.ClientLogger;
+import reactor.core.Exceptions;
+import reactor.core.publisher.Mono;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * TextReplacementPolicy to support session text replacement rules for tests.
+ */
+public class TextReplacementPolicy implements HttpPipelinePolicy {
+ private static final int DEFAULT_BUFFER_LENGTH = 1024;
+ private static final String CONTENT_TYPE = "Content-Type";
+ private static final String CONTENT_ENCODING = "Content-Encoding";
+ private static final String CONTENT_LENGTH = "Content-Length";
+ private static final String X_MS_CLIENT_REQUEST_ID = "x-ms-client-request-id";
+ private static final String X_MS_ENCRYPTION_KEY_SHA256 = "x-ms-encryption-key-sha256";
+ private static final String X_MS_VERSION = "x-ms-version";
+ private static final String USER_AGENT = "User-Agent";
+ private static final String STATUS_CODE = "StatusCode";
+ private static final String BODY = "Body";
+ private static final String SIG = "sig";
+
+ private final ClientLogger logger = new ClientLogger(TextReplacementPolicy.class);
+ private final RecordedData recordedData;
+ private final Map textReplacementRules;
+
+ /**
+ * Creates a policy that records network calls into {@code recordedData} with replacement rules.
+ *
+ * @param recordedData The record to persist network calls into.
+ * @param textReplacementRules The replacement rules
+ */
+ public TextReplacementPolicy(RecordedData recordedData, Map textReplacementRules) {
+ //Objects.requireNonNull(recordedData, "'recordedData' cannot be null.");
+ Objects.requireNonNull(textReplacementRules, "'textReplacementRules' cannot be null.");
+ this.recordedData = recordedData;
+ this.textReplacementRules = textReplacementRules;
+ }
+
+ @Override
+ public Mono process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
+ final NetworkCallRecord networkCallRecord = new NetworkCallRecord();
+ Map headers = new HashMap<>();
+
+ captureRequestHeaders(context.getHttpRequest().getHeaders(), headers,
+ X_MS_CLIENT_REQUEST_ID,
+ CONTENT_TYPE,
+ X_MS_VERSION,
+ USER_AGENT);
+
+ networkCallRecord.setHeaders(headers);
+ networkCallRecord.setMethod(context.getHttpRequest().getHttpMethod().toString());
+
+ // Remove sensitive information such as SAS token signatures from the recording.
+ UrlBuilder urlBuilder = UrlBuilder.parse(context.getHttpRequest().getUrl());
+ if (urlBuilder.getQuery().containsKey(SIG)) {
+ urlBuilder.setQueryParameter(SIG, "REDACTED");
+ }
+ networkCallRecord.setUri(applyReplacementRule(urlBuilder.toString().replaceAll("\\?$", "")));
+
+ return next.process()
+ .doOnError(throwable -> {
+ networkCallRecord.setException(new NetworkCallError(throwable));
+ recordedData.addNetworkCall(networkCallRecord);
+ throw logger.logExceptionAsWarning(Exceptions.propagate(throwable));
+ }).flatMap(httpResponse -> {
+ final HttpResponse bufferedResponse = httpResponse.buffer();
+
+ return extractResponseData(bufferedResponse).map(responseData -> {
+ networkCallRecord.setResponse(responseData);
+ String body = responseData.get(BODY);
+
+ // Remove pre-added header if this is a waiting or redirection
+ if (body != null && body.contains("InProgress")
+ || Integer.parseInt(responseData.get(STATUS_CODE)) == HttpURLConnection.HTTP_MOVED_TEMP) {
+ logger.info("Waiting for a response or redirection.");
+ } else {
+ recordedData.addNetworkCall(networkCallRecord);
+ }
+
+ return bufferedResponse;
+ });
+ });
+ }
+
+ private String applyReplacementRule(String text) {
+ for (Map.Entry rule : textReplacementRules.entrySet()) {
+ if (rule.getValue() != null) {
+ text = text.replaceAll(rule.getKey(), rule.getValue());
+ }
+ }
+ return text;
+ }
+
+ private void captureRequestHeaders(HttpHeaders requestHeaders, Map captureHeaders,
+ String... headerNames) {
+ for (String headerName : headerNames) {
+ if (requestHeaders.getValue(headerName) != null) {
+ captureHeaders.put(headerName, requestHeaders.getValue(headerName));
+ }
+ }
+ }
+
+ private Mono