Skip to content

Commit

Permalink
Schema Registry: Update support for 415 error code. Regenerate test p…
Browse files Browse the repository at this point in the history
…layback files. (#25342)

* Fix user agent string.

* Adding new record playback files.

* Adding regenerated classes.

* Adding additional tests.

* Adding content headers depending on SchemaFormat type.

* Adding CHANGELOG.md

* Update sdk/schemaregistry/azure-data-schemaregistry/CHANGELOG.md

Co-authored-by: Liudmila Molkova <[email protected]>
  • Loading branch information
conniey and lmolkova authored Nov 11, 2021
1 parent d35017e commit 252afe9
Show file tree
Hide file tree
Showing 24 changed files with 423 additions and 191 deletions.
3 changes: 3 additions & 0 deletions sdk/schemaregistry/azure-data-schemaregistry/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@

### Bugs Fixed

- Added correct User Agent string for client.

### Other Changes

- Regenerated REST API based off 2021-10 swagger.
- An `HttpResponseException` with status code 415 is returned if an invalid `SchemaFormat` is passed for `registerSchema` or `getSchemaById` calls.

## 1.0.0-beta.6 (2021-10-08)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ Mono<Response<SchemaProperties>> registerSchemaWithResponse(String groupName, St
logger.verbose("Registering schema. Group: '{}', name: '{}', serialization type: '{}', payload: '{}'",
groupName, name, format, schemaDefinition);

return restService.getSchemas().registerWithResponseAsync(groupName, name, schemaDefinition, context)
final String contentType = getContentType(format);

return restService.getSchemas().registerWithResponseAsync(groupName, name, schemaDefinition, contentType, context)
.map(response -> {
final SchemasRegisterHeaders deserializedHeaders = response.getDeserializedHeaders();
final SchemaProperties registered = new SchemaProperties(deserializedHeaders.getSchemaId(), format);
Expand Down Expand Up @@ -262,8 +264,10 @@ Mono<Response<SchemaProperties>> getSchemaPropertiesWithResponse(String groupNam
context = Context.NONE;
}

final String contentType = getContentType(format);

return restService.getSchemas()
.queryIdByContentWithResponseAsync(groupName, name, schemaDefinition, context)
.queryIdByContentWithResponseAsync(groupName, name, schemaDefinition, contentType, context)
.onErrorMap(ErrorException.class, SchemaRegistryAsyncClient::remapError)
.map(response -> {
final SchemasQueryIdByContentHeaders deserializedHeaders = response.getDeserializedHeaders();
Expand Down Expand Up @@ -296,4 +300,8 @@ private static Throwable remapError(ErrorException error) {

return error;
}

private static String getContentType(SchemaFormat schemaFormat) {
return "application/json; serialization=" + schemaFormat;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class SchemaRegistryClientBuilder {
private final ClientLogger logger = new ClientLogger(SchemaRegistryClientBuilder.class);

private static final String DEFAULT_SCOPE = "https://eventhubs.azure.net/.default";
private static final String CLIENT_PROPERTIES = "azure-data-schemaregistry-client.properties";
private static final String CLIENT_PROPERTIES = "azure-data-schemaregistry.properties";
private static final String NAME = "name";
private static final String VERSION = "version";
private static final RetryPolicy DEFAULT_RETRY_POLICY = new RetryPolicy("retry-after-ms", ChronoUnit.MILLIS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public final class SchemasImpl {
@ServiceInterface(name = "AzureSchemaRegistryS")
private interface SchemasService {
@Get("/$schemaGroups/$schemas/{id}")
@ExpectedResponses({200, 200})
@ExpectedResponses({200})
@UnexpectedResponseExceptionType(ErrorException.class)
Mono<SchemasGetByIdResponse> getById(
@HostParam("endpoint") String endpoint,
Expand All @@ -75,26 +75,34 @@ Mono<Response<SchemaVersions>> getVersions(
Context context);

@Post("/$schemaGroups/{groupName}/schemas/{schemaName}:get-id")
@ExpectedResponses({204, 415})
@ExpectedResponses({204})
@UnexpectedResponseExceptionType(
value = ErrorException.class,
code = {415})
@UnexpectedResponseExceptionType(ErrorException.class)
Mono<SchemasQueryIdByContentResponse> queryIdByContent(
@HostParam("endpoint") String endpoint,
@PathParam("groupName") String groupName,
@PathParam("schemaName") String schemaName,
@QueryParam("api-version") String apiVersion,
@BodyParam("application/json; serialization=avro") String schemaContent,
@BodyParam("application/json; serialization=Avro") String schemaContent,
@HeaderParam("Content-Type") String contentType,
@HeaderParam("Accept") String accept,
Context context);

@Put("/$schemaGroups/{groupName}/schemas/{schemaName}")
@ExpectedResponses({204, 415})
@ExpectedResponses({204})
@UnexpectedResponseExceptionType(
value = ErrorException.class,
code = {415})
@UnexpectedResponseExceptionType(ErrorException.class)
Mono<SchemasRegisterResponse> register(
@HostParam("endpoint") String endpoint,
@PathParam("groupName") String groupName,
@PathParam("schemaName") String schemaName,
@QueryParam("api-version") String apiVersion,
@BodyParam("application/json; serialization=avro") String schemaContent,
@BodyParam("application/json; serialization=Avro") String schemaContent,
@HeaderParam("Content-Type") String contentType,
@HeaderParam("Accept") String accept,
Context context);
}
Expand All @@ -112,7 +120,7 @@ Mono<SchemasRegisterResponse> register(
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<SchemasGetByIdResponse> getByIdWithResponseAsync(String id, Context context) {
final String accept = "text/plain, application/json, application/json;serialization=avro";
final String accept = "application/json; serialization=avro";
return service.getById(this.client.getEndpoint(), id, this.client.getApiVersion(), accept, context);
}

Expand Down Expand Up @@ -144,23 +152,26 @@ public Mono<Response<SchemaVersions>> getVersionsWithResponseAsync(
* serialization type specified in the request.
* @param schemaName Name of requested schema.
* @param schemaContent String representation (UTF-8) of the registered schema.
* @param contentType The contentType parameter.
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ErrorException thrown if the request is rejected by server.
* @throws ErrorException thrown if the request is rejected by server on status code 415.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the ID referencing an existing schema within the specified schema group, as matched by schema content
* comparison.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<SchemasQueryIdByContentResponse> queryIdByContentWithResponseAsync(
String groupName, String schemaName, String schemaContent, Context context) {
String groupName, String schemaName, String schemaContent, String contentType, Context context) {
final String accept = "application/json";
return service.queryIdByContent(
this.client.getEndpoint(),
groupName,
schemaName,
this.client.getApiVersion(),
schemaContent,
contentType,
accept,
context);
}
Expand All @@ -176,19 +187,21 @@ public Mono<SchemasQueryIdByContentResponse> queryIdByContentWithResponseAsync(
* @param context The context to associate with this operation.
* @throws IllegalArgumentException thrown if parameters fail the validation.
* @throws ErrorException thrown if the request is rejected by server.
* @throws ErrorException thrown if the request is rejected by server on status code 415.
* @throws RuntimeException all other wrapped checked exceptions if the request fails to be sent.
* @return the completion.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<SchemasRegisterResponse> registerWithResponseAsync(
String groupName, String schemaName, String schemaContent, Context context) {
String groupName, String schemaName, String schemaContent, String contentType, Context context) {
final String accept = "application/json";
return service.register(
this.client.getEndpoint(),
groupName,
schemaName,
this.client.getApiVersion(),
schemaContent,
contentType,
accept,
context);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.data.schemaregistry.implementation.models;

import com.azure.core.annotation.Fluent;
import com.fasterxml.jackson.annotation.JsonProperty;

/** Object received from the registry containing schema identifiers. */
@Fluent
public final class SchemaId {
/*
* Schema ID that uniquely identifies a schema in the registry namespace.
*/
@JsonProperty(value = "id")
private String id;

/**
* Get the id property: Schema ID that uniquely identifies a schema in the registry namespace.
*
* @return the id value.
*/
public String getId() {
return this.id;
}

/**
* Set the id property: Schema ID that uniquely identifies a schema in the registry namespace.
*
* @param id the id value to set.
* @return the SchemaId object itself.
*/
public SchemaId setId(String id) {
this.id = id;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name=${project.artifactId}
version=${project.version}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.azure.core.credential.TokenRequestContext;
import com.azure.core.exception.HttpResponseException;
import com.azure.core.exception.ResourceNotFoundException;
import com.azure.core.http.policy.HttpLogDetailLevel;
import com.azure.core.http.policy.HttpLogOptions;
import com.azure.core.http.policy.RetryPolicy;
import com.azure.core.test.TestBase;
import com.azure.data.schemaregistry.models.SchemaFormat;
Expand All @@ -19,6 +21,7 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Pattern;
Expand All @@ -43,7 +46,7 @@ public class SchemaRegistryAsyncClientTests extends TestBase {
static final String SCHEMA_CONTENT_NO_WHITESPACE = WHITESPACE_PATTERN.matcher(SCHEMA_CONTENT).replaceAll("");

// When we regenerate recordings, make sure that the schema group matches what we are persisting.
static final String PLAYBACK_TEST_GROUP = "testgroup001";
static final String PLAYBACK_TEST_GROUP = "mygroup";

private String schemaGroup;
private SchemaRegistryClientBuilder builder;
Expand Down Expand Up @@ -82,6 +85,7 @@ protected void beforeTest() {
builder.httpClient(interceptorManager.getPlaybackClient());
} else {
builder.addPolicy(new RetryPolicy())
.httpLogOptions(new HttpLogOptions().setLogLevel(HttpLogDetailLevel.BODY_AND_HEADERS))
.addPolicy(interceptorManager.getRecordPolicy());
}
}
Expand Down Expand Up @@ -201,6 +205,53 @@ public void registerAndGetSchemaId() {
.verifyComplete();
}

/**
* Verifies that a 415 is returned if we use an invalid schema format.
*/
@Test
public void registerSchemaInvalidFormat() {
// Arrange
final String schemaName = testResourceNamer.randomName("sch", RESOURCE_LENGTH);
final SchemaRegistryAsyncClient client = builder.buildAsyncClient();
final SchemaFormat unknownSchemaFormat = SchemaFormat.fromString("protobuf");

// Act & Assert
StepVerifier.create(client.registerSchemaWithResponse(schemaGroup, schemaName, SCHEMA_CONTENT, unknownSchemaFormat))
.expectErrorSatisfies(error -> {
assertTrue(error instanceof HttpResponseException);

final HttpResponseException responseException = ((HttpResponseException) error);
assertEquals(415, responseException.getResponse().getStatusCode());
})
.verify();
}

/**
* Verifies that if we register a schema and try to fetch it using an invalid schema format, an error is returned.
*/
@Test
public void registerAndGetSchemaPropertiesWithInvalidFormat() {
// Arrange
final String schemaName = testResourceNamer.randomName("sch", RESOURCE_LENGTH);
final SchemaRegistryAsyncClient client1 = builder.buildAsyncClient();
final SchemaRegistryAsyncClient client2 = builder.buildAsyncClient();
final SchemaFormat invalidFormat = SchemaFormat.fromString("protobuf");

final SchemaProperties schemaProperties = client1.registerSchema(schemaGroup, schemaName, SCHEMA_CONTENT,
SchemaFormat.AVRO).block(Duration.ofSeconds(10));

assertNotNull(schemaProperties);

// Act & Assert
StepVerifier.create(client2.getSchemaProperties(schemaGroup, schemaName, SCHEMA_CONTENT, invalidFormat))
.expectErrorSatisfies(error -> {
assertTrue(error instanceof HttpResponseException);

final HttpResponseException responseException = ((HttpResponseException) error);
assertEquals(415, responseException.getResponse().getStatusCode());
}).verify();
}

/**
* Verifies that we can register a schema and then get it by its schemaId.
*/
Expand Down Expand Up @@ -248,14 +299,15 @@ public void getSchemaIdDoesNotExist() {
final SchemaRegistryAsyncClient client1 = builder.buildAsyncClient();

// Act & Assert
StepVerifier.create(client1.getSchemaProperties(PLAYBACK_TEST_GROUP, "bar", SCHEMA_CONTENT, SchemaFormat.AVRO))
StepVerifier.create(client1.getSchemaProperties(schemaGroup, "bar", SCHEMA_CONTENT, SchemaFormat.AVRO))
.expectErrorSatisfies(error -> {
assertTrue(error instanceof ResourceNotFoundException);
assertEquals(404, ((ResourceNotFoundException) error).getResponse().getStatusCode());
})
.verify();
}


static void assertSchemaRegistrySchema(SchemaRegistrySchema actual, String expectedSchemaId, SchemaFormat format,
String expectedContents) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

import java.time.OffsetDateTime;

Expand All @@ -31,6 +32,7 @@
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -193,6 +195,27 @@ public void registerBadRequest() {
assertEquals(400, exception.getResponse().getStatusCode());
}

/**
* Verifies that a 415 is returned if we use an invalid schema format.
*/
@Test
public void registerSchemaInvalidFormat() {
// Arrange
final String schemaName = testResourceNamer.randomName("sch", RESOURCE_LENGTH);
final SchemaRegistryAsyncClient client = builder.buildAsyncClient();
final SchemaFormat unknownSchemaFormat = SchemaFormat.fromString("protobuf");

// Act & Assert
StepVerifier.create(client.registerSchemaWithResponse(schemaGroup, schemaName, SCHEMA_CONTENT, unknownSchemaFormat))
.expectErrorSatisfies(error -> {
assertTrue(error instanceof HttpResponseException);

final HttpResponseException responseException = ((HttpResponseException) error);
assertEquals(415, responseException.getResponse().getStatusCode());
})
.verify();
}

/**
* Verifies that we get 404 when non-existent schema returned.
*/
Expand All @@ -219,7 +242,7 @@ public void getSchemaIdDoesNotExist() {

// Act & Assert
final ResourceNotFoundException error = assertThrows(ResourceNotFoundException.class,
() -> client1.getSchemaProperties(PLAYBACK_TEST_GROUP, "bar", SCHEMA_CONTENT, SchemaFormat.AVRO));
() -> client1.getSchemaProperties(schemaGroup, "bar", SCHEMA_CONTENT, SchemaFormat.AVRO));

assertEquals(404, error.getResponse().getStatusCode());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
"Method" : "GET",
"Uri" : "https://REDACTED.servicebus.windows.net/$schemaGroups/$schemas/59f112cf-ff02-40e6-aca9-0d30ed7f7f94?api-version=2021-10",
"Headers" : {
"User-Agent" : "azsdk-java-UnknownName/UnknownVersion (11.0.5; Windows 10; 10.0)",
"x-ms-client-request-id" : "67364f5a-7a2d-4edf-8ec5-4ee3c53a7e6b"
"User-Agent" : "azsdk-java-azure-data-schemaregistry/1.0.0-beta.7 (11.0.5; Windows 10; 10.0)",
"x-ms-client-request-id" : "2c32253c-ef1f-47ba-a7f6-04721ff502b9"
},
"Response" : {
"Transfer-Encoding" : "chunked",
"Strict-Transport-Security" : "max-age=31536000",
"Server" : "Microsoft-HTTPAPI/2.0",
"retry-after" : "0",
"StatusCode" : "404",
"Body" : "{\"Code\":404,\"Detail\":\"Schema id 59f112cf-ff02-40e6-aca9-0d30ed7f7f94 does not exist. TrackingId:897a19b1-d44e-4d5c-b909-1d7a31270b67_G2, SystemTracker:hmlam-sr-test-01.servicebus.windows.net:$schemaGroups\\/$schemas\\/59f112cf-ff02-40e6-aca9-0d30ed7f7f94, Timestamp:2021-11-02T21:05:09\"}",
"Date" : "Tue, 02 Nov 2021 21:05:08 GMT",
"Body" : "{\"Code\":404,\"Detail\":\"Schema id 59f112cf-ff02-40e6-aca9-0d30ed7f7f94 does not exist. TrackingId:0be5b411-cfc7-40f3-aebf-f48ffe71d265_G30, SystemTracker:conniey.servicebus.windows.net:$schemaGroups\\/$schemas\\/59f112cf-ff02-40e6-aca9-0d30ed7f7f94, Timestamp:2021-11-11T02:50:13\"}",
"Date" : "Thu, 11 Nov 2021 02:50:13 GMT",
"Content-Type" : "application/json"
},
"Exception" : null
Expand Down
Loading

0 comments on commit 252afe9

Please sign in to comment.