Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
Copy link
Copy Markdown

@lmolkova lmolkova Nov 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for my own education: if this is eventually ends up in the HTTP content-type header, why does the case (avro -> Avro) matter?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't. I can remove it to reduce the diff

@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