actual = properties.getDocket().getGroupConfigs();
+
+ // then
+ assertThat(actual).hasSize(2);
+ assertThat(actual.get(0)).isEqualTo(sendGroup);
+ assertThat(actual.get(1)).isEqualTo(receiveGroup);
+ }
+ }
}
diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java
index 826348b33..4e42053d8 100644
--- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java
+++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/AsyncApiDocumentIntegrationTest.java
@@ -255,4 +255,74 @@ void enumAsRefIsHandled() {
.isEqualTo("\"DOG\"");
}
}
+
+ @Nested
+ @SpringBootTest(classes = ListenerApplication.class)
+ @MinimalIntegrationTestContextConfiguration
+ @TestPropertySource(
+ properties = {
+ "springwolf.docket.base-package=io.github.springwolf.core.integrationtests.application.listener",
+ "springwolf.docket.group-configs[0].group=FooMessage",
+ "springwolf.docket.group-configs[0].action-to-match=",
+ "springwolf.docket.group-configs[0].channel-name-to-match=",
+ "springwolf.docket.group-configs[0].message-name-to-match=.*Foo",
+ "springwolf.docket.group-configs[1].group=all & everything",
+ "springwolf.docket.group-configs[1].action-to-match=",
+ "springwolf.docket.group-configs[1].channel-name-to-match=.*",
+ "springwolf.docket.group-configs[1].message-name-to-match=",
+ })
+ class GroupingTest {
+ @Autowired
+ private AsyncApiService asyncApiService;
+
+ @Test
+ void shouldFindOnlyForGroupFoo() {
+ AsyncAPI asyncAPI = asyncApiService.getForGroupName("FooMessage").get();
+
+ assertThat(asyncAPI.getChannels().keySet()).containsExactlyInAnyOrder("listener-channel");
+ assertThat(asyncAPI.getChannels().get("listener-channel").getMessages())
+ .containsOnlyKeys(
+ "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo");
+ assertThat(asyncAPI.getOperations())
+ .containsOnlyKeys("listener-channel_receive_listen3", "listener-channel_receive_listen4");
+ assertThat(asyncAPI.getComponents().getMessages())
+ .containsOnlyKeys(
+ "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo");
+ assertThat(asyncAPI.getComponents().getSchemas())
+ .containsOnlyKeys(
+ "HeadersNotDocumented",
+ "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Bar",
+ "io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo");
+
+ MessageObject fooMessage = (MessageObject) asyncAPI.getComponents()
+ .getMessages()
+ .get("io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo");
+ assertThat(fooMessage.getPayload().getMultiFormatSchema().getSchema())
+ .isInstanceOf(MessageReference.class);
+ MessageReference fooRefMessage = (MessageReference)
+ fooMessage.getPayload().getMultiFormatSchema().getSchema();
+ assertThat(fooRefMessage.getRef())
+ .isEqualTo(
+ "#/components/schemas/io.github.springwolf.core.integrationtests.application.listener.ListenerApplication$Foo");
+ }
+
+ @Test
+ void shouldFindAllForGroupAll() {
+ // given
+ AsyncAPI fullApi = asyncApiService.getAsyncAPI();
+
+ // when
+ AsyncAPI asyncAPIOpt =
+ asyncApiService.getForGroupName("all & everything").get();
+
+ // then
+
+ // String and Integer get filtered.
+ // Question: Why are they in the fullApi in the first place, if not referenced? (inline schema)
+ fullApi.getComponents().getSchemas().remove(String.class.getName());
+ fullApi.getComponents().getSchemas().remove(Integer.class.getName());
+
+ assertThat(asyncAPIOpt).isEqualTo(fullApi);
+ }
+ }
}
diff --git a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/InitModeIntegrationTest.java b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/InitModeIntegrationTest.java
index 85a95d13e..41f18b7a2 100644
--- a/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/InitModeIntegrationTest.java
+++ b/springwolf-core/src/test/java/io/github/springwolf/core/integrationtests/InitModeIntegrationTest.java
@@ -71,7 +71,7 @@ void applicationShouldNotStart() {
SpringApplication.run(TestApplication.class, args);
fail("Exception expected, but not raised.");
} catch (Exception ex) {
- assertThat(ex.getMessage()).contains("Error occured during creation of AsyncAPI");
+ assertThat(ex.getMessage()).contains("Error occurred during creation of AsyncAPI");
}
}
}
diff --git a/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties b/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
index 215a84849..aec88ed49 100644
--- a/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
+++ b/springwolf-examples/springwolf-kafka-example/src/main/resources/application.properties
@@ -40,6 +40,9 @@ springwolf.docket.info.contact.url=https://github.com/springwolf/springwolf-core
springwolf.docket.info.license.name=Apache License 2.0
springwolf.payload.extractable-classes.org.apache.kafka.clients.consumer.ConsumerRecord=1
+springwolf.docket.group-configs[0].group=Only Vehicles
+springwolf.docket.group-configs[0].message-name-to-match=.*Vehicle.*
+
# Springwolf kafka configuration
springwolf.docket.servers.kafka-server.protocol=kafka
springwolf.docket.servers.kafka-server.host=${spring.kafka.bootstrap-servers}
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java
index fd940ba55..20235b427 100644
--- a/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java
+++ b/springwolf-examples/springwolf-kafka-example/src/test/java/io/github/springwolf/examples/kafka/ApiIntegrationTest.java
@@ -53,4 +53,30 @@ void asyncApiResourceArtifactYamlTest() throws IOException {
assertEquals(expected, actualPatched);
}
+
+ @Test
+ void asyncApiResourceForVehicleGroupArtifactTest() throws IOException {
+ String url = "/springwolf/docs/Only Vehicles";
+ String actual = restTemplate.getForObject(url, String.class);
+ // When running with EmbeddedKafka, the kafka bootstrap server does run on random ports
+ String actualPatched = actual.replace(bootstrapServers, "kafka:29092").trim();
+ Files.writeString(Path.of("src", "test", "resources", "groups", "vehicles.actual.json"), actualPatched);
+
+ InputStream s = this.getClass().getResourceAsStream("/groups/vehicles.json");
+ String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim();
+
+ assertEquals(expected, actualPatched);
+ }
+
+ @Test
+ void uiConfigTest() throws IOException {
+ String url = "/springwolf/ui-config";
+ String actual = restTemplate.getForObject(url, String.class);
+ Files.writeString(Path.of("src", "test", "resources", "ui-config.actual.json"), actual);
+
+ InputStream s = this.getClass().getResourceAsStream("/ui-config.json");
+ String expected = new String(s.readAllBytes(), StandardCharsets.UTF_8).trim();
+
+ assertEquals(expected, actual);
+ }
}
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/groups/vehicles.json b/springwolf-examples/springwolf-kafka-example/src/test/resources/groups/vehicles.json
new file mode 100644
index 000000000..848db8665
--- /dev/null
+++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/groups/vehicles.json
@@ -0,0 +1,157 @@
+{
+ "asyncapi": "3.0.0",
+ "info": {
+ "title": "Springwolf example project - Kafka",
+ "version": "1.0.0",
+ "description": "Springwolf example project to demonstrate springwolfs abilities, including **markdown** support for descriptions.",
+ "contact": {
+ "name": "springwolf",
+ "url": "https://github.com/springwolf/springwolf-core",
+ "email": "example@example.com"
+ },
+ "license": {
+ "name": "Apache License 2.0"
+ },
+ "x-generator": "springwolf"
+ },
+ "defaultContentType": "application/json",
+ "servers": {
+ "kafka-server": {
+ "host": "kafka:29092",
+ "protocol": "kafka"
+ }
+ },
+ "channels": {
+ "vehicle-topic": {
+ "address": "vehicle-topic",
+ "messages": {
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": {
+ "$ref": "#/components/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ }
+ },
+ "bindings": {
+ "kafka": {
+ "bindingVersion": "0.5.0"
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "SpringKafkaDefaultHeaders-VehicleBase": {
+ "title": "SpringKafkaDefaultHeaders-VehicleBase",
+ "type": "object",
+ "properties": {
+ "__TypeId__": {
+ "type": "string",
+ "description": "Spring Type Id Header",
+ "enum": [
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ ],
+ "examples": [
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ ]
+ }
+ },
+ "examples": [
+ {
+ "__TypeId__": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ }
+ ],
+ "x-json-schema": {
+ "$schema": "https://json-schema.org/draft-04/schema#",
+ "properties": {
+ "__TypeId__": {
+ "description": "Spring Type Id Header",
+ "enum": [
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ ],
+ "type": "string"
+ }
+ },
+ "title": "SpringKafkaDefaultHeaders-VehicleBase",
+ "type": "object"
+ }
+ },
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": {
+ "discriminator": "vehicleType",
+ "title": "VehicleBase",
+ "type": "object",
+ "properties": {
+ "powerSource": {
+ "type": "string"
+ },
+ "topSpeed": {
+ "type": "integer",
+ "format": "int32"
+ },
+ "vehicleType": {
+ "type": "string"
+ }
+ },
+ "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)",
+ "examples": [
+ {
+ "powerSource": "string",
+ "topSpeed": 0,
+ "vehicleType": "string"
+ }
+ ],
+ "x-json-schema": {
+ "$schema": "https://json-schema.org/draft-04/schema#",
+ "description": "Demonstrates the use of discriminator for polymorphic deserialization (not publishable)",
+ "properties": {
+ "powerSource": {
+ "type": "string"
+ },
+ "topSpeed": {
+ "format": "int32",
+ "type": "integer"
+ },
+ "vehicleType": { }
+ },
+ "title": "VehicleBase",
+ "type": "object"
+ }
+ }
+ },
+ "messages": {
+ "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase": {
+ "headers": {
+ "$ref": "#/components/schemas/SpringKafkaDefaultHeaders-VehicleBase"
+ },
+ "payload": {
+ "schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0",
+ "schema": {
+ "$ref": "#/components/schemas/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ }
+ },
+ "name": "io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase",
+ "title": "VehicleBase",
+ "bindings": {
+ "kafka": {
+ "bindingVersion": "0.5.0"
+ }
+ }
+ }
+ }
+ },
+ "operations": {
+ "vehicle-topic_receive_receiveExamplePayload": {
+ "action": "receive",
+ "channel": {
+ "$ref": "#/channels/vehicle-topic"
+ },
+ "bindings": {
+ "kafka": {
+ "bindingVersion": "0.5.0"
+ }
+ },
+ "messages": [
+ {
+ "$ref": "#/channels/vehicle-topic/messages/io.github.springwolf.examples.kafka.dtos.discriminator.VehicleBase"
+ }
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/springwolf-examples/springwolf-kafka-example/src/test/resources/ui-config.json b/springwolf-examples/springwolf-kafka-example/src/test/resources/ui-config.json
new file mode 100644
index 000000000..e44f969cf
--- /dev/null
+++ b/springwolf-examples/springwolf-kafka-example/src/test/resources/ui-config.json
@@ -0,0 +1 @@
+{"groups":[{"name":"Only Vehicles"}]}
\ No newline at end of file
diff --git a/springwolf-ui/src/app/app.component.ts b/springwolf-ui/src/app/app.component.ts
index dfc2c28fe..19663f8dc 100644
--- a/springwolf-ui/src/app/app.component.ts
+++ b/springwolf-ui/src/app/app.component.ts
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: Apache-2.0 */
-import { Component, OnInit } from "@angular/core";
-import { UiService } from "./service/ui.service";
+import { Component } from "@angular/core";
@Component({
selector: "app-root",
diff --git a/springwolf-ui/src/app/app.module.ts b/springwolf-ui/src/app/app.module.ts
index 190022796..7bb7b291a 100644
--- a/springwolf-ui/src/app/app.module.ts
+++ b/springwolf-ui/src/app/app.module.ts
@@ -23,7 +23,7 @@ import { FormsModule } from "@angular/forms";
import { JsonComponent } from "./components/json/json.component";
import { AsyncApiMapperService } from "./service/asyncapi/asyncapi-mapper.service";
import { MarkdownModule, provideMarkdown } from "ngx-markdown";
-import { UiService } from "./service/ui.service";
+import { IUiService, UiService } from "./service/ui.service";
import { provideAnimationsAsync } from "@angular/platform-browser/animations/async";
import { SidenavComponent } from "./components/sidenav/sidenav.component";
import { NavigationTargetDirective } from "./components/sidenav/navigation.directive";
@@ -80,7 +80,7 @@ export const providers = [
AsyncApiMapperService,
{ provide: INotificationService, useClass: NotificationService },
PublisherService,
- UiService,
+ { provide: IUiService, useClass: UiService },
];
export const ngModule = {
diff --git a/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.spec.ts b/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.spec.ts
index 24d1a6266..160fce253 100644
--- a/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.spec.ts
+++ b/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.spec.ts
@@ -9,11 +9,13 @@ import {
mockedAsyncApiService,
mockedExampleSchemaMapped,
} from "../../../service/mock/mock-asyncapi.service";
+import { mockedUiService } from "../../../service/mock/mock-ui.service";
import {
MockAppJson,
MockAppSchemaNewComponent,
MockPrismEditorComponent,
} from "../../mock-components.spec";
+import { IUiService } from "../../../service/ui.service";
describe("ChannelOperationComponent", () => {
const mockData = mockedExampleSchemaMapped.channelOperations
@@ -31,6 +33,7 @@ describe("ChannelOperationComponent", () => {
],
imports: [MaterialModule, MarkdownModule.forRoot()],
providers: [
+ { provide: IUiService, useValue: mockedUiService },
{ provide: AsyncApiService, useValue: mockedAsyncApiService },
{ provide: PublisherService, useValue: {} },
],
diff --git a/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.ts b/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.ts
index d20193e6d..8a94fb6a1 100644
--- a/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.ts
+++ b/springwolf-ui/src/app/components/channels/channel-main/channel-operation.component.ts
@@ -14,7 +14,7 @@ import {
initSchema,
noExample,
} from "../../../service/mock/init-values";
-import { UiService } from "../../../service/ui.service";
+import { IUiService } from "../../../service/ui.service";
@Component({
selector: "app-channel-operation",
@@ -39,14 +39,14 @@ export class ChannelOperationComponent implements OnInit {
operationBindingExampleString?: string;
messageBindingExampleString?: string;
- isShowBindings: boolean = UiService.DEFAULT_SHOW_BINDINGS;
- isShowHeaders: boolean = UiService.DEFAULT_SHOW_HEADERS;
+ isShowBindings: boolean = IUiService.DEFAULT_SHOW_BINDINGS;
+ isShowHeaders: boolean = IUiService.DEFAULT_SHOW_HEADERS;
canPublish: boolean = false;
constructor(
private asyncApiService: AsyncApiService,
private publisherService: PublisherService,
- private uiService: UiService,
+ private uiService: IUiService,
private snackBar: MatSnackBar
) {}
diff --git a/springwolf-ui/src/app/components/channels/channels.component.spec.ts b/springwolf-ui/src/app/components/channels/channels.component.spec.ts
index 6e2a8343f..a9e4999c5 100644
--- a/springwolf-ui/src/app/components/channels/channels.component.spec.ts
+++ b/springwolf-ui/src/app/components/channels/channels.component.spec.ts
@@ -6,8 +6,13 @@ import {
mockedAsyncApiService,
mockedExampleSchemaMapped,
} from "../../service/mock/mock-asyncapi.service";
+import { mockedUiService } from "../../service/mock/mock-ui.service";
import { MaterialModule } from "../../material.module";
-import { MockChannelOperationComponent } from "../mock-components.spec";
+import {
+ MockChannelOperationComponent,
+ MockPrismEditorComponent,
+} from "../mock-components.spec";
+import { IUiService } from "../../service/ui.service";
describe("ChannelsNewComponent", () => {
beforeEach(async () => {
@@ -15,8 +20,9 @@ describe("ChannelsNewComponent", () => {
await render(ChannelsComponent, {
imports: [MaterialModule],
- declarations: [MockChannelOperationComponent],
+ declarations: [MockChannelOperationComponent, MockPrismEditorComponent],
providers: [
+ { provide: IUiService, useValue: mockedUiService },
{ provide: AsyncApiService, useValue: mockedAsyncApiService },
],
});
diff --git a/springwolf-ui/src/app/components/channels/channels.component.ts b/springwolf-ui/src/app/components/channels/channels.component.ts
index 4f58368ba..63ba6aaf1 100644
--- a/springwolf-ui/src/app/components/channels/channels.component.ts
+++ b/springwolf-ui/src/app/components/channels/channels.component.ts
@@ -2,7 +2,7 @@
import { Component, OnInit } from "@angular/core";
import { AsyncApiService } from "../../service/asyncapi/asyncapi.service";
import { Channel } from "../../models/channel.model";
-import { UiService } from "../../service/ui.service";
+import { IUiService } from "../../service/ui.service";
@Component({
selector: "app-channels",
@@ -11,12 +11,12 @@ import { UiService } from "../../service/ui.service";
})
export class ChannelsComponent implements OnInit {
channels: Channel[] = [];
- isShowBindings: boolean = UiService.DEFAULT_SHOW_BINDINGS;
+ isShowBindings: boolean = IUiService.DEFAULT_SHOW_BINDINGS;
JSON = JSON;
constructor(
private asyncApiService: AsyncApiService,
- private uiService: UiService
+ private uiService: IUiService
) {}
ngOnInit(): void {
diff --git a/springwolf-ui/src/app/components/header/header.component.html b/springwolf-ui/src/app/components/header/header.component.html
index 1b0ecb35d..019f4081d 100644
--- a/springwolf-ui/src/app/components/header/header.component.html
+++ b/springwolf-ui/src/app/components/header/header.component.html
@@ -18,11 +18,32 @@
{{ title }}
-