Search in sources :

Example 6 with TopicCreationData

use of com.bakdata.quick.common.api.model.manager.creation.TopicCreationData in project quick by bakdata.

the class KafkaTopicServiceTest method shouldNotCreateTopicIfSubjectExists.

@Test
@Disabled("Compatibility test not supported in SR mock yet")
void shouldNotCreateTopicIfSubjectExists() throws RestClientException, IOException {
    final String topicName = UUID.randomUUID().toString();
    this.successfulMock();
    this.schemaRegistry.registerValueSchema(topicName, this.graphQLToAvroConverter.convertToSchema(SCHEMA));
    when(this.gatewayService.getGateway(GATEWAY_SCHEMA.getGateway())).thenReturn(Single.just(new GatewayDescription("test", 1, "latest")));
    when(this.gatewayClient.getWriteSchema(anyString(), anyString())).thenReturn(Single.just(new SchemaData(SCHEMA)));
    final TopicCreationData requestData = new TopicCreationData(TopicWriteType.MUTABLE, GATEWAY_SCHEMA, null, null);
    final Throwable throwable = this.topicService.createTopic(topicName, QuickTopicType.DOUBLE, QuickTopicType.SCHEMA, requestData).blockingGet();
    assertThat(throwable).isNotNull().isExactlyInstanceOf(BadArgumentException.class).extracting(Throwable::getMessage).asString().endsWith("already exists");
    assertThat(kafkaCluster.exists(topicName)).isFalse();
    assertThat(this.topicRegistryClient.topicDataExists(topicName).blockingGet()).isFalse();
    assertThat(this.schemaRegistry.getSchemaRegistryClient().getAllSubjects()).isEmpty();
}
Also used : BadArgumentException(com.bakdata.quick.common.exception.BadArgumentException) TopicCreationData(com.bakdata.quick.common.api.model.manager.creation.TopicCreationData) SchemaData(com.bakdata.quick.common.api.model.gateway.SchemaData) GatewayDescription(com.bakdata.quick.common.api.model.manager.GatewayDescription) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test) Disabled(org.junit.jupiter.api.Disabled)

Example 7 with TopicCreationData

use of com.bakdata.quick.common.api.model.manager.creation.TopicCreationData in project quick by bakdata.

the class KafkaTopicServiceTest method shouldNotCreateTopicThatAlreadyExistsInRegistry.

@Test
void shouldNotCreateTopicThatAlreadyExistsInRegistry() throws RestClientException, IOException {
    final String topicName = UUID.randomUUID().toString();
    this.successfulMock();
    final TopicCreationData requestData = new TopicCreationData(TopicWriteType.MUTABLE, null, null, null);
    this.topicRegistryClient.register(topicName, new TopicData(topicName, TopicWriteType.MUTABLE, null, null, null)).blockingAwait();
    assertThat(this.topicRegistryClient.topicDataExists(topicName).blockingGet()).isTrue();
    final Throwable exception = this.topicService.createTopic(topicName, QuickTopicType.DOUBLE, QuickTopicType.DOUBLE, requestData).blockingGet();
    final String expectedErrorMsg = String.format("Topic \"%s\" already exists", topicName);
    assertThat(exception).isExactlyInstanceOf(BadArgumentException.class).extracting(Throwable::getMessage).asString().startsWith(expectedErrorMsg);
    assertThat(kafkaCluster.exists(topicName)).isFalse();
    assertThat(this.schemaRegistry.getSchemaRegistryClient().getAllSubjects()).isEmpty();
}
Also used : BadArgumentException(com.bakdata.quick.common.exception.BadArgumentException) TopicCreationData(com.bakdata.quick.common.api.model.manager.creation.TopicCreationData) TopicData(com.bakdata.quick.common.api.model.TopicData) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test)

Example 8 with TopicCreationData

use of com.bakdata.quick.common.api.model.manager.creation.TopicCreationData in project quick by bakdata.

the class KafkaTopicService method createTopic.

@SuppressWarnings("RxReturnValueIgnored")
@Override
public Completable createTopic(final String name, final QuickTopicType keyType, final QuickTopicType valueType, final TopicCreationData requestData) {
    log.info("Create new topic {} with data {}", name, requestData);
    // we don't need the cache, so make sure we get the current information
    this.schemaRegistryClient.reset();
    // first, check if topic might already exist in topic registry or kafka itself and then make also sure there
    final Completable kafkaStateCheck = Completable.mergeArray(this.checkKafka(name), this.checkTopicRegistry(name));
    final Single<Optional<QuickSchemas>> keySchema = this.getQuickSchemas(requestData.getKeySchema()).cache();
    final Single<Optional<QuickSchemas>> valueSchema = this.getQuickSchemas(requestData.getValueSchema()).cache();
    final Completable schemaRegistryCheck = Completable.defer(() -> Completable.mergeArray(keySchema.flatMapCompletable(schema -> this.checkSchemaRegistry(name + "-key", schema)), valueSchema.flatMapCompletable(schema -> this.checkSchemaRegistry(name + "-value", schema))));
    final Completable stateCheck = kafkaStateCheck.andThen(schemaRegistryCheck);
    // create topic in kafka and deploy a mirror application
    final Completable kafkaTopicCreation = this.createKafkaTopic(name);
    final Completable mirrorCreation = this.createMirror(name, requestData.getRetentionTime());
    // default to mutable topic write type
    final TopicWriteType writeType = Objects.requireNonNullElse(requestData.getWriteType(), TopicWriteType.MUTABLE);
    // register at topic registry (value schema can be nullable)
    // todo evaluate whether the schema should be part of the topic registry
    final Completable topicRegister = Completable.defer(() -> {
        log.debug("Register subject '{}' with topic registry", name);
        return valueSchema.flatMapCompletable(schema -> {
            final String graphQLSchema = schema.map(QuickSchemas::getGraphQLSchema).orElse(null);
            final TopicData topicData = new TopicData(name, writeType, keyType, valueType, graphQLSchema);
            return this.topicRegistryClient.register(name, topicData);
        });
    });
    // register potential avro schema with the schema registry
    final Completable keyRegister = keySchema.flatMapCompletable(schemas -> this.registerSchema(name, schemas, KEY));
    final Completable valueRegister = valueSchema.flatMapCompletable(schemas -> this.registerSchema(name, schemas, VALUE));
    final Completable creationOperations = Completable.mergeArray(kafkaTopicCreation, mirrorCreation, topicRegister, keyRegister, valueRegister);
    return stateCheck.andThen(creationOperations.doOnError(ignored -> this.deleteTopic(name)));
}
Also used : MirrorCreationData(com.bakdata.quick.common.api.model.manager.creation.MirrorCreationData) TopicRegistryClient(com.bakdata.quick.common.api.client.TopicRegistryClient) SchemaRegistryClient(io.confluent.kafka.schemaregistry.client.SchemaRegistryClient) KEY(com.bakdata.quick.common.api.model.KeyValueEnum.KEY) TopicWriteType(com.bakdata.quick.common.api.model.TopicWriteType) Completable(io.reactivex.Completable) GatewayClient(com.bakdata.quick.common.api.client.GatewayClient) Singleton(javax.inject.Singleton) Single(io.reactivex.Single) Supplier(java.util.function.Supplier) GraphQLToAvroConverter(com.bakdata.quick.manager.graphql.GraphQLToAvroConverter) Value(lombok.Value) AdminClient(org.apache.kafka.clients.admin.AdminClient) KafkaConfig(com.bakdata.quick.common.config.KafkaConfig) MirrorService(com.bakdata.quick.manager.mirror.MirrorService) Duration(java.time.Duration) KeyValueEnum(com.bakdata.quick.common.api.model.KeyValueEnum) QuickTopicConfig(com.bakdata.quick.common.config.QuickTopicConfig) QuickTopicType(com.bakdata.quick.common.type.QuickTopicType) Schema(org.apache.avro.Schema) ResourcePrefix(com.bakdata.quick.manager.k8s.resource.QuickResources.ResourcePrefix) NewTopic(org.apache.kafka.clients.admin.NewTopic) GatewaySchema(com.bakdata.quick.common.api.model.manager.GatewaySchema) IOException(java.io.IOException) VALUE(com.bakdata.quick.common.api.model.KeyValueEnum.VALUE) BadArgumentException(com.bakdata.quick.common.exception.BadArgumentException) TopicCreationData(com.bakdata.quick.common.api.model.manager.creation.TopicCreationData) Objects(java.util.Objects) List(java.util.List) Slf4j(lombok.extern.slf4j.Slf4j) TopicData(com.bakdata.quick.common.api.model.TopicData) GatewayService(com.bakdata.quick.manager.gateway.GatewayService) Optional(java.util.Optional) CachedSchemaRegistryClient(io.confluent.kafka.schemaregistry.client.CachedSchemaRegistryClient) Completable(io.reactivex.Completable) Optional(java.util.Optional) TopicData(com.bakdata.quick.common.api.model.TopicData) TopicWriteType(com.bakdata.quick.common.api.model.TopicWriteType)

Example 9 with TopicCreationData

use of com.bakdata.quick.common.api.model.manager.creation.TopicCreationData in project quick by bakdata.

the class KafkaTopicServiceTest method shouldNotCreateTopicThatAlreadyExists.

@Test
void shouldNotCreateTopicThatAlreadyExists() {
    final String topicName = UUID.randomUUID().toString();
    this.successfulMock();
    final TopicCreationData requestData = new TopicCreationData(TopicWriteType.MUTABLE, null, null, null);
    this.topicService.createTopic(topicName, QuickTopicType.DOUBLE, QuickTopicType.DOUBLE, requestData).blockingAwait();
    assertThat(kafkaCluster.exists(topicName)).isTrue();
    final Throwable exception = this.topicService.createTopic(topicName, QuickTopicType.DOUBLE, QuickTopicType.DOUBLE, requestData).blockingGet();
    final String expectedErrorMsg = String.format("Topic \"%s\" already exists", topicName);
    assertThat(exception).isExactlyInstanceOf(BadArgumentException.class).extracting(Throwable::getMessage).asString().startsWith(expectedErrorMsg);
}
Also used : BadArgumentException(com.bakdata.quick.common.exception.BadArgumentException) TopicCreationData(com.bakdata.quick.common.api.model.manager.creation.TopicCreationData) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test)

Example 10 with TopicCreationData

use of com.bakdata.quick.common.api.model.manager.creation.TopicCreationData in project quick by bakdata.

the class KafkaTopicServiceTest method shouldThrowExceptionForNonExistingGateway.

@Test
void shouldThrowExceptionForNonExistingGateway() {
    final String topicName = UUID.randomUUID().toString();
    this.successfulMock();
    // error thrown when checking if gateway exists
    final Throwable error = new NotFoundException(String.format("Could not find resource %s", GATEWAY_SCHEMA.getGateway()));
    when(this.gatewayService.getGateway(GATEWAY_SCHEMA.getGateway())).thenReturn(Single.error(error));
    // resource doesn't exist, traefik cannot route it; This should not be called since we check existence before
    final HttpException clientException = new HttpClientResponseException("Not found", HttpResponse.notFound());
    when(this.gatewayClient.getWriteSchema(anyString(), anyString())).thenReturn(Single.error(clientException));
    final TopicCreationData requestData = new TopicCreationData(TopicWriteType.MUTABLE, GATEWAY_SCHEMA, null, null);
    final Completable completable = this.topicService.createTopic(topicName, QuickTopicType.DOUBLE, QuickTopicType.SCHEMA, requestData);
    final Throwable actual = completable.blockingGet();
    assertThat(actual).isNotNull().isInstanceOf(QuickException.class).hasMessageStartingWith("Could not find resource test");
    verify(this.gatewayClient, never()).getWriteSchema(anyString(), anyString());
}
Also used : TopicCreationData(com.bakdata.quick.common.api.model.manager.creation.TopicCreationData) Completable(io.reactivex.Completable) QuickException(com.bakdata.quick.common.exception.QuickException) HttpClientResponseException(io.micronaut.http.client.exceptions.HttpClientResponseException) NotFoundException(com.bakdata.quick.common.exception.NotFoundException) HttpException(io.micronaut.http.exceptions.HttpException) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Test(org.junit.jupiter.api.Test)

Aggregations

TopicCreationData (com.bakdata.quick.common.api.model.manager.creation.TopicCreationData)15 Test (org.junit.jupiter.api.Test)14 ArgumentMatchers.anyString (org.mockito.ArgumentMatchers.anyString)13 Completable (io.reactivex.Completable)8 GatewayDescription (com.bakdata.quick.common.api.model.manager.GatewayDescription)5 BadArgumentException (com.bakdata.quick.common.exception.BadArgumentException)5 TopicData (com.bakdata.quick.common.api.model.TopicData)4 SchemaData (com.bakdata.quick.common.api.model.gateway.SchemaData)4 GatewaySchema (com.bakdata.quick.common.api.model.manager.GatewaySchema)3 MirrorCreationData (com.bakdata.quick.common.api.model.manager.creation.MirrorCreationData)2 SchemaRegistryClient (io.confluent.kafka.schemaregistry.client.SchemaRegistryClient)2 MicronautTest (io.micronaut.test.extensions.junit5.annotation.MicronautTest)2 Duration (java.time.Duration)2 List (java.util.List)2 Schema (org.apache.avro.Schema)2 GatewayClient (com.bakdata.quick.common.api.client.GatewayClient)1 TopicRegistryClient (com.bakdata.quick.common.api.client.TopicRegistryClient)1 KeyValueEnum (com.bakdata.quick.common.api.model.KeyValueEnum)1 KEY (com.bakdata.quick.common.api.model.KeyValueEnum.KEY)1 VALUE (com.bakdata.quick.common.api.model.KeyValueEnum.VALUE)1