Skip to content

Commit

Permalink
client, repeatability-first-sent should be set when sending request
Browse files Browse the repository at this point in the history
  • Loading branch information
weidongxu-microsoft committed Jun 26, 2024
1 parent d4844d6 commit 793be03
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ protected void generatePagedAsyncSinglePage(ClientMethod clientMethod, JavaType
addOptionalAndConstantVariables(function, clientMethod, restAPIMethod.getParameters(), settings);
applyParameterTransformations(function, clientMethod, settings);
convertClientTypesToWireTypes(function, clientMethod, restAPIMethod.getParameters(), clientMethod.getClientReference(), settings);
addSpecialHeadersToLocalVariables(function, clientMethod);
if (mergeContextParameter) {
function.line(String.format("context = %s.mergeContext(context);", clientMethod.getClientReference()));
}
Expand Down Expand Up @@ -206,7 +205,6 @@ protected void generateSimpleAsyncRestResponse(ClientMethod clientMethod, JavaTy
addOptionalAndConstantVariables(function, clientMethod, restAPIMethod.getParameters(), settings);
applyParameterTransformations(function, clientMethod, settings);
convertClientTypesToWireTypes(function, clientMethod, restAPIMethod.getParameters(), clientMethod.getClientReference(), settings);
addSpecialHeadersToLocalVariables(function, clientMethod);

String restAPIMethodArgumentList = String.join(", ", clientMethod.getProxyMethodArguments(settings));
String serviceMethodCall = String.format("service.%s(%s)", restAPIMethod.getName(), restAPIMethodArgumentList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,13 +739,13 @@ protected List<ProxyMethodParameter> getSpecialParameters(Operation operation) {

specialParameters.add(commonBuilderSetting.apply(new ProxyMethodParameter.Builder()
.name(MethodUtil.REPEATABILITY_REQUEST_ID_VARIABLE_NAME)
.parameterReference(MethodUtil.REPEATABILITY_REQUEST_ID_VARIABLE_NAME)
.parameterReference(MethodUtil.REPEATABILITY_REQUEST_ID_EXPRESSION)
.requestParameterName(MethodUtil.REPEATABILITY_REQUEST_ID_HEADER)
.description("Repeatability request ID header"))
.build());
specialParameters.add(commonBuilderSetting.apply(new ProxyMethodParameter.Builder()
.name(MethodUtil.REPEATABILITY_FIRST_SENT_VARIABLE_NAME)
.parameterReference(MethodUtil.REPEATABILITY_FIRST_SENT_VARIABLE_NAME)
.parameterReference(MethodUtil.REPEATABILITY_FIRST_SENT_EXPRESSION)
.requestParameterName(MethodUtil.REPEATABILITY_FIRST_SENT_HEADER)
.description("Repeatability first sent header as HTTP-date"))
.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,8 @@ private static boolean addSpecialHeadersToRequestOptions(JavaBlock function, Cli

// repeatability headers
if (repeatabilityRequestHeaders) {
addSpecialHeadersToLocalVariables(function, clientMethod);
requestOptionsSetHeaderIfAbsent(function, MethodUtil.REPEATABILITY_REQUEST_ID_VARIABLE_NAME, MethodUtil.REPEATABILITY_REQUEST_ID_HEADER);
requestOptionsSetHeaderIfAbsent(function, MethodUtil.REPEATABILITY_FIRST_SENT_VARIABLE_NAME, MethodUtil.REPEATABILITY_FIRST_SENT_HEADER);
requestOptionsSetHeaderIfAbsent(function, MethodUtil.REPEATABILITY_REQUEST_ID_EXPRESSION, MethodUtil.REPEATABILITY_REQUEST_ID_HEADER);
requestOptionsSetHeaderIfAbsent(function, MethodUtil.REPEATABILITY_FIRST_SENT_EXPRESSION, MethodUtil.REPEATABILITY_FIRST_SENT_HEADER);
}

// content-type headers for optional body parameter
Expand All @@ -523,23 +522,16 @@ private static boolean addSpecialHeadersToRequestOptions(JavaBlock function, Cli
return requestOptionsLocal;
}

private static void requestOptionsSetHeaderIfAbsent(JavaBlock function, String variableName, String headerName) {
private static void requestOptionsSetHeaderIfAbsent(JavaBlock function, String expression, String headerName) {
function.line("requestOptionsLocal.addRequestCallback(requestLocal -> {");
function.indent(() -> {
function.ifBlock(String.format("requestLocal.getHeaders().get(HttpHeaderName.fromString(\"%1$s\")) == null", headerName), ifBlock -> {
function.line(String.format("requestLocal.getHeaders().set(HttpHeaderName.fromString(\"%1$s\"), %2$s);", headerName, variableName));
function.line(String.format("requestLocal.getHeaders().set(HttpHeaderName.fromString(\"%1$s\"), %2$s);", headerName, expression));
});
});
function.line("});");
}

protected static void addSpecialHeadersToLocalVariables(JavaBlock function, ClientMethod clientMethod) {
if (MethodUtil.isMethodIncludeRepeatableRequestHeaders(clientMethod.getProxyMethod())) {
function.line(String.format("String %1$s = CoreUtils.randomUuid().toString();", MethodUtil.REPEATABILITY_REQUEST_ID_VARIABLE_NAME));
function.line(String.format("String %1$s = DateTimeRfc1123.toRfc1123String(OffsetDateTime.now());", MethodUtil.REPEATABILITY_FIRST_SENT_VARIABLE_NAME));
}
}

protected static void writeMethod(JavaType typeBlock, JavaVisibility visibility, String methodSignature, Consumer<JavaBlock> method) {
if (visibility == JavaVisibility.Public) {
typeBlock.publicMethod(methodSignature, method);
Expand Down Expand Up @@ -742,8 +734,6 @@ private void generatePagedSinglePage(ClientMethod clientMethod, JavaType typeBlo
boolean requestOptionsLocal = false;
if (settings.isDataPlaneClient()) {
requestOptionsLocal = addSpecialHeadersToRequestOptions(function, clientMethod);
} else {
addSpecialHeadersToLocalVariables(function, clientMethod);
}

String serviceMethodCall = checkAndReplaceParamNameCollision(clientMethod, restAPIMethod, requestOptionsLocal, settings);
Expand Down Expand Up @@ -1063,8 +1053,6 @@ protected void generatePlainSyncMethod(ClientMethod clientMethod, JavaType typeB
boolean requestOptionsLocal = false;
if (settings.isDataPlaneClient()) {
requestOptionsLocal = addSpecialHeadersToRequestOptions(function, clientMethod);
} else {
addSpecialHeadersToLocalVariables(function, clientMethod);
}

String serviceMethodCall = checkAndReplaceParamNameCollision(clientMethod, restAPIMethod.toSync(), requestOptionsLocal,
Expand Down Expand Up @@ -1163,8 +1151,6 @@ protected void generatePagedAsyncSinglePage(ClientMethod clientMethod, JavaType
boolean requestOptionsLocal = false;
if (settings.isDataPlaneClient()) {
requestOptionsLocal = addSpecialHeadersToRequestOptions(function, clientMethod);
} else {
addSpecialHeadersToLocalVariables(function, clientMethod);
}

String serviceMethodCall = checkAndReplaceParamNameCollision(clientMethod, restAPIMethod, requestOptionsLocal, settings);
Expand Down Expand Up @@ -1300,8 +1286,6 @@ protected void generateSimpleAsyncRestResponse(ClientMethod clientMethod, JavaTy
boolean requestOptionsLocal = false;
if (settings.isDataPlaneClient()) {
requestOptionsLocal = addSpecialHeadersToRequestOptions(function, clientMethod);
} else {
addSpecialHeadersToLocalVariables(function, clientMethod);
}

String serviceMethodCall = checkAndReplaceParamNameCollision(clientMethod, restAPIMethod, requestOptionsLocal, settings);
Expand Down
2 changes: 2 additions & 0 deletions javagen/src/main/java/com/azure/autorest/util/MethodUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public class MethodUtil {
public static final String REPEATABILITY_FIRST_SENT_HEADER = "repeatability-first-sent";
public static final String REPEATABILITY_REQUEST_ID_VARIABLE_NAME = CodeNamer.toCamelCase(REPEATABILITY_REQUEST_ID_HEADER);
public static final String REPEATABILITY_FIRST_SENT_VARIABLE_NAME = CodeNamer.toCamelCase(REPEATABILITY_FIRST_SENT_HEADER);
public static final String REPEATABILITY_REQUEST_ID_EXPRESSION = "CoreUtils.randomUuid().toString()";
public static final String REPEATABILITY_FIRST_SENT_EXPRESSION = "DateTimeRfc1123.toRfc1123String(OffsetDateTime.now())";

private static final Set<HttpMethod> REPEATABILITY_REQUEST_HTTP_METHODS
= EnumSet.of(HttpMethod.PUT, HttpMethod.PATCH, HttpMethod.DELETE, HttpMethod.POST);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ public Mono<Response<BinaryData>> paramRepeatabilityRequestWithResponseAsync(Req
requestOptionsLocal.addRequestCallback(requestLocal -> {
if (requestLocal.getHeaders().get(HttpHeaderName.fromString("repeatability-first-sent")) == null) {
requestLocal.getHeaders()
.set(HttpHeaderName.fromString("repeatability-first-sent"), repeatabilityFirstSent);
.set(HttpHeaderName.fromString("repeatability-first-sent"), DateTimeRfc1123.toRfc1123String(OffsetDateTime.now()));
}
});
return FluxUtil.withContext(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.azure.core.exception.HttpResponseException;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpHeader;
import com.azure.core.http.HttpHeaderName;
import com.azure.core.http.HttpHeaders;
import com.azure.core.http.HttpPipelineCallContext;
import com.azure.core.http.HttpPipelineNextPolicy;
Expand All @@ -15,6 +16,8 @@
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.HttpPipelinePolicy;
import com.azure.core.http.rest.RequestOptions;
import com.azure.core.http.rest.Response;
import com.azure.core.util.BinaryData;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.DateTimeRfc1123;
import fixtures.MockHttpResponse;
Expand All @@ -23,17 +26,22 @@
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class SpecialHeaderTests {

private static SpecialHeaderClient client;

private static SpecialHeaderAsyncClient asyncClient;

private static class ValidationPolicy implements HttpPipelinePolicy {
private String repeatabilityRequestId;
private String repeatabilityFirstSent;
Expand Down Expand Up @@ -97,25 +105,33 @@ public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineN
public static void setup() {
HttpClient mockHttpClient = request -> Mono.just(new MockHttpResponse(request, 500));

HttpLogOptions httpLogOptions = new HttpLogOptions()
.setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
.setRequestLogger((logger, loggingOptions) -> {
final HttpRequest request = loggingOptions.getHttpRequest();
StringBuilder sb = new StringBuilder();
for (HttpHeader header : request.getHeaders()) {
String headerName = header.getName();
sb.append(headerName).append(":");
sb.append(header.getValue());
sb.append("; ");
}
logger.info(sb.toString());
return Mono.empty();
});

client = new SpecialHeaderClientBuilder()
// .host("https://httpbin.org/")
.httpClient(mockHttpClient)
.addPolicy(VALIDATION_POLICY)
.httpLogOptions(new HttpLogOptions()
.setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS)
.setRequestLogger((logger, loggingOptions) -> {
final HttpRequest request = loggingOptions.getHttpRequest();
StringBuilder sb = new StringBuilder();
for (HttpHeader header : request.getHeaders()) {
String headerName = header.getName();
sb.append(headerName).append(":");
sb.append(header.getValue());
sb.append("; ");
}
logger.info(sb.toString());
return Mono.empty();
}))
.httpLogOptions(httpLogOptions)
.buildClient();

asyncClient = new SpecialHeaderClientBuilder()
.httpClient(mockHttpClient)
.addPolicy(VALIDATION_POLICY)
.httpLogOptions(httpLogOptions)
.buildAsyncClient();
}

@Test
Expand All @@ -142,17 +158,39 @@ public void testRepeatabilityRequestPut() {
public void testRepeatabilityRequestUserProvidedHeader() {
VALIDATION_POLICY.clear();

final String id = UUID.randomUUID().toString();
final String id = CoreUtils.randomUuid().toString();
final String date = DateTimeRfc1123.toRfc1123String(OffsetDateTime.now().minusMinutes(1));

Assertions.assertThrows(HttpResponseException.class,
() -> client.paramRepeatabilityRequestWithResponse(new RequestOptions()
.setHeader("Repeatability-Request-ID", id)
.setHeader("Repeatability-First-Sent", date)));
.setHeader(HttpHeaderName.fromString("Repeatability-Request-ID"), id)
.setHeader(HttpHeaderName.fromString("Repeatability-First-Sent"), date)));

Assertions.assertTrue(VALIDATION_POLICY.isValidationPass());

Assertions.assertEquals(id, VALIDATION_POLICY.repeatabilityRequestId);
Assertions.assertEquals(date, VALIDATION_POLICY.repeatabilityFirstSent);
}

@Test
public void testRepeatabilityRequestAsyncDate() throws InterruptedException {
// make the Mono but do not subscribe
Instant instantAtMono = OffsetDateTime.now().toInstant();
Mono<Response<BinaryData>> responseMono = asyncClient.paramRepeatabilityRequestWithResponse(null);

// wait for 3 sec
TimeUnit.SECONDS.sleep(3);

// subscribe - send request
Instant instantAtRequest = OffsetDateTime.now().toInstant();
Assertions.assertThrows(HttpResponseException.class, responseMono::block);

Assertions.assertTrue(VALIDATION_POLICY.isValidationPass());
Instant instantOfRepeatabilityFirstSent = new DateTimeRfc1123(VALIDATION_POLICY.repeatabilityFirstSent).getDateTime().toInstant();

// instantOfRepeatabilityFirstSent should be near instantAtRequest, not instantAtMono
Duration duration = Duration.between(instantAtMono, instantOfRepeatabilityFirstSent);
// check for 2 sec, as the precision of "repeatability-first-sent" is 1 sec
Assertions.assertTrue(duration.compareTo(Duration.ofSeconds(2)) > 0);
}
}

0 comments on commit 793be03

Please sign in to comment.