Skip to content

Commit

Permalink
feat: added test for spring messaging consumer bean
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheheryar authored and Sheheryar committed Nov 8, 2023
1 parent fd05041 commit 07b745d
Show file tree
Hide file tree
Showing 89 changed files with 1,386 additions and 492 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SPRINGWOLF_VERSION=0.16.0-SNAPSHOT
SPRINGWOLF_VERSION=0.17.0-SNAPSHOT
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ buildscript {
plugins {
id 'ca.cutterslade.analyze' version '1.9.1'
id 'io.spring.dependency-management' version '1.1.3' apply false
id 'org.springframework.boot' version '3.1.4' apply false
id 'org.owasp.dependencycheck' version '8.4.0'
id 'org.springframework.boot' version '3.1.5' apply false
id 'org.owasp.dependencycheck' version '8.4.2'
id 'com.diffplug.spotless' version '6.22.0'
id 'com.bmuschko.docker-spring-boot-application' version '9.3.4' apply false
id 'com.bmuschko.docker-spring-boot-application' version '9.3.6' apply false
}

applyDotEnvFileAsGradleProperties()
Expand Down
2 changes: 1 addition & 1 deletion dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ ext {

slf4jApiVersion = '2.0.9'

swaggerVersion = '2.2.17'
swaggerVersion = '2.2.18'

testcontainersVersion = '1.19.1'
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ public SpringwolfConfigProperties springwolfConfigProperties() {
}

@Bean
@ConditionalOnMissingBean
public SpringwolfInitApplicationListener springwolfInitApplicationListener(
AsyncApiService asyncApiService, SpringwolfConfigProperties configProperties) {
return new SpringwolfInitApplicationListener(asyncApiService, configProperties);
}

@Bean
@ConditionalOnMissingBean
public AsyncApiService asyncApiService(
AsyncApiDocketService asyncApiDocketService,
ChannelsService channelsService,
Expand All @@ -58,16 +60,22 @@ public AsyncApiService asyncApiService(
}

@Bean
@ConditionalOnMissingBean
public ChannelsService channelsService(List<? extends ChannelsScanner> channelsScanners) {
return new DefaultChannelsService(channelsScanners);
}

@Bean
public SchemasService schemasService(List<ModelConverter> modelConverters, ExampleGenerator exampleGenerator) {
return new DefaultSchemasService(modelConverters, exampleGenerator);
@ConditionalOnMissingBean
public SchemasService schemasService(
List<ModelConverter> modelConverters,
ExampleGenerator exampleGenerator,
SpringwolfConfigProperties springwolfConfigProperties) {
return new DefaultSchemasService(modelConverters, exampleGenerator, springwolfConfigProperties);
}

@Bean
@ConditionalOnMissingBean
public AsyncApiDocketService asyncApiDocketService(
Optional<AsyncApiDocket> optionalAsyncApiDocket, SpringwolfConfigProperties springwolfConfigProperties) {
return new DefaultAsyncApiDocketService(optionalAsyncApiDocket, springwolfConfigProperties);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ConfigurationClassScanner;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -34,18 +35,21 @@
public class SpringwolfScannerConfiguration {

@Bean
@ConditionalOnMissingBean
public ComponentClassScanner componentClassScanner(
AsyncApiDocketService asyncApiDocketService, Environment environment) {
return new ComponentClassScanner(asyncApiDocketService, environment);
}

@Bean
@ConditionalOnMissingBean
public ConfigurationClassScanner configurationClassScanner(
AsyncApiDocketService asyncApiDocketService, Environment environment) {
return new ConfigurationClassScanner(asyncApiDocketService, environment);
}

@Bean
@ConditionalOnMissingBean
public BeanMethodsScanner beanMethodsScanner(ConfigurationClassScanner configurationClassScanner) {
return new DefaultBeanMethodsScanner(configurationClassScanner);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.stavshamir.springwolf.asyncapi.AsyncApiSerializerService;
import io.github.stavshamir.springwolf.asyncapi.AsyncApiService;
import io.github.stavshamir.springwolf.asyncapi.DefaultAsyncApiSerializerService;
import io.github.stavshamir.springwolf.asyncapi.controller.ActuatorAsyncApiController;
import io.github.stavshamir.springwolf.asyncapi.controller.AsyncApiController;
import io.github.stavshamir.springwolf.asyncapi.controller.PublishingPayloadCreator;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand All @@ -20,19 +24,28 @@ public class SpringwolfWebConfiguration {

@Bean
@ConditionalOnProperty(name = SPRINGWOLF_ENDPOINT_ACTUATOR_ENABLED, havingValue = "false", matchIfMissing = true)
@ConditionalOnMissingBean
public AsyncApiController asyncApiController(
AsyncApiService asyncApiService, AsyncApiSerializerService asyncApiSerializerService) {
return new AsyncApiController(asyncApiService, asyncApiSerializerService);
}

@Bean
@ConditionalOnMissingBean
public PublishingPayloadCreator publishingPayloadCreator(SchemasService schemasService, ObjectMapper objectMapper) {
return new PublishingPayloadCreator(schemasService, objectMapper);
}

@Bean
@ConditionalOnProperty(name = SPRINGWOLF_ENDPOINT_ACTUATOR_ENABLED, havingValue = "true")
@ConditionalOnMissingBean
public ActuatorAsyncApiController actuatorAsyncApiController(
AsyncApiService asyncApiService, AsyncApiSerializerService asyncApiSerializerService) {
return new ActuatorAsyncApiController(asyncApiService, asyncApiSerializerService);
}

@Bean
@ConditionalOnMissingBean
public AsyncApiSerializerService asyncApiSerializerService() {
return new DefaultAsyncApiSerializerService();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.controller;

import io.github.stavshamir.springwolf.asyncapi.controller.dtos.MessageDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

/**
* Used in plugins with publishing enabled.
* Located in springwolf-core to allow sharing of code
*/
@RequiredArgsConstructor
@Slf4j
public abstract class PublishingBaseController implements InitializingBean {

private final PublishingPayloadCreator publishingPayloadCreator;

protected abstract boolean isEnabled();

protected abstract void publishMessage(String topic, MessageDto message, Object payload);

@PostMapping("/publish")
public ResponseEntity<String> publish(@RequestParam String topic, @RequestBody MessageDto message) {
if (!isEnabled()) {
String errorMessage = "Publishing using %s is not enabled - message will not be published"
.formatted(this.getClass().getSimpleName());
log.warn(errorMessage);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorMessage);
}

PublishingPayloadCreator.Result result = publishingPayloadCreator.createPayloadObject(message);
if (result.payload() != null) {
publishMessage(topic, message, result.payload());
return ResponseEntity.ok().build();
}
return ResponseEntity.badRequest().body(result.errorMessage());
}

@Override
public void afterPropertiesSet() {
log.debug(
"Message publishing via %s is active.".formatted(this.getClass().getSimpleName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.stavshamir.springwolf.asyncapi.controller.dtos.MessageDto;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import io.swagger.v3.oas.models.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.text.MessageFormat;

/**
* Used in plugins with publishing enabled.
* Located in springwolf-core to allow sharing of code
*/
@RequiredArgsConstructor
@Slf4j
public class PublishingPayloadCreator {

private final SchemasService schemasService;
private final ObjectMapper objectMapper;

public Result createPayloadObject(MessageDto message) {

String messagePayloadType = message.getPayloadType();
for (Schema<?> value : schemasService.getDefinitions().values()) {
String schemaPayloadType = value.getName();
// security: match against user input, but always use our controlled data from the DefaultSchemaService
if (schemaPayloadType.equals(messagePayloadType)) {
try {
Class<?> payloadClass = Class.forName(schemaPayloadType);
Object payload = objectMapper.readValue(message.getPayload(), payloadClass);
return new Result(payload, null);
} catch (ClassNotFoundException | JsonProcessingException ex) {
String errorMessage = MessageFormat.format(
"Unable to create payload {0} from data: {1}", schemaPayloadType, message.getPayload());
log.info(errorMessage, ex);
return new Result(null, errorMessage);
}
}
}

String errorMessage = MessageFormat.format(
"Specified payloadType {0} is not a registered springwolf schema.", messagePayloadType);
log.info(errorMessage);
return new Result(null, errorMessage);
}

public record Result(Object payload, String errorMessage) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ private Message buildMessage(Method method) {

return Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
.bindings(buildMessageBinding(method))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private ChannelItem buildChannel(

Message message = Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
.bindings(messageBinding)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static java.util.stream.Collectors.toSet;

@Slf4j
@Deprecated(forRemoval = true)
public abstract class AbstractOperationDataScanner implements ChannelsScanner {

protected abstract SchemasService getSchemaService();
Expand Down Expand Up @@ -108,7 +109,7 @@ private Message buildMessage(OperationData operationData) {

var builder = Message.builder()
.name(payloadType.getName())
.title(modelName)
.title(payloadType.getSimpleName())
.description(description)
.payload(PayloadReference.fromModelName(modelName))
.headers(HeaderReference.fromModelName(headerModelName))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

@Slf4j
@RequiredArgsConstructor
@Deprecated(forRemoval = true)
public class ConsumerOperationDataScanner extends AbstractOperationDataScanner {

private final AsyncApiDocketService asyncApiDocketService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

@Slf4j
@RequiredArgsConstructor
@Deprecated(forRemoval = true)
public class ProducerOperationDataScanner extends AbstractOperationDataScanner {

private final AsyncApiDocketService asyncApiDocketService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
String name();

/**
* Mapped to {@link AsyncHeaderSchema#getDescription()} ()}
* Mapped to {@link AsyncHeaderSchema#getDescription()}
*/
String description() default "";

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header;

public class AsyncHeadersCloudEventConstants {
public static final String CONTENT_TYPE = "content-type";
public static final String CONTENT_TYPE_DESC = "CloudEvent Content-Type Header";
public static final String ID = "ce_id";
public static final String ID_DESC = "CloudEvent Id Header";
public static final String SPECVERSION = "ce_specversion";
public static final String SPECVERSION_DESC = "CloudEvent Spec Version Header";
public static final String SOURCE = "ce_source";
public static final String SOURCE_DESC = "CloudEvent Source Header";
public static final String SUBJECT = "ce_subject";
public static final String SUBJECT_DESC = "CloudEvent Subject Header";
public static final String TIME = "ce_time";
public static final String TIME_DESC = "CloudEvent Time Header";
public static final String TYPE = "ce_type";
public static final String TYPE_DESC = "CloudEvent Payload Type Header";
}
Loading

0 comments on commit 07b745d

Please sign in to comment.