diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..b8903129 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,156 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0-EAP-3] - 2024-03-10 + +Kudos to: +- https://github.com/jaydeepk +- https://github.com/ctasada +- https://github.com/guillaumelamirand +- https://github.com/ivanalayan15 +- https://github.com/Crain-32 +- https://github.com/wrwks +- https://github.com/dennis-brinley + +### Added + +- AsyncAPI 3.0.0 + +### Changed + +- Reference was moved from `com.asyncapi.v2._6_0.model` to `com.asyncapi.v2` +- 2.0.0: + - `Schema.multipleOf` type was changed to `Number` +- 2.6.0: + - Specification: + - `AsyncAPI.servers` now can hold server objects and references + - `AsyncAPI.info` now has default value - empty Info object + - `AsyncAPI.channels` now has default value - empty map + - `Info.title` now has default value - empty string + - `Info.version` now has default value - empty string + - `License.name` now has default value - empty string + - `Server.url` now has default value - empty string + - `Server.protocol` now has default value - empty string + - `Tag.name` now has default value - empty string + - `CorrelationId.location` now has default value - empty string + - `OneOfMessages.oneOf` now has default value - empty list + - Bindings: + - AMQP: + - `AMQPChannelBinding.is` now `is required` and type was changed from `string` to `AMQPChannelType` enum and has default value - `routingKey` + - AMQP `ExchangeProperties` was extracted and renamed to `AMQPChannelExchangeProperties` + - AMQP `QueueProperties` was extracted and renamed to `AMQPChannelQueueProperties` + - Anypoint MQ: + - `AnypointMQChannelBinding.destinationType` was changed from `string` to `AnypointMQChannelDestinationType` with next default value - `queue` + - Google Pub/Sub: + - channels: + - `GooglePubSubChannelBinding.topic` now has default value - empty string + - `GooglePubSubChannelBinding.messageStoragePolicy` was extracted and renamed to `GooglePubSubChannelMessageStoragePolicy` + - `GooglePubSubChannelBinding.schemaSettings` was extracted and renamed to `GooglePubSubChannelSchemaSettings` + - `GooglePubSubChannelBinding.schemaSettings` now has default value - `GooglePubSubChannelSchemaSettings()` + - messages: + - `GooglePubSubMessageBinding.schema` was extracted and renamed to `GooglePubSubMessageSchemaDefinition` + - IBM MQ: + - channels: + - `IBMMQChannelBinding.destinationType` type was changed to `IBMMQChannelDestinationType` + - `IBMMQChannelBinding.destinationType` now has default value - `topic` + - `IBMMQChannelBinding.queue` was extracted and renamed to `IBMMQChannelQueueProperties` + - `IBMMQChannelBinding.topic` was extracted and renamed to `IBMMQChannelTopicProperties` + - `IBMMQChannelBinding.topic` was extracted and renamed to `IBMMQChannelTopicProperties` + - messages: + - `IBMMQMessageBinding.type` type was changed to `IBMMQMessageType` + - `IBMMQMessageBinding.type` now has default value - `string` + - `IBMMQMessageBinding.expiry` now has default value - `0` + - Kafka: + - channels: + - `KafkaChannelBinding.topicConfiguration` was extracted and renamed to `KafkaChannelTopicConfiguration` + - messages: + - `KafkaMessageBinding.key` type was changed to `Schema` + - `KafkaMessageBinding.schemaIdLocation` type was changed to `KafkaMessageSchemaIdLocation` + - operations: + - `KafkaOperationBinding.groupId` type was changed to `Schema` + - `KafkaOperationBinding.clientId` type was changed to `Schema` + - Pulsar: + - `PulsarChannelBinding.namespace` now has default value - empty string + - `PulsarChannelBinding.persistence` type was changed to `PulsarChannelPersistence` + - `PulsarChannelBinding.persistence` now has default value - `persistent` + - `PulsarChannelBinding.retention` was extracted and renamed to `PulsarChannelRetentionDefinition` + - WebSocket: + - `WebSocketsChannelBinding.method` type was changed to `WebSocketsChannelMethod` + - `WebSocketsChannelBinding.query` type was changed to `Schema` + - `WebSocketsChannelBinding.headers` type was changed to `Schema` + - Anypoint MQ: + - `AnypointMQMessageBinding.headers` type was changed to `Schema` + - HTTP: + - messages: + - `HTTPMessageBinding.headers` type was changed to `Schema` + - operations: + - `HTTPOperationBinding.type` type was changed to `HTTPOperationType` + - `HTTPOperationBinding.type` now has default value - `request` + - `HTTPOperationBinding.method` type was changed to `HTTPOperationMethod` + - `HTTPOperationBinding.query` type was changed to `Schema` + - Solace: + - operations: + - `SolaceOperationBinding.destinations` type was changed to `List` + - `SolaceDestination` was extracted end renamed to `SolaceOperationDestination` + - `SolaceQueue` was renamed to `SolaceOperationQueue` + - `SolaceTopic` was renamed to `SolaceOperationTopic` + - MQTT: + - servers: + - `LastWillConfiguration` was renamed to `MQTTServerLastWillConfiguration` + +### Fixed + +- Compiling warnings - https://github.com/asyncapi/jasyncapi/pull/152 +- Array schema is not being parsed correctly - https://github.com/asyncapi/jasyncapi/pull/159 + +## [1.0.0-EAP-2] - 2023-03-16 + +https://github.com/asyncapi/jasyncapi/pull/137 + +### Added + +- AsyncAPI 2.6.0 +- New Bindings +- New Security Schemes +- Specification components now can be extended with `x-*` + +### Changed + +- Bindings now are common for `2.6.0` and `2.0.0` +- Schema now is common for `2.6.0` and `2.0.0` +- Security Scheme now is common for `2.6.0` and `2.0.0` +- `Schema.additionalProperties` now can be `boolean` or `Schema` +- Schema.minimum, Schema.exclusiveMinimum, Schema.maximum, Schema.exclusiveMaximum now are BigDecimal: + - https://github.com/asyncapi/jasyncapi/issues/97 + - https://github.com/asyncapi/jasyncapi/issues/96 + +### Fixed + +- Specification components doesn't overrides given ObjectMapper - https://github.com/asyncapi/jasyncapi/issues/128 +- 2.0.0 - typo in Components serverBindings: ServerBinding instead of ServerBindingsDeserializer +- 2.0.0 - fixed typo in ServerVariable field name - example was renamed to examples +- Error while parsing of specifications when Reference was recognized as Schema + +## [1.0.0-EAP-1] - 2021-03-08 + +https://github.com/asyncapi/jasyncapi/pull/35 + +### Changed + +- `com.asyncapi.v2.schema.Schema` field `enumValues` was renamed to `enumValue` +- `com.asyncapi.v2.model.schema.Type` was changed to class +- Updated description of `examples` for `com.asyncapi.v2.model.channel.message.Message` + +## [1.0.0-EAP] - 2021-02-08 + +Initial release of AsyncAPI 2.0.0 + +https://github.com/asyncapi/jasyncapi/pull/31 + +### Added + +- AsyncAPI 2.0.0 \ No newline at end of file diff --git a/README.md b/README.md index 66ff100d..97d13f95 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ > ⚠️ This project doesn't support AsyncAPI 1.x --- -[![Version](https://img.shields.io/maven-central/v/com.asyncapi/asyncapi-core?logo=apache-maven)](https://search.maven.org/artifact/io.quarkiverse.asyncapi/quarkus-asyncapi) +[![Version](https://img.shields.io/maven-central/v/com.asyncapi/asyncapi-core?logo=apache-maven)](https://central.sonatype.com/artifact/com.asyncapi/asyncapi-core/1.0.0-EAP-3) ## Overview JVM-friendly bindings for AsyncAPI. It allows you to read or write specifications for your asynchronous API through code diff --git a/asyncapi-core/pom.xml b/asyncapi-core/pom.xml index 76314cda..ad3d103a 100644 --- a/asyncapi-core/pom.xml +++ b/asyncapi-core/pom.xml @@ -6,7 +6,7 @@ asyncapi com.asyncapi - 1.0.0-EAP-3-SNAPSHOT + 1.0.0-EAP-3 4.0.0 diff --git a/asyncapi-core/src/main/java/com/asyncapi/v2/schema/Schema.java b/asyncapi-core/src/main/java/com/asyncapi/v2/schema/Schema.java index c4937bc4..42c71db3 100644 --- a/asyncapi-core/src/main/java/com/asyncapi/v2/schema/Schema.java +++ b/asyncapi-core/src/main/java/com/asyncapi/v2/schema/Schema.java @@ -269,7 +269,7 @@ Validation Keywords for Numeric Instances (number and integer) */ @Nullable @JsonProperty - public Integer multipleOf; + public Number multipleOf; /** * The value of "maximum" MUST be a number, representing an inclusive upper limit for a numeric instance. diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AbstractExampleValidationTest.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AbstractExampleValidationTest.kt new file mode 100644 index 00000000..88f4f6cd --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AbstractExampleValidationTest.kt @@ -0,0 +1,93 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v3.ClasspathUtils +import com.asyncapi.v2._0_0.model.AsyncAPI +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test + +abstract class AbstractExampleValidationTest { + + private val objectMapper = ObjectMapper(YAMLFactory()) + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + + abstract fun specificationLocation(): String + + private fun specification(): AsyncAPI { + return objectMapper.readValue( + ClasspathUtils.readAsString(specificationLocation()), + AsyncAPI::class.java + ) + } + + open fun expectedId(): String? = null + + @Test + fun `ensure that id was read correctly`() { + Assertions.assertEquals( + specification().id, + expectedId(), + "id must be read correctly" + ) + } + + open fun expectedDefaultContentType(): String? = null + + @Test + fun `ensure that defaultContentType was read correctly`() { + Assertions.assertEquals( + specification().defaultContentType, + expectedDefaultContentType(), + "defaultContentType must be read correctly" + ) + } + + abstract fun expectedInfo(): Info + + @Test + fun `ensure that info was read correctly`() { + Assertions.assertEquals( + specification().info, + expectedInfo(), + "Info must be read correctly" + ) + } + + abstract fun expectedServers(): Map? + + @Test + fun `ensure that servers were read correctly`() { + Assertions.assertEquals( + specification().servers, + expectedServers(), + "Servers must be read correctly" + ) + } + + abstract fun expectedChannels(): Map + + @Test + fun `ensure that channels were read correctly`() { + Assertions.assertEquals( + specification().channels, + expectedChannels(), + "Channels must be read correctly" + ) + } + + abstract fun expectedComponents(): Components? + + @Test + fun `ensure that components were read correctly`() { + Assertions.assertEquals( + specification().components, + expectedComponents(), + "Components must be read correctly" + ) + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AnyOf.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AnyOf.kt new file mode 100644 index 00000000..4abfebc1 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/AnyOf.kt @@ -0,0 +1,76 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2.schema.Schema + +class AnyOf: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/anyof.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("AnyOf example") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map? = null + + override fun expectedChannels(): Map { + return mapOf( + Pair("test", ChannelItem.builder() + .publish(Operation.builder() + .message(Reference("#/components/messages/testMessages")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("testMessages", Message.builder() + .payload(Schema.builder() + .anyOf(listOf( + Schema.builder().ref("#/components/schemas/objectWithKey").build(), + Schema.builder().ref("#/components/schemas/objectWithKey2").build(), + )) + .build() + ) + .build() + ) + )) + .schemas(mapOf( + Pair("objectWithKey", Schema.builder() + .type("object") + .properties(mapOf( + Pair("key", Schema.builder() + .type("string") + .additionalProperties(false) + .build() + ) + )) + .build() + ), + Pair("objectWithKey2", Schema.builder() + .type("object") + .properties(mapOf( + Pair("key2", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/ApplicationHeaders.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/ApplicationHeaders.kt new file mode 100644 index 00000000..0655c2dc --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/ApplicationHeaders.kt @@ -0,0 +1,149 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.CorrelationId +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.info.License +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2._0_0.model.server.ServerVariable +import com.asyncapi.v2.schema.Schema +import java.math.BigDecimal + +class ApplicationHeaders: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/application-headers.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Application Headers example") + .version("1.0.0") + .description("A cut of the Streetlights API to test application header changes supporting") + .license(License( + "Apache 2.0", + "https://www.apache.org/licenses/LICENSE-2.0" + )) + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("test.mosquitto.org:{port}") + .protocol("mqtt") + .description("Test broker") + .variables(mapOf( + Pair("port", ServerVariable.builder() + .description("Secure connection (TLS) is available through port 8883.") + .defaultValue("1883") + .enumValues(listOf("1883", "8883")) + .build() + ) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured", ChannelItem.builder() + .parameters(mapOf( + Pair("streetlightId", Reference("#/components/parameters/streetlightId")) + )) + .publish(Operation.builder() + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .operationId("receiveLightMeasurement") + .message(Reference("#/components/messages/lightMeasured")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .correlationId(CorrelationId( + null, + "\$message.header#/MQMD/CorrelId" + )) + .contentType("application/json") + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("MQMD", Schema.builder() + .type("object") + .properties(mapOf( + Pair("CorrelId", Schema.builder() + .type("string") + .minLength(24) + .maxLength(24) + .format("binary") + .build() + ) + )) + .build() + ), + Pair("applicationInstanceId", Schema.builder() + .ref("#/components/schemas/applicationInstanceId") + .build() + ) + )) + .build() + ) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", Schema.builder() + .ref("#/components/schemas/sentAt") + .build() + ) + )) + .build() + ), + Pair("sentAt", Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ), + Pair("applicationInstanceId", Schema.builder() + .type("string") + .description("Unique identifier for a given instance of the publishing application") + .build() + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/CorrelationId.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/CorrelationId.kt new file mode 100644 index 00000000..34b04dde --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/CorrelationId.kt @@ -0,0 +1,230 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.CorrelationId +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.info.License +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2._0_0.model.server.ServerVariable +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.ApiKeySecurityScheme +import com.asyncapi.v2.security_scheme.OpenIdConnectSecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.flow.AuthorizationCodeOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ImplicitOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.PasswordOAuthFlow +import java.math.BigDecimal + +class CorrelationId: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/correlation-id.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Correlation ID Example") + .version("1.0.0") + .description("A cut of the Streetlights API to test Correlation ID") + .license(License( + "Apache 2.0", + "https://www.apache.org/licenses/LICENSE-2.0" + )) + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("test.mosquitto.org:{port}") + .protocol("mqtt") + .description("Test broker") + .variables(mapOf( + Pair("port", ServerVariable.builder() + .description("Secure connection (TLS) is available through port 8883.") + .defaultValue("1883") + .enumValues(listOf("1883", "8883")) + .build() + ) + )) + .security(listOf( + mapOf(Pair("apiKey", emptyList())), + mapOf(Pair("supportedOauthFlows", listOf( + "streetlights:on", "streetlights:off", "streetlights:dim" + ))), + mapOf(Pair("openIdConnectWellKnown", emptyList())), + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured", ChannelItem.builder() + .parameters(mapOf( + Pair("streetlightId", Reference("#/components/parameters/streetlightId")) + )) + .publish(Operation.builder() + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .operationId("receiveLightMeasurement") + .message(Reference("#/components/messages/lightMeasured")) + .build() + ) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/dim", ChannelItem.builder() + .parameters(mapOf( + Pair("streetlightId", Reference("#/components/parameters/streetlightId")) + )) + .subscribe(Operation.builder() + .operationId("dimLight") + .message(Reference("#/components/messages/dimLight")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .correlationId(CorrelationId( + null, + "\$message.header#/MQMD/CorrelId" + )) + .contentType("application/json") + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("dimLight", Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .correlationId(Reference("#/components/correlationIds/sentAtCorrelator")) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", Schema.builder() + .ref("#/components/schemas/sentAt") + .build() + ) + )) + .build() + ), + Pair("sentAt", Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ), + Pair("dimLightPayload", Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", Schema.builder() + .ref("#/components/schemas/sentAt") + .build() + ) + )) + .build() + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .correlationIds(mapOf( + Pair("sentAtCorrelator", CorrelationId( + "Data from message payload used as correlation ID", + "\$message.payload#/sentAt" + )) + )) + .securitySchemes(mapOf( + Pair("apiKey", ApiKeySecurityScheme( + "Provide your API key as the user and leave the password empty.", + ApiKeySecurityScheme.ApiKeyLocation.USER + )), + Pair("supportedOauthFlows", OAuth2SecurityScheme( + "Flows to support OAuth 2.0", + OAuthFlows( + ImplicitOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights"), + ), + "https://authserver.example/auth", + ), + PasswordOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights"), + ), + "https://authserver.example/token", + ), + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights"), + ), + "https://authserver.example/token", + ), + AuthorizationCodeOAuthFlow( + "https://authserver.example/refresh", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights"), + ), + "https://authserver.example/auth", + "https://authserver.example/token", + ) + ) + )), + Pair("openIdConnectWellKnown", OpenIdConnectSecurityScheme( + null, + "https://authserver.example/.well-known" + )) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/GitterStreaming.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/GitterStreaming.kt new file mode 100644 index 00000000..9a58f547 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/GitterStreaming.kt @@ -0,0 +1,305 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.message.http.HTTPMessageBinding +import com.asyncapi.v2.binding.operation.http.HTTPOperationBinding +import com.asyncapi.v2.binding.operation.http.HTTPOperationType +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.http.HttpSecurityScheme + +class GitterStreaming: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/gitter-streaming.yml" + + override fun expectedId(): String = "tag:stream.gitter.im,2022:api" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Gitter Streaming API") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("https://stream.gitter.im/v1") + .protocol("https") + .protocolVersion("1.1") + .security(listOf( + mapOf(Pair("httpBearerToken", emptyList())), + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("/rooms/{roomId}/{resource}", ChannelItem.builder() + .parameters(mapOf( + Pair("roomId", Parameter.builder() + .description("Id of the Gitter room.") + .schema(Schema.builder() + .type("string") + .examples(listOf("53307860c3599d1de448e19d")) + .build() + ) + .build() + ), + Pair("resource", Parameter.builder() + .description("The resource to consume.") + .schema(Schema.builder() + .type("string") + .enumValue(listOf("chatMessages", "events")) + .build() + ) + .build() + ) + )) + .subscribe(Operation.builder() + .bindings(mapOf( + Pair("http", HTTPOperationBinding.builder() + .type(HTTPOperationType.RESPONSE) + .build() + ) + )) + // TODO: add OneOfMessages for 2.0.0 + .message(Reference("#/components/messages/chatMessage")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .securitySchemes(mapOf( + Pair("httpBearerToken", HttpSecurityScheme( + null, + "bearer", + null, + )) + )) + .messages(mapOf( + Pair("chatMessage", Message.builder() + .schemaFormat("application/schema+yaml;version=draft-07") + .summary("A message represents an individual chat message sent to a room. They are a sub-resource of a room.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .description("ID of the message.") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .description("Original message in plain-text/markdown.") + .build() + ), + Pair("html", Schema.builder() + .type("string") + .description("HTML formatted message.") + .build() + ), + Pair("sent", Schema.builder() + .type("string") + .format("date-time") + .description("ISO formatted date of the message.") + .build() + ), + Pair("fromUser", Schema.builder() + .type("object") + .description("User that sent the message.") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .description("Gitter User ID.") + .build() + ), + Pair("username", Schema.builder() + .type("string") + .description("Gitter/GitHub username.") + .build() + ), + Pair("displayName", Schema.builder() + .type("string") + .description("Gitter/GitHub user real name.") + .build() + ), + Pair("url", Schema.builder() + .type("string") + .description("Path to the user on Gitter.") + .build() + ), + Pair("avatarUrl", Schema.builder() + .type("string") + .format("uri") + .description("User avatar URI.") + .build() + ), + Pair("avatarUrlSmall", Schema.builder() + .type("string") + .format("uri") + .description("User avatar URI (small).") + .build() + ), + Pair("avatarUrlMedium", Schema.builder() + .type("string") + .format("uri") + .description("User avatar URI (medium).") + .build() + ), + Pair("v", Schema.builder() + .type("number") + .description("Version.") + .build() + ), + Pair("gv", Schema.builder() + .type("string") + .description("Stands for \"Gravatar version\" and is used for cache busting.") + .build() + ) + )) + .build() + ), + Pair("unread", Schema.builder() + .type("boolean") + .description("Boolean that indicates if the current user has read the message.") + .build() + ), + Pair("readBy", Schema.builder() + .type("number") + .description("Number of users that have read the message.") + .build() + ), + Pair("urls", Schema.builder() + .type("array") + .description("List of URLs present in the message.") + .items(Schema.builder() + .type("string") + .format("uri") + .build()) + .build() + ), + Pair("mentions", Schema.builder() + .type("array") + .description("List of @Mentions in the message.") + .items(Schema.builder() + .type("object") + .properties(mapOf( + Pair("screenName", Schema.builder() + .type("string") + .build() + ), + Pair("userId", Schema.builder() + .type("string") + .build() + ), + Pair("userIds", Schema.builder() + .type("array") + .items(Schema.builder() + .type("string") + .build()) + .build() + ) + )) + .build()) + .build() + ), + Pair("issues", Schema.builder() + .type("array") + .description("List of #Issues referenced in the message.") + .items(Schema.builder() + .type("object") + .properties(mapOf( + Pair("number", Schema.builder().type("string").build()) + )) + .build()) + .build() + ), + Pair("meta", Schema.builder() + .type("array") + .description("Metadata. This is currently not used for anything.") + .items(Schema.builder().build()) + .build() + ), + Pair("v", Schema.builder() + .type("number") + .description("Version.") + .build() + ), + Pair("gv", Schema.builder() + .type("string") + .description("Stands for \"Gravatar version\" and is used for cache busting.") + .build() + ), + )) + .build() + ) + .bindings(mapOf( + Pair("http", HTTPMessageBinding.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("Transfer-Encoding", Schema.builder() + .type("string") + .constValue("chunked") + .build() + ), + Pair("Trailer", Schema.builder() + .type("string") + .constValue("\\r\\n") + .build() + ) + )) + .build() + ) + .build()) + )) + .build() + ), + Pair("heartbeat", Message.builder() + .schemaFormat("application/schema+yaml;version=draft-07") + .summary("Its purpose is to keep the connection alive.") + .payload(Schema.builder() + .type("string") + .enumValue(listOf("\r\n")) + .build() + ) + .bindings(mapOf( + Pair("http", HTTPMessageBinding.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("Transfer-Encoding", Schema.builder() + .type("string") + .constValue("chunked") + .build() + ), + Pair("Trailer", Schema.builder() + .type("string") + .constValue("\\r\\n") + .build() + ) + )) + .build() + ) + .build()) + )) + .build() + ), + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Mercure.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Mercure.kt new file mode 100644 index 00000000..20b03054 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Mercure.kt @@ -0,0 +1,107 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.ExternalDocumentation +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.schema.Schema + +class Mercure: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/mercure.yml" + + override fun expectedDefaultContentType(): String = "application/ld+json" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Mercure Hub Example") + .description("This example demonstrates how to define a Mercure hub.") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("https://demo.mercure.rocks/.well-known/mercure") + .protocol("mercure") + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("https://example.com/books/{id}", ChannelItem.builder() + .description("Every time a resource of type `http://schema.org/Book` is created or modified, a JSON-LD representation of the new version of this resource must be pushed in this Mercure topic.") + .parameters(mapOf( + Pair("id", Parameter.builder() + .schema(Schema.builder() + .type("integer") + .build() + ) + .build() + ) + )) + .subscribe(Operation.builder() + .message(Reference("#/components/messages/book")) + .build() + ) + .publish(Operation.builder() + .message(Reference("#/components/messages/book")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("book", Message.builder() + .summary("The content of a book resource.") + .externalDocs(ExternalDocumentation( + null, + "https://schema.org/Book" + )) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("@id", Schema.builder() + .type("string") + .format("iri-reference") + .build() + ), + Pair("@type", Schema.builder() + .type("string") + .format("iri-reference") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("isbn", Schema.builder() + .type("string") + .build() + ), + Pair("abstract", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Not.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Not.kt new file mode 100644 index 00000000..bc74b729 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Not.kt @@ -0,0 +1,59 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2.schema.Schema + +class Not: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/not.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Not example") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map? = null + + override fun expectedChannels(): Map { + return mapOf( + Pair("test", ChannelItem.builder() + .publish(Operation.builder() + .message(Reference("#/components/messages/testMessages")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("testMessages", Message.builder() + .payload(Schema.builder().ref("#/components/schemas/testSchema").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("testSchema", Schema.builder() + .type("object") + .properties(mapOf( + Pair("key", Schema.builder() + .not(Schema.builder().type("integer").build()) + .build() + ) + )) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OneOf.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OneOf.kt new file mode 100644 index 00000000..d37188e7 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OneOf.kt @@ -0,0 +1,93 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2.schema.Schema + +class OneOf: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/oneof.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("OneOf example") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map? = null + + override fun expectedChannels(): Map { + return mapOf( + Pair("test", ChannelItem.builder() + .publish(Operation.builder() + .message(Reference("#/components/messages/testMessages")) + .build() + ) + .build() + ), + Pair("test2", ChannelItem.builder() + .subscribe(Operation.builder() + // TODO: add OneOfMessage to 2.0.0 + .message(Message.builder() + .payload(Schema.builder().ref("#/components/schemas/objectWithKey").build()) + .build()) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("testMessages", Message.builder() + .payload(Schema.builder() + .oneOf(listOf( + Schema.builder().ref("#/components/schemas/objectWithKey").build(), + Schema.builder().ref("#/components/schemas/objectWithKey2").build() + )) + .build() + ) + .build() + ), + Pair("testMessage1", Message.builder() + .payload(Schema.builder().ref("#/components/schemas/objectWithKey").build()) + .build() + ), + Pair("testMessage2", Message.builder() + .payload(Schema.builder().ref("#/components/schemas/objectWithKey2").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("objectWithKey", Schema.builder() + .type("object") + .properties(mapOf( + Pair("key", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ), + Pair("objectWithKey2", Schema.builder() + .type("object") + .properties(mapOf( + Pair("key2", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OperationSecurity.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OperationSecurity.kt new file mode 100644 index 00000000..61a0dc3c --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/OperationSecurity.kt @@ -0,0 +1,197 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2.binding.operation.http.HTTPOperationBinding +import com.asyncapi.v2.binding.operation.http.HTTPOperationMethod +import com.asyncapi.v2.binding.operation.http.HTTPOperationType +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow + +class OperationSecurity: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/operation-security.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Notifications") + .version("1.0.0") + .description("This contract defines HTTP Push notification for application authorization revocation topic" + ) + .build() + } + + override fun expectedServers(): Map? = null + + override fun expectedChannels(): Map { + return mapOf( + Pair("AUTHORIZATION_REVOCATION", ChannelItem.builder() + .subscribe(Operation.builder() + .message(Reference("#/components/messages/message")) + .bindings(mapOf( + Pair("http", HTTPOperationBinding.builder() + .type(HTTPOperationType.REQUEST) + .method(HTTPOperationMethod.POST) + .build()) + )) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("message", Message.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("X-SIGNATURE", Schema.builder() + .type("string") + .description("ECC message signature") + .build() + ) + )) + .build() + ) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("metadata", Schema.builder() + .ref("#/components/schemas/MetaData") + .build() + ), + Pair("notification", Schema.builder() + .ref("#/components/schemas/Notification") + .build() + ) + )) + .build() + ) + .build() + ) + )) + .schemas(mapOf( + Pair("MetaData", Schema.builder() + .type("object") + .properties(mapOf( + Pair("topic", Schema.builder() + .type("string") + .description("Topic subscribed to.") + .build() + ), + Pair("schemaVersion", Schema.builder() + .type("string") + .description("The schema for this topic.") + .build() + ), + Pair("deprecated", Schema.builder() + .type("boolean") + .description("If this is a deprecated schema or topic.") + .defaultValue("false") + .build() + ) + )) + .build() + ), + Pair("Notification", Schema.builder() + .type("object") + .properties(mapOf( + Pair("notificationId", Schema.builder() + .type("string") + .description("The notification Id.") + .build() + ), + Pair("eventDate", Schema.builder() + .type("string") + .description("The event date associated with this notification in UTC.") + .build() + ), + Pair("publishDate", Schema.builder() + .type("string") + .description("The message publish date in UTC.") + .build() + ), + Pair("publishAttemptCount", Schema.builder() + .type("integer") + .description("The number of attempts made to publish this message.") + .build() + ), + Pair("publishAttemptCount", Schema.builder() + .type("integer") + .description("The number of attempts made to publish this message.") + .build() + ), + Pair("data", Schema.builder() + .ref("#/components/schemas/AuthorizationRevocationData") + .build() + ) + )) + .build() + ), + Pair("AuthorizationRevocationData", Schema.builder() + .type("object") + .description("The Authorization Revocation payload.") + .properties(mapOf( + Pair("username", Schema.builder() + .type("string") + .description("The username for the user.") + .build() + ), + Pair("userId", Schema.builder() + .type("string") + .description("The immutable public userId for the user") + .build() + ), + Pair("eiasToken", Schema.builder() + .type("string") + .description("The legacy eiasToken specific to the user") + .build() + ), + Pair("revokeReason", Schema.builder() + .type("string") + .enumValue(listOf( + "REVOKED_BY_APP", + "REVOKED_BY_USER", + "REVOKED_BY_ADMIN", + "PASSWORD_CHANGE" + )) + .description("The reason for authorization revocation") + .build() + ), + Pair("revocationDate", Schema.builder() + .type("string") + .description("Date and time when the authorization was revoked") + .build() + ) + )) + .build() + ), + )) + .securitySchemes(mapOf( + Pair("petstore_auth", OAuth2SecurityScheme( + "The oauth security descriptions", + OAuthFlows( + null, + null, + ClientCredentialsOAuthFlow( + "", + mapOf(Pair("subscribe:auth_revocations", "Scope required for authorization revocation topic")), + "https://example.com/api/oauth/dialog" + ), + null + ), + )) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcClient.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcClient.kt new file mode 100644 index 00000000..d9f43432 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcClient.kt @@ -0,0 +1,135 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.CorrelationId +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.channel.amqp.AMQPChannelBinding +import com.asyncapi.v2.binding.channel.amqp.AMQPChannelType +import com.asyncapi.v2.binding.channel.amqp.queue.AMQPChannelQueueProperties +import com.asyncapi.v2.binding.operation.amqp.AMQPOperationBinding +import com.asyncapi.v2.schema.Schema + +class RpcClient: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/rpc-client.yml" + + override fun expectedId(): String = "urn:example:rpcclient" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info.builder() + .title("RPC Client Example") + .version("1.0.0") + .description("This example demonstrates how to define an RPC client." + ) + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("rabbitmq.example.org") + .protocol("amqp") + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("{queue}", ChannelItem.builder() + .parameters(mapOf( + Pair("queue", Parameter.builder() + .schema(Schema.builder() + .type("string") + .pattern("^amq\\\\.gen\\\\-.+\$") + .build()) + .build() + ), + )) + .bindings(mapOf( + Pair("amqp", AMQPChannelBinding.builder() + .`is`(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .exclusive(true) + .build() + ) + .build() + ) + )) + .publish(Operation.builder() + .operationId("receiveSumResult") + .bindings(mapOf( + Pair("amqp", AMQPOperationBinding.builder() + .ack(false) + .build() + ) + )) + .message(Message.builder() + .correlationId(CorrelationId(null, "\$message.header#/correlation_id")) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("result", Schema.builder() + .type("number") + .examples(listOf(7)) + .build()) + )) + .build() + ) + .build() + ) + .build() + ) + .build() + ), + Pair("rpc_queue", ChannelItem.builder() + .bindings(mapOf( + Pair("amqp", AMQPChannelBinding.builder() + .`is`(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .durable(false) + .build() + ) + .build() + ) + )) + .subscribe(Operation.builder() + .operationId("requestSum") + .bindings(mapOf( + Pair("amqp", AMQPOperationBinding.builder() + .ack(true) + .build() + ) + )) + .message(Message.builder() + .correlationId(CorrelationId(null, "\$message.header#/correlation_id")) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("numbers", Schema.builder() + .type("array") + .items(Schema.builder().type("number").build()) + .examples(listOf(listOf(4, 3))) + .build()) + )) + .build() + ) + .build() + ) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? = null + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcServer.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcServer.kt new file mode 100644 index 00000000..01f305a7 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/RpcServer.kt @@ -0,0 +1,129 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.CorrelationId +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.channel.amqp.AMQPChannelBinding +import com.asyncapi.v2.binding.channel.amqp.AMQPChannelType +import com.asyncapi.v2.binding.channel.amqp.queue.AMQPChannelQueueProperties +import com.asyncapi.v2.binding.operation.amqp.AMQPOperationBinding +import com.asyncapi.v2.schema.Schema + +class RpcServer: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/rpc-server.yml" + + override fun expectedId(): String = "urn:example:rpcserver" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info.builder() + .title("RPC Server Example") + .version("1.0.0") + .description("This example demonstrates how to define an RPC server." + ) + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", Server.builder() + .url("rabbitmq.example.org") + .protocol("amqp") + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("{queue}", ChannelItem.builder() + .parameters(mapOf( + Pair("queue", Parameter.builder() + .schema(Schema.builder() + .type("string") + .pattern("^amq\\\\.gen\\\\-.+\$") + .build()) + .build() + ), + )) + .bindings(mapOf( + Pair("amqp", AMQPChannelBinding.builder() + .`is`(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .exclusive(true) + .build() + ) + .build() + ) + )) + .subscribe(Operation.builder() + .operationId("sendSumResult") + .bindings(mapOf( + Pair("amqp", AMQPOperationBinding.builder() + .ack(true) + .build() + ) + )) + .message(Message.builder() + .correlationId(CorrelationId(null, "\$message.header#/correlation_id")) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("result", Schema.builder() + .type("number") + .examples(listOf(7)) + .build()) + )) + .build() + ) + .build() + ) + .build() + ) + .build() + ), + Pair("rpc_queue", ChannelItem.builder() + .bindings(mapOf( + Pair("amqp", AMQPChannelBinding.builder() + .`is`(AMQPChannelType.QUEUE) + .queue(AMQPChannelQueueProperties.builder() + .durable(false) + .build() + ) + .build() + ) + )) + .publish(Operation.builder() + .operationId("sum") + .message(Message.builder() + .correlationId(CorrelationId(null, "\$message.header#/correlation_id")) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("numbers", Schema.builder() + .type("array") + .items(Schema.builder().type("number").build()) + .examples(listOf(listOf(4, 3))) + .build()) + )) + .build() + ) + .build() + ) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? = null + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Simple.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Simple.kt new file mode 100644 index 00000000..26eb0567 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/Simple.kt @@ -0,0 +1,64 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2.schema.Schema + +class Simple: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/simple.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Account Service") + .version("1.0.0") + .description("This service is in charge of processing user signups") + .build() + } + + override fun expectedServers(): Map? = null + + override fun expectedChannels(): Map { + return mapOf( + Pair("user/signedup", ChannelItem.builder() + .subscribe(Operation.builder() + .message(Reference("#/components/messages/UserSignedUp")) + .build() + ) + .build() + ), + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("UserSignedUp", Message.builder() + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("displayName", Schema.builder() + .type("string") + .description("Name of the user") + .build() + ), + Pair("email", Schema.builder() + .type("string") + .format("email") + .description("Email of the user") + .build() + ) + )) + .build() + ) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/SlackRtm.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/SlackRtm.kt new file mode 100644 index 00000000..fa086a3e --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/SlackRtm.kt @@ -0,0 +1,1523 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.http.HttpApiKeySecurityScheme + +class SlackRtm: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/slack-rtm.yml" + + override fun expectedId(): String = "wss://wss-primary.slack.com/websocket" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Slack Real Time Messaging API") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", + Server.builder() + .url("https://slack.com/api/rtm.connect") + .protocol("https") + .protocolVersion("1.1") + .security(listOf( + mapOf(Pair("token", emptyList())) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("/", + ChannelItem.builder() + .publish(Operation.builder() + .message(Reference("#/components/messages/outgoingMessage")) + .build() + ) + .subscribe(Operation.builder() + // TODO: add OneOfMessage to 2.0.0 + .message(Reference("#/components/messages/hello")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .securitySchemes(mapOf( + Pair("token", HttpApiKeySecurityScheme( + null, + "token", + HttpApiKeySecurityScheme.ApiKeyLocation.QUERY + )) + )) + .schemas(mapOf( + Pair("attachment", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("fallback", Schema.builder() + .type("string") + .build() + ), + Pair("color", Schema.builder() + .type("string") + .build() + ), + Pair("pretext", Schema.builder() + .type("string") + .build() + ), + Pair("author_name", Schema.builder() + .type("string") + .build() + ), + Pair("author_link", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("author_icon", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("title", Schema.builder() + .type("string") + .build() + ), + Pair("title_link", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + Pair("fields", Schema.builder() + .type("array") + .items(Schema.builder() + .type("object") + .properties(mapOf( + Pair("title", Schema.builder() + .type("string") + .build() + ), + Pair("value", Schema.builder() + .type("string") + .build() + ), + Pair("short", Schema.builder() + .type("boolean") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("image_url", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("thumb_url", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("footer", Schema.builder() + .type("string") + .build() + ), + Pair("footer_icon", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("ts", Schema.builder() + .type("number") + .build() + ), + )) + .build() + ) + )) + .messages(mapOf( + Pair("hello", + Message.builder() + .summary("First event received upon connection.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("hello")) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("connectionError", + Message.builder() + .summary("Event received when a connection error happens.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("error")) + .build() + ), + Pair("error", Schema.builder() + .type("object") + .properties(mapOf( + Pair("code", Schema.builder().type("number").build()), + Pair("msg", Schema.builder().type("string").build()), + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("accountsChanged", + Message.builder() + .summary("The list of accounts a user is signed into has changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("accounts_changed")) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("botAdded", + Message.builder() + .summary("A bot user was added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("bot_added")) + .build() + ), + Pair("bot", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("app_id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("icons", Schema.builder() + .type("object") + .additionalProperties(Schema.builder().type("string").build()) + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("botChanged", + Message.builder() + .summary("A bot user was changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("bot_added")) + .build() + ), + Pair("bot", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("app_id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("icons", Schema.builder() + .type("object") + .additionalProperties(Schema.builder().type("string").build()) + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelArchive", + Message.builder() + .summary("A channel was archived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_archive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("channelCreated", + Message.builder() + .summary("A channel was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_created")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelDeleted", + Message.builder() + .summary("A channel was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_deleted")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelHistoryChanged", + Message.builder() + .summary("Bulk updates were made to a channel's history.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_history_changed")) + .build() + ), + Pair("latest", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelJoined", + Message.builder() + .summary("You joined a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_joined")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelLeft", + Message.builder() + .summary("You left a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_left")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelMarked", + Message.builder() + .summary("Your channel read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelRename", + Message.builder() + .summary("A channel was renamed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_rename")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("channelUnarchive", + Message.builder() + .summary("A channel was unarchived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_unarchive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("commandsChanged", + Message.builder() + .summary("A slash command has been added or changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("commands_changed")) + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("dndUpdated", + Message.builder() + .summary("Do not Disturb settings changed for the current user.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("dnd_updated")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("dnd_status", Schema.builder() + .type("object") + .properties(mapOf( + Pair("dnd_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("next_dnd_start_ts", Schema.builder() + .type("number") + .build() + ), + Pair("next_dnd_end_ts", Schema.builder() + .type("number") + .build() + ), + Pair("snooze_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("snooze_endtime", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("dndUpdatedUser", + Message.builder() + .summary("Do not Disturb settings changed for a member.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("dnd_updated_user")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("dnd_status", Schema.builder() + .type("object") + .properties(mapOf( + Pair("dnd_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("next_dnd_start_ts", Schema.builder() + .type("number") + .build() + ), + Pair("next_dnd_end_ts", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("emailDomainChanged", + Message.builder() + .summary("The workspace email domain has changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("email_domain_changed")) + .build() + ), + Pair("email_domain", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("emojiRemoved", + Message.builder() + .summary("A custom emoji has been removed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("emoji_changed")) + .build() + ), + Pair("subtype", Schema.builder() + .type("string") + .enumValue(listOf("remove")) + .build() + ), + Pair("names", Schema.builder() + .type("array") + .items(Schema.builder().type("string").build()) + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("emojiAdded", + Message.builder() + .summary("A custom emoji has been added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("emoji_changed")) + .build() + ), + Pair("subtype", Schema.builder() + .type("string") + .enumValue(listOf("add")) + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("value", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileChange", + Message.builder() + .summary("A file was changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_change")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentAdded", + Message.builder() + .summary("A file comment was added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_added")) + .build() + ), + Pair("comment", Schema()), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentDeleted", + Message.builder() + .summary("A file comment was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_deleted")) + .build() + ), + Pair("comment", Schema.builder() + .type("string") + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentEdited", + Message.builder() + .summary("A file comment was edited.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_edited")) + .build() + ), + Pair("comment", Schema()), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCreated", + Message.builder() + .summary("A file was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_created")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileDeleted", + Message.builder() + .summary("A file was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_deleted")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("filePublic", + Message.builder() + .summary("A file was made public.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_public")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileShared", + Message.builder() + .summary("A file was shared.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_shared")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileUnshared", + Message.builder() + .summary("A file was unshared.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_unshared")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("goodbye", + Message.builder() + .summary("The server intends to close the connection soon.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("goodbye")) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupArchive", + Message.builder() + .summary("A private channel was archived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_archive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupClose", + Message.builder() + .summary("You closed a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_close")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupHistoryChanged", + Message.builder() + .summary("Bulk updates were made to a private channel's history.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_history_changed")) + .build() + ), + Pair("latest", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupJoined", + Message.builder() + .summary("You joined a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_joined")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupLeft", + Message.builder() + .summary("You left a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_left")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupMarked", + Message.builder() + .summary("A private channel read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupOpen", + Message.builder() + .summary("You opened a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_open")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupRename", + Message.builder() + .summary("A private channel was renamed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_rename")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupUnarchive", + Message.builder() + .summary("A private channel was unarchived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_unarchive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imClose", + Message.builder() + .summary("You closed a DM.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_close")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imCreated", + Message.builder() + .summary("A DM was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_created")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imMarked", + Message.builder() + .summary("A direct message read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imOpen", + Message.builder() + .summary("You opened a DM.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_open")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("manualPresenceChange", + Message.builder() + .summary("You manually updated your presence.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("manual_presence_change")) + .build() + ), + Pair("presence", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("memberJoinedChannel", + Message.builder() + .summary("A user joined a public or private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("member_joined_channel")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("channel_type", Schema.builder() + .type("string") + .enumValue(listOf("C", "G")) + .build() + ), + Pair("team", Schema.builder() + .type("string") + .build() + ), + Pair("inviter", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("memberLeftChannel", + Message.builder() + .summary("A user left a public or private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("member_left_channel")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("channel_type", Schema.builder() + .type("string") + .enumValue(listOf("C", "G")) + .build() + ), + Pair("team", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("message", + Message.builder() + .summary("A message was sent to a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("message")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("attachments", Schema.builder() + .type("array") + .items(Schema.builder().ref("#/components/schemas/attachment").build()) + .build() + ), + Pair("edited", Schema.builder() + .type("object") + .properties(mapOf( + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("outgoingMessage", + Message.builder() + .summary("A message was sent to a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("message")) + .build() + ), + Pair("id", Schema.builder() + .type("number") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsKafka.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsKafka.kt new file mode 100644 index 00000000..3d4e273d --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsKafka.kt @@ -0,0 +1,261 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.Tag +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.message.MessageTrait +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.info.License +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.operation.kafka.KafkaOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.SecurityScheme +import java.math.BigDecimal + +class StreetlightsKafka: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/streetlights-kafka.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info( + "Streetlights Kafka API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0"), + ) + } + + override fun expectedServers(): Map { + return mapOf( + Pair("scram-connections", Server.builder() + .url("test.mykafkacluster.org:18092") + .protocol("kafka-secure") + .description("Test broker secured with scramSha256") + .security(listOf( + mapOf(Pair("saslScram", emptyList())) + )) + .build() + ), + Pair("mtls-connections", Server.builder() + .url("test.mykafkacluster.org:28092") + .protocol("kafka-secure") + .description("Test broker secured with X509") + .security(listOf( + mapOf(Pair("certs", emptyList())) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/dimLight")) + .build()) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("saslScram", + SecurityScheme.builder() + .type(SecurityScheme.Type.SCRAM_SHA256) + .description("Provide your username and password for SASL/SCRAM authentication") + .build() + ), + Pair("certs", + SecurityScheme( + SecurityScheme.Type.X509, + "Download the certificate files from service provider" + ) + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("kafka", + OperationTrait.builder() + .bindings(mapOf( + Pair("kafka", KafkaOperationBinding.builder() + .clientId(Schema.builder() + .type("string") + .enumValue(listOf("my-app-id")) + .build() + ) + .build() + ) + )) + .build() + ) + )) + .build() + } +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsMQTT.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsMQTT.kt new file mode 100644 index 00000000..0ceb940d --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsMQTT.kt @@ -0,0 +1,309 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.Tag +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.message.MessageTrait +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.info.License +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2._0_0.model.server.ServerVariable +import com.asyncapi.v2.binding.operation.mqtt.MQTTOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.ApiKeySecurityScheme +import com.asyncapi.v2.security_scheme.OpenIdConnectSecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.flow.AuthorizationCodeOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ImplicitOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.PasswordOAuthFlow +import java.math.BigDecimal + +class StreetlightsMQTT: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/streetlights-mqtt.yml" + + override fun expectedInfo(): Info { + return Info( + "Streetlights MQTT API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0") + ) + } + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedServers(): Map { + return mapOf( + Pair("production", + Server.builder() + .url("test.mosquitto.org:{port}") + .protocol("mqtt") + .description("Test broker") + .variables(mapOf( + Pair("port", + ServerVariable.builder() + .description("Secure connection (TLS) is available through port 8883.") + .defaultValue("1883") + .enumValues(listOf("1883", "8883")) + .build() + ) + )) + .security(listOf( + mapOf(Pair("apiKey", emptyList())), + mapOf(Pair("supportedOauthFlows", listOf( + "streetlights:on", + "streetlights:off", + "streetlights:dim", + ))), + mapOf(Pair("openIdConnectWellKnown", emptyList())), + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/turn/on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/turn/off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/dimLight")) + .build()) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("apiKey", + ApiKeySecurityScheme("Provide your API key as the user and leave the password empty.", ApiKeySecurityScheme.ApiKeyLocation.USER) + ), + Pair("supportedOauthFlows", + OAuth2SecurityScheme( + "Flows to support OAuth 2.0", + OAuthFlows( + ImplicitOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/auth" + ), + PasswordOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/token" + ), + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/token" + ), + AuthorizationCodeOAuthFlow( + "https://authserver.example/refresh", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/auth", + "https://authserver.example/token" + ) + ) + ) + ), + Pair("openIdConnectWellKnown", OpenIdConnectSecurityScheme(null, "https://authserver.example/.well-known")) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("mqtt", + OperationTrait.builder() + .bindings(mapOf( + Pair("mqtt", MQTTOperationBinding.builder() + .qos(1) + .build() + ) + )) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsOperationSecurity.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsOperationSecurity.kt new file mode 100644 index 00000000..bac1cb5c --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/StreetlightsOperationSecurity.kt @@ -0,0 +1,281 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.Tag +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.message.MessageTrait +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.info.License +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.operation.kafka.KafkaOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow +import java.math.BigDecimal + +class StreetlightsOperationSecurity: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/streetlights-operation-security.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info( + "Streetlights Kafka API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0"), + ) + } + + override fun expectedServers(): Map { + return mapOf( + Pair("test", Server.builder() + .url("test.mykafkacluster.org:8092") + .protocol("kafka-secure") + .description("Test broker") + .security(listOf( + mapOf(Pair("saslScram", emptyList())) + )) + .build() + ), + Pair("test_oauth", Server.builder() + .url("test.mykafkacluster.org:8093") + .protocol("kafka-secure") + .description("Test port for oauth") + .security(listOf( + mapOf(Pair("streetlights_auth", listOf( + "streetlights:write", + "streetlights:read" + ))) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build() + ) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/dimLight")) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("saslScram", + SecurityScheme.builder() + .type(SecurityScheme.Type.SCRAM_SHA256) + .description("Provide your username and password for SASL/SCRAM authentication") + .build() + ), + Pair("streetlights_auth", + OAuth2SecurityScheme( + "The oauth security descriptions", + OAuthFlows( + null, + null, + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("streetlights:read", "Scope required for subscribing to channel"), + Pair("streetlights:write", "Scope required for publishing to channel"), + ), + "https://example.com/api/oauth/dialog", + ), + null, + ) + ) + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("kafka", + OperationTrait.builder() + .bindings(mapOf( + Pair("kafka", KafkaOperationBinding.builder() + .clientId(Schema.builder() + .type("string") + .enumValue(listOf("my-app-id")) + .build() + ) + .build() + ) + )) + .build() + ) + )) + .build() + } +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/WebsocketGemini.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/WebsocketGemini.kt new file mode 100644 index 00000000..e72c9331 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_0_0/WebsocketGemini.kt @@ -0,0 +1,394 @@ +package com.asyncapi.examples.v2._0_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._0_0.model.channel.ChannelItem +import com.asyncapi.v2._0_0.model.channel.Parameter +import com.asyncapi.v2._0_0.model.channel.message.Message +import com.asyncapi.v2._0_0.model.channel.operation.Operation +import com.asyncapi.v2._0_0.model.component.Components +import com.asyncapi.v2._0_0.model.info.Contact +import com.asyncapi.v2._0_0.model.info.Info +import com.asyncapi.v2._0_0.model.server.Server +import com.asyncapi.v2.binding.channel.ws.WebSocketsChannelBinding +import com.asyncapi.v2.schema.Schema + +class WebsocketGemini: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.0.0/websocket-gemini.yml" + + override fun expectedInfo(): Info { + return Info( + "Gemini Market Data Websocket API", + "1.0.0", + """ + Market data is a public API that streams all the market data on a given symbol. + + You can quickly play with the API using [websocat](https://github.com/vi/websocat#installation) like this: + ```bash + websocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S + ``` + + """.trimIndent(), + null, + Contact("Gemini", "https://www.gemini.com/", null), + null, + ) + } + + override fun expectedServers(): Map { + return mapOf(Pair("public", Server.builder().url("wss://api.gemini.com").protocol("wss").build())) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("/v1/marketdata/{symbol}", + ChannelItem.builder() + .subscribe(Operation.builder() + .summary("Receive market updates on a given symbol") + .message(Reference("#/components/messages/marketData")) + .build()) + .parameters( + mapOf( + Pair("symbol", + Parameter.builder() + .schema(Schema.builder() + .type("string") + .enumValue(listOf( + "btcusd", + "ethbtc", + "ethusd", + "zecusd", + "zecbtc", + "zeceth", + "zecbch", + "zecltc", + "bchusd", + "bchbtc", + "bcheth", + "ltcusd", + "ltcbtc", + "ltceth", + "ltcbch", + "batusd", + "daiusd", + "linkusd", + "oxtusd", + "batbtc", + "linkbtc", + "oxtbtc", + "bateth", + "linketh", + "oxteth", + "ampusd", + "compusd", + "paxgusd", + "mkrusd", + "zrxusd", + "kncusd", + "manausd", + "storjusd", + "snxusd", + "crvusd", + "balusd", + "uniusd", + "renusd", + "umausd", + "yfiusd", + "btcdai", + "ethdai", + "aaveusd", + "filusd", + "btceur", + "btcgbp", + "etheur", + "ethgbp", + "btcsgd", + "ethsgd", + "sklusd", + "grtusd", + "bntusd", + "1inchusd", + "enjusd", + "lrcusd", + "sandusd", + "cubeusd", + "lptusd", + "bondusd", + "maticusd", + "injusd", + "sushiusd" + )) + .build() + ) + .description( + "Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. To read more click [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums).\n" + ) + .build() + ) + ) + ) + .bindings( + mapOf( + Pair( + "ws", + WebSocketsChannelBinding.builder() + .query( + Schema.builder() + .type("object") + .description( + "The semantics of entry type filtering is:\n" + + "\n" + + "If any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response\n" + + "If no entry types filtering parameters are included in the url, then all entry types will appear in the response\n" + + "\n" + + "NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified\n" + ) + .properties(mapOf( + Pair( + "heartbeat", + Schema.builder() + .type("boolean") + .defaultValue(false) + .description( + "Optionally add this parameter and set to true to receive a " + + "heartbeat every 5 seconds" + ) + .build() + ), + Pair( + "top_of_book", + Schema.builder() + .type("boolean") + .defaultValue(false) + .description( + "If absent or false, receive full order book depth; if present " + + "and true, receive top of book only. Only applies to bids and " + + "offers." + ) + .build() + ), + Pair( + "bids", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include bids in change events") + .build() + ), + Pair( + "offers", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include asks in change events") + .build() + ), + Pair( + "trades", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include trade events") + .build() + ), + Pair( + "auctions", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include auction events") + .build() + ) + )) + .build() + ) + .build() + ) + ) + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair( + "marketData", + Message.builder() + .summary("Message with marked data information.") + .description( + "The initial response message will show the existing state of the order book. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled.\n" + ) + .payload(Schema.builder().ref("#/components/schemas/market").build()) + .examples(listOf( + mapOf( + Pair("name", "updateMessage"), + Pair("summary", "Example of an update message that contains a change in price information."), + Pair("payload", mapOf( + Pair("type", "update"), + Pair("eventId", 36902233362), + Pair("timestamp", 1619769673), + Pair("timestampms", 1619769673527), + Pair("socket_sequence", 661), + Pair("events", listOf(mapOf( + Pair("type", "change"), + Pair("side", "bid"), + Pair("price", 54350.40), + Pair("remaining", 0.002), + Pair("delta", 0.002), + Pair("reason", "place") + ))), + )) + ), + mapOf( + Pair("name", "heartbeatMessage"), + Pair("summary", "Example of additional heartbeat message when you enable them."), + Pair("payload", mapOf( + Pair("type", "heartbeat"), + Pair("socket_sequence", 1656) + )), + ) + )) + .build() + ) + )) + .schemas(mapOf( + Pair("market", Schema.builder() + .type("object") + .oneOf(listOf( + Schema.builder().ref("#/components/schemas/heartbeat").build(), + Schema.builder().ref("#/components/schemas/update").build(), + )) + .build() + ), + Pair("heartbeat", Schema.builder() + .allOf(listOf( + Schema.builder() + .properties(mapOf( + Pair("type", Schema.builder().type("string").constValue("heartbeat").build()) + )) + .required(listOf("type")) + .build(), + Schema.builder() + .ref("#/components/schemas/default") + .build(), + )) + .build() + ), + Pair("update", Schema.builder() + .allOf(listOf( + Schema.builder() + .properties(mapOf( + Pair("type", Schema.builder().type("string").constValue("update").build()), + Pair("eventId", Schema.builder() + .type("integer") + .description( + "A monotonically increasing sequence number indicating when this " + + "change occurred. These numbers are persistent and consistent " + + "between market data connections." + ) + .build() + ), + Pair("events", Schema.builder().ref("#/components/schemas/events").build()), + Pair("timestamp", Schema.builder() + .type("number") + .description( + "The timestamp in seconds for this group of events (included for " + + "compatibility reasons). We recommend using the timestampms field " + + "instead." + ) + .build() + ), + Pair("timestampms", Schema.builder() + .type("number") + .description("The timestamp in milliseconds for this group of events.") + .build() + ), + )) + .required(listOf("type", "eventId", "events", "timestamp", "timestampms")) + .build(), + Schema.builder().ref("#/components/schemas/default").build(), + )) + .build() + ), + Pair("default", Schema.builder() + .type("object") + .description( + "This object is always part of the payload. In case of type=heartbeat, " + + "these are the only fields.") + .required(listOf("type", "socket_sequence")) + .properties(mapOf( + Pair("socket_sequence", Schema.builder() + .type("integer") + .description( + "zero-indexed monotonic increasing sequence number attached to each " + + "message sent - if there is a gap in this sequence, you have missed a " + + "message. If you choose to enable heartbeats, then heartbeat and " + + "update messages will share a single increasing sequence. See " + + "[Sequence Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers) " + + "for more information." + ) + .build() + ) + )) + .build() + ), + Pair("events", Schema.builder() + .type("array") + .description("Either a change to the order book, or the indication that a trade has occurred.") + .items(Schema.builder() + .type("object") + .additionalProperties(false) + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("trade", "change", "auction, block_trade")) + .build() + ), + Pair("price", Schema.builder() + .type("number") + .multipleOf(0.01) + .description("The price of this order book entry.") + .build() + ), + Pair("side", Schema.builder() + .type("string") + .enumValue(listOf("bid", "side")) + .build() + ), + Pair("reason", Schema.builder() + .type("string") + .enumValue(listOf("place", "trade", "cancel", "initial")) + .description( + "Indicates why the change has occurred. initial is for the initial " + + "response message, which will show the entire existing state of the " + + "order book." + ) + .build() + ), + Pair("remaining", Schema.builder() + .type("number") + .description( + "The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled." + ) + .build() + ), + Pair("delta", Schema.builder() + .type("number") + .description( + "The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining." + ) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/SlackRtm.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/SlackRtm.kt new file mode 100644 index 00000000..f1fc2791 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/SlackRtm.kt @@ -0,0 +1,1570 @@ +package com.asyncapi.examples.v2._6_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._6_0.model.channel.ChannelItem +import com.asyncapi.v2._6_0.model.channel.message.Message +import com.asyncapi.v2._6_0.model.channel.message.OneOfMessages +import com.asyncapi.v2._6_0.model.channel.operation.Operation +import com.asyncapi.v2._6_0.model.component.Components +import com.asyncapi.v2._6_0.model.info.Info +import com.asyncapi.v2._6_0.model.server.Server +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.http.HttpApiKeySecurityScheme + +class SlackRtm: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.6.0/slack-rtm.yml" + + override fun expectedId(): String = "wss://wss-primary.slack.com/websocket" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Slack Real Time Messaging API") + .version("1.0.0") + .build() + } + + override fun expectedServers(): Map { + return mapOf( + Pair("production", + Server.builder() + .url("https://slack.com/api/rtm.connect") + .protocol("https") + .protocolVersion("1.1") + .security(listOf( + mapOf(Pair("token", emptyList())) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("/", + ChannelItem.builder() + .publish(Operation.builder() + .message(Reference("#/components/messages/outgoingMessage")) + .build() + ) + .subscribe(Operation.builder() + .message(OneOfMessages(listOf( + Reference("#/components/messages/hello"), + Reference("#/components/messages/connectionError"), + Reference("#/components/messages/accountsChanged"), + Reference("#/components/messages/botAdded"), + Reference("#/components/messages/botChanged"), + Reference("#/components/messages/channelArchive"), + Reference("#/components/messages/channelCreated"), + Reference("#/components/messages/channelDeleted"), + Reference("#/components/messages/channelHistoryChanged"), + Reference("#/components/messages/channelJoined"), + Reference("#/components/messages/channelLeft"), + Reference("#/components/messages/channelMarked"), + Reference("#/components/messages/channelRename"), + Reference("#/components/messages/channelUnarchive"), + Reference("#/components/messages/commandsChanged"), + Reference("#/components/messages/dndUpdated"), + Reference("#/components/messages/dndUpdatedUser"), + Reference("#/components/messages/emailDomainChanged"), + Reference("#/components/messages/emojiRemoved"), + Reference("#/components/messages/emojiAdded"), + Reference("#/components/messages/fileChange"), + Reference("#/components/messages/fileCommentAdded"), + Reference("#/components/messages/fileCommentDeleted"), + Reference("#/components/messages/fileCommentEdited"), + Reference("#/components/messages/fileCreated"), + Reference("#/components/messages/fileDeleted"), + Reference("#/components/messages/filePublic"), + Reference("#/components/messages/fileShared"), + Reference("#/components/messages/fileUnshared"), + Reference("#/components/messages/goodbye"), + Reference("#/components/messages/groupArchive"), + Reference("#/components/messages/groupClose"), + Reference("#/components/messages/groupHistoryChanged"), + Reference("#/components/messages/groupJoined"), + Reference("#/components/messages/groupLeft"), + Reference("#/components/messages/groupMarked"), + Reference("#/components/messages/groupOpen"), + Reference("#/components/messages/groupRename"), + Reference("#/components/messages/groupUnarchive"), + Reference("#/components/messages/imClose"), + Reference("#/components/messages/imCreated"), + Reference("#/components/messages/imMarked"), + Reference("#/components/messages/imOpen"), + Reference("#/components/messages/manualPresenceChange"), + Reference("#/components/messages/memberJoinedChannel"), + Reference("#/components/messages/message") + ))) + .build() + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .securitySchemes(mapOf( + Pair("token", HttpApiKeySecurityScheme( + null, + "token", + HttpApiKeySecurityScheme.ApiKeyLocation.QUERY + )) + )) + .schemas(mapOf( + Pair("attachment", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("fallback", Schema.builder() + .type("string") + .build() + ), + Pair("color", Schema.builder() + .type("string") + .build() + ), + Pair("pretext", Schema.builder() + .type("string") + .build() + ), + Pair("author_name", Schema.builder() + .type("string") + .build() + ), + Pair("author_link", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("author_icon", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("title", Schema.builder() + .type("string") + .build() + ), + Pair("title_link", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + Pair("fields", Schema.builder() + .type("array") + .items(Schema.builder() + .type("object") + .properties(mapOf( + Pair("title", Schema.builder() + .type("string") + .build() + ), + Pair("value", Schema.builder() + .type("string") + .build() + ), + Pair("short", Schema.builder() + .type("boolean") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("image_url", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("thumb_url", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("footer", Schema.builder() + .type("string") + .build() + ), + Pair("footer_icon", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("ts", Schema.builder() + .type("number") + .build() + ), + )) + .build() + ) + )) + .messages(mapOf( + Pair("hello", + Message.builder() + .summary("First event received upon connection.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("hello")) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("connectionError", + Message.builder() + .summary("Event received when a connection error happens.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("error")) + .build() + ), + Pair("error", Schema.builder() + .type("object") + .properties(mapOf( + Pair("code", Schema.builder().type("number").build()), + Pair("msg", Schema.builder().type("string").build()), + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("accountsChanged", + Message.builder() + .summary("The list of accounts a user is signed into has changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("accounts_changed")) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("botAdded", + Message.builder() + .summary("A bot user was added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("bot_added")) + .build() + ), + Pair("bot", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("app_id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("icons", Schema.builder() + .type("object") + .additionalProperties(Schema.builder().type("string").build()) + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("botChanged", + Message.builder() + .summary("A bot user was changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("bot_added")) + .build() + ), + Pair("bot", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("app_id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("icons", Schema.builder() + .type("object") + .additionalProperties(Schema.builder().type("string").build()) + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelArchive", + Message.builder() + .summary("A channel was archived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_archive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("channelCreated", + Message.builder() + .summary("A channel was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_created")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelDeleted", + Message.builder() + .summary("A channel was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_deleted")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelHistoryChanged", + Message.builder() + .summary("Bulk updates were made to a channel's history.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_history_changed")) + .build() + ), + Pair("latest", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelJoined", + Message.builder() + .summary("You joined a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_joined")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelLeft", + Message.builder() + .summary("You left a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_left")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelMarked", + Message.builder() + .summary("Your channel read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("channelRename", + Message.builder() + .summary("A channel was renamed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_rename")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("channelUnarchive", + Message.builder() + .summary("A channel was unarchived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("channel_unarchive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("commandsChanged", + Message.builder() + .summary("A slash command has been added or changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("commands_changed")) + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ) + .build() + ), + Pair("dndUpdated", + Message.builder() + .summary("Do not Disturb settings changed for the current user.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("dnd_updated")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("dnd_status", Schema.builder() + .type("object") + .properties(mapOf( + Pair("dnd_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("next_dnd_start_ts", Schema.builder() + .type("number") + .build() + ), + Pair("next_dnd_end_ts", Schema.builder() + .type("number") + .build() + ), + Pair("snooze_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("snooze_endtime", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("dndUpdatedUser", + Message.builder() + .summary("Do not Disturb settings changed for a member.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("dnd_updated_user")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("dnd_status", Schema.builder() + .type("object") + .properties(mapOf( + Pair("dnd_enabled", Schema.builder() + .type("boolean") + .build() + ), + Pair("next_dnd_start_ts", Schema.builder() + .type("number") + .build() + ), + Pair("next_dnd_end_ts", Schema.builder() + .type("number") + .build() + ) + )) + .build() + ) + )) + .build() + ) + .build() + ), + Pair("emailDomainChanged", + Message.builder() + .summary("The workspace email domain has changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("email_domain_changed")) + .build() + ), + Pair("email_domain", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("emojiRemoved", + Message.builder() + .summary("A custom emoji has been removed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("emoji_changed")) + .build() + ), + Pair("subtype", Schema.builder() + .type("string") + .enumValue(listOf("remove")) + .build() + ), + Pair("names", Schema.builder() + .type("array") + .items(Schema.builder().type("string").build()) + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("emojiAdded", + Message.builder() + .summary("A custom emoji has been added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("emoji_changed")) + .build() + ), + Pair("subtype", Schema.builder() + .type("string") + .enumValue(listOf("add")) + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("value", Schema.builder() + .type("string") + .format("uri") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileChange", + Message.builder() + .summary("A file was changed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_change")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentAdded", + Message.builder() + .summary("A file comment was added.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_added")) + .build() + ), + Pair("comment", Schema()), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentDeleted", + Message.builder() + .summary("A file comment was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_deleted")) + .build() + ), + Pair("comment", Schema.builder() + .type("string") + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCommentEdited", + Message.builder() + .summary("A file comment was edited.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_comment_edited")) + .build() + ), + Pair("comment", Schema()), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileCreated", + Message.builder() + .summary("A file was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_created")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileDeleted", + Message.builder() + .summary("A file was deleted.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_deleted")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("filePublic", + Message.builder() + .summary("A file was made public.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_public")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileShared", + Message.builder() + .summary("A file was shared.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_shared")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("fileUnshared", + Message.builder() + .summary("A file was unshared.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("file_unshared")) + .build() + ), + Pair("file_id", Schema.builder() + .type("string") + .build() + ), + Pair("file", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder().type("string").build()), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("goodbye", + Message.builder() + .summary("The server intends to close the connection soon.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("goodbye")) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupArchive", + Message.builder() + .summary("A private channel was archived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_archive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupClose", + Message.builder() + .summary("You closed a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_close")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupHistoryChanged", + Message.builder() + .summary("Bulk updates were made to a private channel's history.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_history_changed")) + .build() + ), + Pair("latest", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("event_ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupJoined", + Message.builder() + .summary("You joined a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_joined")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupLeft", + Message.builder() + .summary("You left a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_left")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupMarked", + Message.builder() + .summary("A private channel read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupOpen", + Message.builder() + .summary("You opened a private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_open")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupRename", + Message.builder() + .summary("A private channel was renamed.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_rename")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("groupUnarchive", + Message.builder() + .summary("A private channel was unarchived.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("group_unarchive")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imClose", + Message.builder() + .summary("You closed a DM.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_close")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imCreated", + Message.builder() + .summary("A DM was created.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_created")) + .build() + ), + Pair("channel", Schema.builder() + .type("object") + .properties(mapOf( + Pair("id", Schema.builder() + .type("string") + .build() + ), + Pair("name", Schema.builder() + .type("string") + .build() + ), + Pair("created", Schema.builder() + .type("number") + .build() + ), + Pair("creator", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imMarked", + Message.builder() + .summary("A direct message read marker was updated.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_marked")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("imOpen", + Message.builder() + .summary("You opened a DM.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("im_open")) + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("manualPresenceChange", + Message.builder() + .summary("You manually updated your presence.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("manual_presence_change")) + .build() + ), + Pair("presence", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("memberJoinedChannel", + Message.builder() + .summary("A user joined a public or private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("member_joined_channel")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("channel_type", Schema.builder() + .type("string") + .enumValue(listOf("C", "G")) + .build() + ), + Pair("team", Schema.builder() + .type("string") + .build() + ), + Pair("inviter", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("memberLeftChannel", + Message.builder() + .summary("A user left a public or private channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("member_left_channel")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("channel_type", Schema.builder() + .type("string") + .enumValue(listOf("C", "G")) + .build() + ), + Pair("team", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ), + Pair("message", + Message.builder() + .summary("A message was sent to a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("message")) + .build() + ), + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ), + Pair("attachments", Schema.builder() + .type("array") + .items(Schema.builder().ref("#/components/schemas/attachment").build()) + .build() + ), + Pair("edited", Schema.builder() + .type("object") + .properties(mapOf( + Pair("user", Schema.builder() + .type("string") + .build() + ), + Pair("ts", Schema.builder() + .type("string") + .build() + ) + )) + .build() + ), + )) + .build() + ) + .build() + ), + Pair("outgoingMessage", + Message.builder() + .summary("A message was sent to a channel.") + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("message")) + .build() + ), + Pair("id", Schema.builder() + .type("number") + .build() + ), + Pair("channel", Schema.builder() + .type("string") + .build() + ), + Pair("text", Schema.builder() + .type("string") + .build() + ), + )) + .build() + ) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsKafka.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsKafka.kt new file mode 100644 index 00000000..ede0887b --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsKafka.kt @@ -0,0 +1,289 @@ +package com.asyncapi.examples.v2._6_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._6_0.model.Tag +import com.asyncapi.v2._6_0.model.channel.ChannelItem +import com.asyncapi.v2._6_0.model.channel.Parameter +import com.asyncapi.v2._6_0.model.channel.message.Message +import com.asyncapi.v2._6_0.model.channel.message.MessageTrait +import com.asyncapi.v2._6_0.model.channel.operation.Operation +import com.asyncapi.v2._6_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._6_0.model.component.Components +import com.asyncapi.v2._6_0.model.info.Info +import com.asyncapi.v2._6_0.model.info.License +import com.asyncapi.v2._6_0.model.server.Server +import com.asyncapi.v2.binding.operation.kafka.KafkaOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.SecurityScheme +import java.math.BigDecimal + +class StreetlightsKafka: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.6.0/streetlights-kafka.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info( + "Streetlights Kafka API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0"), + ) + } + + override fun expectedServers(): Map { + return mapOf( + Pair("scram-connections", Server.builder() + .url("test.mykafkacluster.org:18092") + .protocol("kafka-secure") + .description("Test broker secured with scramSha256") + .security(listOf( + mapOf(Pair("saslScram", emptyList())) + )) + .tags(listOf( + Tag.builder() + .name("env:test-scram") + .description("This environment is meant for running internal tests through scramSha256") + .build(), + Tag.builder() + .name("kind:remote") + .description("This server is a remote server. Not exposed by the application") + .build(), + Tag.builder() + .name("visibility:private") + .description("This resource is private and only available to certain users") + .build() + )) + .build() + ), + Pair("mtls-connections", Server.builder() + .url("test.mykafkacluster.org:28092") + .protocol("kafka-secure") + .description("Test broker secured with X509") + .security(listOf( + mapOf(Pair("certs", emptyList())) + )) + .tags(listOf( + Tag.builder() + .name("env:test-mtls") + .description("This environment is meant for running internal tests through mtls") + .build(), + Tag.builder() + .name("kind:remote") + .description("This server is a remote server. Not exposed by the application") + .build(), + Tag.builder() + .name("visibility:private") + .description("This resource is private and only available to certain users") + .build() + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/dimLight")) + .build()) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("saslScram", + SecurityScheme.builder() + .type(SecurityScheme.Type.SCRAM_SHA256) + .description("Provide your username and password for SASL/SCRAM authentication") + .build() + ), + Pair("certs", + SecurityScheme( + SecurityScheme.Type.X509, + "Download the certificate files from service provider" + ) + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("kafka", + OperationTrait.builder() + .bindings(mapOf( + Pair("kafka", KafkaOperationBinding.builder() + .clientId(Schema.builder() + .type("string") + .enumValue(listOf("my-app-id")) + .build() + ) + .build() + ) + )) + .build() + ) + )) + .build() + } +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsMQTT.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsMQTT.kt new file mode 100644 index 00000000..44b393b0 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsMQTT.kt @@ -0,0 +1,314 @@ +package com.asyncapi.examples.v2._6_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._6_0.model.Tag +import com.asyncapi.v2._6_0.model.channel.ChannelItem +import com.asyncapi.v2._6_0.model.channel.Parameter +import com.asyncapi.v2._6_0.model.channel.message.Message +import com.asyncapi.v2._6_0.model.channel.message.MessageTrait +import com.asyncapi.v2._6_0.model.channel.operation.Operation +import com.asyncapi.v2._6_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._6_0.model.component.Components +import com.asyncapi.v2._6_0.model.info.Info +import com.asyncapi.v2._6_0.model.info.License +import com.asyncapi.v2._6_0.model.server.Server +import com.asyncapi.v2._6_0.model.server.ServerVariable +import com.asyncapi.v2.binding.operation.mqtt.MQTTOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.ApiKeySecurityScheme +import com.asyncapi.v2.security_scheme.OpenIdConnectSecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.flow.AuthorizationCodeOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.ImplicitOAuthFlow +import com.asyncapi.v2.security_scheme.oauth2.flow.PasswordOAuthFlow +import java.math.BigDecimal + +class StreetlightsMQTT: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.6.0/streetlights-mqtt.yml" + + override fun expectedInfo(): Info { + return Info( + "Streetlights MQTT API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0") + ) + } + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedServers(): Map { + return mapOf( + Pair("production", + Server.builder() + .url("test.mosquitto.org:{port}") + .protocol("mqtt") + .description("Test broker") + .variables(mapOf( + Pair("port", + ServerVariable.builder() + .description("Secure connection (TLS) is available through port 8883.") + .defaultValue("1883") + .enumValues(listOf("1883", "8883")) + .build() + ) + )) + .security(listOf( + mapOf(Pair("apiKey", emptyList())), + mapOf(Pair("supportedOauthFlows", listOf( + "streetlights:on", + "streetlights:off", + "streetlights:dim", + ))), + mapOf(Pair("openIdConnectWellKnown", emptyList())), + )) + .tags(listOf( + Tag("env:production", "This environment is meant for production use case", null), + Tag("kind:remote", "This server is a remote server. Not exposed by the application", null), + Tag("visibility:public", "This resource is public and available to everyone", null) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/turn/on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/turn/off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/turnOnOff")) + .build()) + .build() + ), + Pair("smartylighting/streetlights/1/0/action/{streetlightId}/dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/mqtt"))) + .message(Reference("#/components/messages/dimLight")) + .build()) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("apiKey", + ApiKeySecurityScheme("Provide your API key as the user and leave the password empty.", ApiKeySecurityScheme.ApiKeyLocation.USER) + ), + Pair("supportedOauthFlows", + OAuth2SecurityScheme( + "Flows to support OAuth 2.0", + OAuthFlows( + ImplicitOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/auth" + ), + PasswordOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/token" + ), + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/token" + ), + AuthorizationCodeOAuthFlow( + "https://authserver.example/refresh", + mapOf( + Pair("streetlights:on", "Ability to switch lights on"), + Pair("streetlights:off", "Ability to switch lights off"), + Pair("streetlights:dim", "Ability to dim the lights") + ), + "https://authserver.example/auth", + "https://authserver.example/token" + ) + ) + ) + ), + Pair("openIdConnectWellKnown", OpenIdConnectSecurityScheme(null, "https://authserver.example/.well-known")) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("mqtt", + OperationTrait.builder() + .bindings(mapOf( + Pair("mqtt", MQTTOperationBinding.builder() + .qos(1) + .build() + ) + )) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsOperationSecurity.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsOperationSecurity.kt new file mode 100644 index 00000000..cfb050f4 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/StreetlightsOperationSecurity.kt @@ -0,0 +1,288 @@ +package com.asyncapi.examples.v2._6_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._6_0.model.Tag +import com.asyncapi.v2._6_0.model.channel.ChannelItem +import com.asyncapi.v2._6_0.model.channel.Parameter +import com.asyncapi.v2._6_0.model.channel.message.Message +import com.asyncapi.v2._6_0.model.channel.message.MessageTrait +import com.asyncapi.v2._6_0.model.channel.operation.Operation +import com.asyncapi.v2._6_0.model.channel.operation.OperationTrait +import com.asyncapi.v2._6_0.model.component.Components +import com.asyncapi.v2._6_0.model.info.Info +import com.asyncapi.v2._6_0.model.info.License +import com.asyncapi.v2._6_0.model.server.Server +import com.asyncapi.v2.binding.operation.kafka.KafkaOperationBinding +import com.asyncapi.v2.schema.Schema +import com.asyncapi.v2.security_scheme.SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v2.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v2.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow +import java.math.BigDecimal + +class StreetlightsOperationSecurity: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.6.0/streetlights-operation-security.yml" + + override fun expectedDefaultContentType(): String = "application/json" + + override fun expectedInfo(): Info { + return Info( + "Streetlights Kafka API", + "1.0.0", + "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n" + + "### Check out its awesome features:\n\n" + + "* Turn a specific streetlight on/off \uD83C\uDF03\n" + + "* Dim a specific streetlight \uD83D\uDE0E\n" + + "* Receive real-time information about environmental lighting conditions \uD83D\uDCC8\n", + null, + null, + License("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0"), + ) + } + + override fun expectedServers(): Map { + return mapOf( + Pair("test", Server.builder() + .url("test.mykafkacluster.org:8092") + .protocol("kafka-secure") + .description("Test broker") + .security(listOf( + mapOf(Pair("saslScram", emptyList())) + )) + .build() + ), + Pair("test_oauth", Server.builder() + .url("test.mykafkacluster.org:8093") + .protocol("kafka-secure") + .description("Test port for oauth") + .security(listOf( + mapOf(Pair("streetlights_auth", listOf( + "streetlights:write", + "streetlights:read" + ))) + )) + .build() + ) + ) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured", + ChannelItem.builder() + .description("The topic on which measured values may be produced and consumed.") + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .publish(Operation.builder() + .operationId("receiveLightMeasurement") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/lightMeasured")) + .build()) + .servers(listOf("test")) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.on", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOn") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .security(listOf(mapOf(Pair("streetlights_auth", listOf("streetlights:read"))))) + .build()) + .servers(listOf("test_oauth")) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.turn.off", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("turnOff") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/turnOnOff")) + .security(listOf(mapOf(Pair("streetlights_auth", listOf("streetlights:read"))))) + .build() + ) + .servers(listOf("test_oauth")) + .build() + ), + Pair("smartylighting.streetlights.1.0.action.{streetlightId}.dim", + ChannelItem.builder() + .parameters(mapOf(Pair("streetlightId", Reference("#/components/parameters/streetlightId")))) + .subscribe(Operation.builder() + .operationId("dimLight") + .traits(listOf(Reference("#/components/operationTraits/kafka"))) + .message(Reference("#/components/messages/dimLight")) + .security(listOf(mapOf(Pair("streetlights_auth", listOf("streetlights:read"))))) + .build() + ) + .servers(listOf("test_oauth")) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair("lightMeasured", + Message.builder() + .name("lightMeasured") + .title("Light measured") + .summary("Inform about environmental lighting conditions of a particular streetlight.") + .contentType("application/json") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/lightMeasuredPayload").build()) + .build() + ), + Pair("turnOnOff", + Message.builder() + .name("turnOnOff") + .title("Turn on/off") + .summary("Command a particular streetlight to turn the lights on or off.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/turnOnOffPayload").build()) + .build() + ), + Pair("dimLight", + Message.builder() + .name("dimLight") + .title("Dim light") + .summary("Command a particular streetlight to dim the lights.") + .traits(listOf(Reference("#/components/messageTraits/commonHeaders"))) + .payload(Schema.builder().ref("#/components/schemas/dimLightPayload").build()) + .build() + ) + )) + .schemas(mapOf( + Pair("lightMeasuredPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("lumens", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .description("Light intensity measured in lumens.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("turnOnOffPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("command", + Schema.builder() + .type("string") + .enumValue(listOf("on", "off")) + .description("Whether to turn on or off the light.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("dimLightPayload", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("percentage", + Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .description("Percentage to which the light should be dimmed to.") + .build() + ), + Pair("sentAt", + Schema.builder().ref("#/components/schemas/sentAt").build() + ) + )) + .build() + ), + Pair("sentAt", + Schema.builder() + .type("string") + .format("date-time") + .description("Date and time when the message was sent.") + .build() + ) + )) + .securitySchemes(mapOf( + Pair("saslScram", + SecurityScheme.builder() + .type(SecurityScheme.Type.SCRAM_SHA256) + .description("Provide your username and password for SASL/SCRAM authentication") + .build() + ), + Pair("streetlights_auth", + OAuth2SecurityScheme( + "The oauth security descriptions", + OAuthFlows( + null, + null, + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("streetlights:read", "Scope required for subscribing to channel"), + Pair("streetlights:write", "Scope required for publishing to channel"), + ), + "https://example.com/api/oauth/dialog", + ), + null, + ) + ) + ) + )) + .parameters(mapOf( + Pair("streetlightId", Parameter.builder() + .description("The ID of the streetlight.") + .schema(Schema.builder().type("string").build()) + .build() + ) + )) + .messageTraits(mapOf( + Pair("commonHeaders", + MessageTrait.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("my-app-header", Schema.builder() + .type("integer") + .minimum(BigDecimal.ZERO) + .maximum(BigDecimal.valueOf(100)) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .operationTraits(mapOf( + Pair("kafka", + OperationTrait.builder() + .bindings(mapOf( + Pair("kafka", KafkaOperationBinding.builder() + .clientId(Schema.builder() + .type("string") + .enumValue(listOf("my-app-id")) + .build() + ) + .build() + ) + )) + .build() + ) + )) + .build() + } +} \ No newline at end of file diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/WebsocketGemini.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/WebsocketGemini.kt new file mode 100644 index 00000000..e10a4890 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v2/_6_0/WebsocketGemini.kt @@ -0,0 +1,396 @@ +package com.asyncapi.examples.v2._6_0 + +import com.asyncapi.v2.Reference +import com.asyncapi.v2._6_0.model.ExternalDocumentation +import com.asyncapi.v2._6_0.model.channel.ChannelItem +import com.asyncapi.v2._6_0.model.channel.operation.Operation +import com.asyncapi.v2._6_0.model.channel.Parameter +import com.asyncapi.v2._6_0.model.channel.message.Message +import com.asyncapi.v2._6_0.model.channel.message.MessageExample +import com.asyncapi.v2._6_0.model.component.Components +import com.asyncapi.v2._6_0.model.info.Info +import com.asyncapi.v2._6_0.model.info.Contact +import com.asyncapi.v2._6_0.model.server.Server +import com.asyncapi.v2.binding.channel.ws.WebSocketsChannelBinding +import com.asyncapi.v2.schema.Schema + +class WebsocketGemini: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v2.6.0/websocket-gemini.yml" + + override fun expectedInfo(): Info { + return Info( + "Gemini Market Data Websocket API", + "1.0.0", + """ + Market data is a public API that streams all the market data on a given symbol. + + You can quickly play with the API using [websocat](https://github.com/vi/websocat#installation) like this: + ```bash + websocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S + ``` + + """.trimIndent(), + null, + Contact("Gemini", "https://www.gemini.com/", null), + null, + ) + } + + override fun expectedServers(): Map { + return mapOf(Pair("public", Server.builder().url("wss://api.gemini.com").protocol("wss").build())) + } + + override fun expectedChannels(): Map { + return mapOf( + Pair("/v1/marketdata/{symbol}", + ChannelItem.builder() + .subscribe(Operation.builder() + .summary("Receive market updates on a given symbol") + .message(Reference("#/components/messages/marketData")) + .build()) + .parameters( + mapOf( + Pair("symbol", + Parameter.builder() + .schema(Schema.builder() + .type("string") + .enumValue(listOf( + "btcusd", + "ethbtc", + "ethusd", + "zecusd", + "zecbtc", + "zeceth", + "zecbch", + "zecltc", + "bchusd", + "bchbtc", + "bcheth", + "ltcusd", + "ltcbtc", + "ltceth", + "ltcbch", + "batusd", + "daiusd", + "linkusd", + "oxtusd", + "batbtc", + "linkbtc", + "oxtbtc", + "bateth", + "linketh", + "oxteth", + "ampusd", + "compusd", + "paxgusd", + "mkrusd", + "zrxusd", + "kncusd", + "manausd", + "storjusd", + "snxusd", + "crvusd", + "balusd", + "uniusd", + "renusd", + "umausd", + "yfiusd", + "btcdai", + "ethdai", + "aaveusd", + "filusd", + "btceur", + "btcgbp", + "etheur", + "ethgbp", + "btcsgd", + "ethsgd", + "sklusd", + "grtusd", + "bntusd", + "1inchusd", + "enjusd", + "lrcusd", + "sandusd", + "cubeusd", + "lptusd", + "bondusd", + "maticusd", + "injusd", + "sushiusd" + )) + .build() + ) + .description( + "Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. To read more click [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums).\n" + ) + .build() + ) + ) + ) + .bindings( + mapOf( + Pair( + "ws", + WebSocketsChannelBinding.builder() + .query( + Schema.builder() + .type("object") + .description( + "The semantics of entry type filtering is:\n" + + "\n" + + "If any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response\n" + + "If no entry types filtering parameters are included in the url, then all entry types will appear in the response\n" + + "\n" + + "NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified\n" + ) + .properties(mapOf( + Pair( + "heartbeat", + Schema.builder() + .type("boolean") + .defaultValue(false) + .description( + "Optionally add this parameter and set to true to receive a " + + "heartbeat every 5 seconds" + ) + .build() + ), + Pair( + "top_of_book", + Schema.builder() + .type("boolean") + .defaultValue(false) + .description( + "If absent or false, receive full order book depth; if present " + + "and true, receive top of book only. Only applies to bids and " + + "offers." + ) + .build() + ), + Pair( + "bids", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include bids in change events") + .build() + ), + Pair( + "offers", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include asks in change events") + .build() + ), + Pair( + "trades", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include trade events") + .build() + ), + Pair( + "auctions", + Schema.builder() + .type("boolean") + .defaultValue(true) + .description("Include auction events") + .build() + ) + )) + .build() + ) + .build() + ) + ) + ) + .build() + ) + ) + } + + override fun expectedComponents(): Components { + return Components.builder() + .messages(mapOf( + Pair( + "marketData", + Message.builder() + .summary("Message with marked data information.") + .description( + "The initial response message will show the existing state of the order book. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled.\n" + ) + .payload(Schema.builder().ref("#/components/schemas/market").build()) + .examples(listOf( + MessageExample.builder() + .name("updateMessage") + .summary("Example of an update message that contains a change in price information.") + .payload(mapOf( + Pair("type", "update"), + Pair("eventId", 36902233362), + Pair("timestamp", 1619769673), + Pair("timestampms", 1619769673527), + Pair("socket_sequence", 661), + Pair("events", listOf(mapOf( + Pair("type", "change"), + Pair("side", "bid"), + Pair("price", 54350.40), + Pair("remaining", 0.002), + Pair("delta", 0.002), + Pair("reason", "place") + ))), + )) + .build(), + MessageExample.builder() + .name("heartbeatMessage") + .summary("Example of additional heartbeat message when you enable them.") + .payload(mapOf( + Pair("type", "heartbeat"), + Pair("socket_sequence", 1656) + )) + .build(), + )) + .build() + ) + )) + .schemas(mapOf( + Pair("market", Schema.builder() + .type("object") + .oneOf(listOf( + Schema.builder().ref("#/components/schemas/heartbeat").build(), + Schema.builder().ref("#/components/schemas/update").build(), + )) + .build() + ), + Pair("heartbeat", Schema.builder() + .allOf(listOf( + Schema.builder() + .properties(mapOf( + Pair("type", Schema.builder().type("string").constValue("heartbeat").build()) + )) + .required(listOf("type")) + .build(), + Schema.builder() + .ref("#/components/schemas/default") + .build(), + )) + .build() + ), + Pair("update", Schema.builder() + .allOf(listOf( + Schema.builder() + .properties(mapOf( + Pair("type", Schema.builder().type("string").constValue("update").build()), + Pair("eventId", Schema.builder() + .type("integer") + .description( + "A monotonically increasing sequence number indicating when this " + + "change occurred. These numbers are persistent and consistent " + + "between market data connections." + ) + .build() + ), + Pair("events", Schema.builder().ref("#/components/schemas/events").build()), + Pair("timestamp", Schema.builder() + .type("number") + .description( + "The timestamp in seconds for this group of events (included for " + + "compatibility reasons). We recommend using the timestampms field " + + "instead." + ) + .build() + ), + Pair("timestampms", Schema.builder() + .type("number") + .description("The timestamp in milliseconds for this group of events.") + .build() + ), + )) + .required(listOf("type", "eventId", "events", "timestamp", "timestampms")) + .build(), + Schema.builder().ref("#/components/schemas/default").build(), + )) + .build() + ), + Pair("default", Schema.builder() + .type("object") + .description( + "This object is always part of the payload. In case of type=heartbeat, " + + "these are the only fields.") + .required(listOf("type", "socket_sequence")) + .properties(mapOf( + Pair("socket_sequence", Schema.builder() + .type("integer") + .description( + "zero-indexed monotonic increasing sequence number attached to each " + + "message sent - if there is a gap in this sequence, you have missed a " + + "message. If you choose to enable heartbeats, then heartbeat and " + + "update messages will share a single increasing sequence. See " + + "[Sequence Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers) " + + "for more information." + ) + .build() + ) + )) + .build() + ), + Pair("events", Schema.builder() + .type("array") + .description("Either a change to the order book, or the indication that a trade has occurred.") + .items(Schema.builder() + .type("object") + .additionalProperties(false) + .properties(mapOf( + Pair("type", Schema.builder() + .type("string") + .enumValue(listOf("trade", "change", "auction, block_trade")) + .build() + ), + Pair("price", Schema.builder() + .type("number") + .multipleOf(0.01) + .description("The price of this order book entry.") + .build() + ), + Pair("side", Schema.builder() + .type("string") + .enumValue(listOf("bid", "side")) + .build() + ), + Pair("reason", Schema.builder() + .type("string") + .enumValue(listOf("place", "trade", "cancel", "initial")) + .description( + "Indicates why the change has occurred. initial is for the initial " + + "response message, which will show the entire existing state of the " + + "order book." + ) + .build() + ), + Pair("remaining", Schema.builder() + .type("number") + .description( + "The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled." + ) + .build() + ), + Pair("delta", Schema.builder() + .type("number") + .description( + "The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining." + ) + .build() + ) + )) + .build() + ) + .build() + ) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/anyof.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/anyof.yml new file mode 100644 index 00000000..812ebd17 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/anyof.yml @@ -0,0 +1,31 @@ +asyncapi: 2.0.0 +info: + title: AnyOf example + version: '1.0.0' + +channels: + test: + publish: + message: + $ref: '#/components/messages/testMessages' + +components: + messages: + testMessages: + payload: + anyOf: # anyOf in payload schema + - $ref: "#/components/schemas/objectWithKey" + - $ref: "#/components/schemas/objectWithKey2" + + schemas: + objectWithKey: + type: object + properties: + key: + type: string + additionalProperties: false + objectWithKey2: + type: object + properties: + key2: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/application-headers.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/application-headers.yml new file mode 100644 index 00000000..9d373776 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/application-headers.yml @@ -0,0 +1,83 @@ +asyncapi: 2.0.0 +info: + title: Application Headers example + version: '1.0.0' + description: A cut of the Streetlights API to test application header changes supporting #112 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + +defaultContentType: application/json + +channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + message: + $ref: '#/components/messages/lightMeasured' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + correlationId: + location: "$message.header#/MQMD/CorrelId" + contentType: application/json + headers: + type: object + properties: + MQMD: + type: object + properties: + CorrelId: + type: string + minLength: 24 + maxLength: 24 + format: binary + applicationInstanceId: + $ref: "#/components/schemas/applicationInstanceId" + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + applicationInstanceId: + description: Unique identifier for a given instance of the publishing application + type: string + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/correlation-id.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/correlation-id.yml new file mode 100644 index 00000000..428f76a5 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/correlation-id.yml @@ -0,0 +1,144 @@ +asyncapi: "2.0.0" +info: + title: Correlation ID Example + version: '1.0.0' + description: A cut of the Streetlights API to test Correlation ID + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + +defaultContentType: application/json + +channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting/streetlights/1/0/action/{streetlightId}/dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + correlationId: + location: "$message.header#/MQMD/CorrelId" + contentType: application/json + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + correlationId: + $ref: "#/components/correlationIds/sentAtCorrelator" + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + correlationIds: + sentAtCorrelator: + description: Data from message payload used as correlation ID + location: $message.payload#/sentAt + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/gitter-streaming.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/gitter-streaming.yml new file mode 100644 index 00000000..85ed148f --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/gitter-streaming.yml @@ -0,0 +1,171 @@ +asyncapi: "2.0.0" +id: 'tag:stream.gitter.im,2022:api' +info: + title: Gitter Streaming API + version: '1.0.0' + +servers: + production: + url: https://stream.gitter.im/v1 + protocol: https + protocolVersion: '1.1' + security: + - httpBearerToken: [] + +channels: + /rooms/{roomId}/{resource}: + parameters: + roomId: + description: Id of the Gitter room. + schema: + type: string + examples: + - 53307860c3599d1de448e19d + resource: + description: The resource to consume. + schema: + type: string + enum: + - chatMessages + - events + subscribe: + bindings: + http: + type: response + message: + $ref: '#/components/messages/chatMessage' + +components: + securitySchemes: + httpBearerToken: + type: http + scheme: bearer + messages: + chatMessage: + schemaFormat: 'application/schema+yaml;version=draft-07' + summary: >- + A message represents an individual chat message sent to a room. + They are a sub-resource of a room. + payload: + type: object + properties: + id: + type: string + description: ID of the message. + text: + type: string + description: Original message in plain-text/markdown. + html: + type: string + description: HTML formatted message. + sent: + type: string + format: date-time + description: ISO formatted date of the message. + fromUser: + type: object + description: User that sent the message. + properties: + id: + type: string + description: Gitter User ID. + username: + type: string + description: Gitter/GitHub username. + displayName: + type: string + description: Gitter/GitHub user real name. + url: + type: string + description: Path to the user on Gitter. + avatarUrl: + type: string + format: uri + description: User avatar URI. + avatarUrlSmall: + type: string + format: uri + description: User avatar URI (small). + avatarUrlMedium: + type: string + format: uri + description: User avatar URI (medium). + v: + type: number + description: Version. + gv: + type: string + description: Stands for "Gravatar version" and is used for cache busting. + unread: + type: boolean + description: Boolean that indicates if the current user has read the message. + readBy: + type: number + description: Number of users that have read the message. + urls: + type: array + description: List of URLs present in the message. + items: + type: string + format: uri + mentions: + type: array + description: List of @Mentions in the message. + items: + type: object + properties: + screenName: + type: string + userId: + type: string + userIds: + type: array + items: + type: string + issues: + type: array + description: 'List of #Issues referenced in the message.' + items: + type: object + properties: + number: + type: string + meta: + type: array + description: Metadata. This is currently not used for anything. + items: {} + v: + type: number + description: Version. + gv: + type: string + description: Stands for "Gravatar version" and is used for cache busting. + bindings: + http: + headers: + type: object + properties: + 'Transfer-Encoding': + type: string + const: 'chunked' + Trailer: + type: string + const: '\r\n' + + heartbeat: + schemaFormat: 'application/schema+yaml;version=draft-07' + summary: Its purpose is to keep the connection alive. + payload: + type: string + enum: ["\r\n"] + bindings: + http: + headers: + type: object + properties: + 'Transfer-Encoding': + type: string + const: 'chunked' + Trailer: + type: string + const: '\r\n' \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/mercure.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/mercure.yml new file mode 100644 index 00000000..2470885a --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/mercure.yml @@ -0,0 +1,49 @@ +asyncapi: "2.0.0" +info: + title: Mercure Hub Example + version: '1.0.0' + description: This example demonstrates how to define a Mercure hub. + +# While not mandatory, it's a best practice to use formats with hypermedia capabilities such as JSON-LD, Atom or HTML with the Mercure protocol +defaultContentType: application/ld+json + +servers: + production: + url: https://demo.mercure.rocks/.well-known/mercure + protocol: mercure + +channels: + 'https://example.com/books/{id}': + description: Every time a resource of type `http://schema.org/Book` is created or modified, a JSON-LD representation of the new version of this resource must be pushed in this Mercure topic. + parameters: + id: + schema: + type: integer + subscribe: + message: + $ref: '#/components/messages/book' + publish: + message: + $ref: '#/components/messages/book' + +components: + messages: + book: + summary: The content of a book resource. + externalDocs: + url: https://schema.org/Book + payload: + type: object + properties: + '@id': + type: string + format: iri-reference + '@type': + type: string + format: iri-reference + name: + type: string + isbn: + type: string + abstract: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/not.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/not.yml new file mode 100644 index 00000000..95420d0f --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/not.yml @@ -0,0 +1,24 @@ +asyncapi: "2.0.0" +info: + title: Not example + version: '1.0.0' + +channels: + test: + publish: + message: + $ref: '#/components/messages/testMessages' + +components: + messages: + testMessages: + payload: + $ref: "#/components/schemas/testSchema" + + schemas: + testSchema: + type: object + properties: + key: + not: + type: integer \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/oneof.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/oneof.yml new file mode 100644 index 00000000..738b220f --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/oneof.yml @@ -0,0 +1,42 @@ +asyncapi: "2.0.0" +info: + title: OneOf example + version: '1.0.0' + +channels: + test: + publish: + message: + $ref: '#/components/messages/testMessages' + + test2: + subscribe: + message: + payload: + $ref: "#/components/schemas/objectWithKey" + +components: + messages: + testMessages: + payload: + oneOf: # oneOf in payload schema + - $ref: "#/components/schemas/objectWithKey" + - $ref: "#/components/schemas/objectWithKey2" + testMessage1: + payload: + $ref: "#/components/schemas/objectWithKey" + testMessage2: + payload: + $ref: "#/components/schemas/objectWithKey2" + + schemas: + objectWithKey: + type: object + properties: + key: + type: string + objectWithKey2: + type: object + properties: + key2: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/operation-security.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/operation-security.yml new file mode 100644 index 00000000..c0f77bc2 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/operation-security.yml @@ -0,0 +1,96 @@ +asyncapi: 2.0.0 +info: + title: Notifications + version: 1.0.0 + description: >- + This contract defines HTTP Push notification for + application authorization revocation topic +channels: + AUTHORIZATION_REVOCATION: + subscribe: + message: + $ref: '#/components/messages/message' + bindings: + http: + type: request + method: POST +components: + messages: + message: + headers: + type: object + properties: + X-SIGNATURE: + description: ECC message signature + type: string + payload: + type: object + properties: + metadata: + $ref: '#/components/schemas/MetaData' + notification: + $ref: '#/components/schemas/Notification' + schemas: + MetaData: + type: object + properties: + topic: + type: string + description: Topic subscribed to. + schemaVersion: + type: string + description: The schema for this topic. + deprecated: + type: boolean + description: If this is a deprecated schema or topic. + default: 'false' + Notification: + type: object + properties: + notificationId: + type: string + description: The notification Id. + eventDate: + type: string + description: The event date associated with this notification in UTC. + publishDate: + type: string + description: The message publish date in UTC. + publishAttemptCount: + type: integer + description: The number of attempts made to publish this message. + data: + $ref: '#/components/schemas/AuthorizationRevocationData' + AuthorizationRevocationData: + type: object + description: The Authorization Revocation payload. + properties: + username: + type: string + description: The username for the user. + userId: + type: string + description: The immutable public userId for the user + eiasToken: + type: string + description: The legacy eiasToken specific to the user + revokeReason: + type: string + enum: + - REVOKED_BY_APP + - REVOKED_BY_USER + - REVOKED_BY_ADMIN + - PASSWORD_CHANGE + description: The reason for authorization revocation + revocationDate: + type: string + description: Date and time when the authorization was revoked + securitySchemes: + petstore_auth: + type: oauth2 + description: The oauth security descriptions + flows: + clientCredentials: + tokenUrl: 'https://example.com/api/oauth/dialog' + scopes: + subscribe:auth_revocations: Scope required for authorization revocation topic \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-client.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-client.yml new file mode 100644 index 00000000..5a1d5875 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-client.yml @@ -0,0 +1,65 @@ +asyncapi: "2.0.0" +id: 'urn:example:rpcclient' +defaultContentType: application/json + +info: + title: RPC Client Example + description: This example demonstrates how to define an RPC client. + version: '1.0.0' + +servers: + production: + url: rabbitmq.example.org + protocol: amqp + +channels: + '{queue}': + parameters: + queue: + schema: + type: string + pattern: '^amq\\.gen\\-.+$' + bindings: + amqp: + is: queue + queue: + exclusive: true + publish: + operationId: receiveSumResult + bindings: + amqp: + ack: false + message: + correlationId: + location: $message.header#/correlation_id + payload: + type: object + properties: + result: + type: number + examples: + - 7 + + rpc_queue: + bindings: + amqp: + is: queue + queue: + durable: false + subscribe: + operationId: requestSum + bindings: + amqp: + ack: true + message: + correlationId: + location: $message.header#/correlation_id + payload: + type: object + properties: + numbers: + type: array + items: + type: number + examples: + - [4,3] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-server.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-server.yml new file mode 100644 index 00000000..4794b5f9 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/rpc-server.yml @@ -0,0 +1,62 @@ +asyncapi: "2.0.0" +id: 'urn:example:rpcserver' +defaultContentType: application/json + +info: + title: RPC Server Example + description: This example demonstrates how to define an RPC server. + version: '1.0.0' + +servers: + production: + url: rabbitmq.example.org + protocol: amqp + +channels: + '{queue}': + parameters: + queue: + schema: + type: string + pattern: '^amq\\.gen\\-.+$' + bindings: + amqp: + is: queue + queue: + exclusive: true + subscribe: + operationId: sendSumResult + bindings: + amqp: + ack: true + message: + correlationId: + location: $message.header#/correlation_id + payload: + type: object + properties: + result: + type: number + examples: + - 7 + + rpc_queue: + bindings: + amqp: + is: queue + queue: + durable: false + publish: + operationId: sum + message: + correlationId: + location: $message.header#/correlation_id + payload: + type: object + properties: + numbers: + type: array + items: + type: number + examples: + - [4,3] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/simple.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/simple.yml new file mode 100644 index 00000000..82793c33 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/simple.yml @@ -0,0 +1,23 @@ +asyncapi: "2.0.0" +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: '#/components/messages/UserSignedUp' +components: + messages: + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/slack-rtm.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/slack-rtm.yml new file mode 100644 index 00000000..d10cdd51 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/slack-rtm.yml @@ -0,0 +1,838 @@ +asyncapi: "2.0.0" +id: 'wss://wss-primary.slack.com/websocket' +info: + title: Slack Real Time Messaging API + version: '1.0.0' + +servers: + production: + url: https://slack.com/api/rtm.connect + protocol: https + protocolVersion: '1.1' + security: + - token: [] + +channels: + /: + publish: + message: + $ref: '#/components/messages/outgoingMessage' + subscribe: + message: + $ref: '#/components/messages/hello' + +components: + securitySchemes: + token: + type: httpApiKey + name: token + in: query + + schemas: + attachment: + type: object + properties: + fallback: + type: string + color: + type: string + pretext: + type: string + author_name: + type: string + author_link: + type: string + format: uri + author_icon: + type: string + format: uri + title: + type: string + title_link: + type: string + format: uri + text: + type: string + fields: + type: array + items: + type: object + properties: + title: + type: string + value: + type: string + short: + type: boolean + image_url: + type: string + format: uri + thumb_url: + type: string + format: uri + footer: + type: string + footer_icon: + type: string + format: uri + ts: + type: number + + messages: + hello: + summary: 'First event received upon connection.' + payload: + type: object + properties: + type: + type: string + enum: + - hello + connectionError: + summary: 'Event received when a connection error happens.' + payload: + type: object + properties: + type: + type: string + enum: + - error + error: + type: object + properties: + code: + type: number + msg: + type: string + accountsChanged: + summary: 'The list of accounts a user is signed into has changed.' + payload: + type: object + properties: + type: + type: string + enum: + - accounts_changed + botAdded: + summary: 'A bot user was added.' + payload: + type: object + properties: + type: + type: string + enum: + - bot_added + bot: + type: object + properties: + id: + type: string + app_id: + type: string + name: + type: string + icons: + type: object + additionalProperties: + type: string + botChanged: + summary: 'A bot user was changed.' + payload: + type: object + properties: + type: + type: string + enum: + - bot_added + bot: + type: object + properties: + id: + type: string + app_id: + type: string + name: + type: string + icons: + type: object + additionalProperties: + type: string + channelArchive: + summary: 'A channel was archived.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_archive + channel: + type: string + user: + type: string + channelCreated: + summary: 'A channel was created.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_created + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + channelDeleted: + summary: 'A channel was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_deleted + channel: + type: string + channelHistoryChanged: + summary: 'Bulk updates were made to a channel''s history.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_history_changed + latest: + type: string + ts: + type: string + event_ts: + type: string + channelJoined: + summary: 'You joined a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_joined + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + channelLeft: + summary: 'You left a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_left + channel: + type: string + channelMarked: + summary: 'Your channel read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_marked + channel: + type: string + ts: + type: string + channelRename: + summary: 'A channel was renamed.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_rename + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + channelUnarchive: + summary: 'A channel was unarchived.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_unarchive + channel: + type: string + user: + type: string + commandsChanged: + summary: 'A slash command has been added or changed.' + payload: + type: object + properties: + type: + type: string + enum: + - commands_changed + event_ts: + type: string + dndUpdated: + summary: 'Do not Disturb settings changed for the current user.' + payload: + type: object + properties: + type: + type: string + enum: + - dnd_updated + user: + type: string + dnd_status: + type: object + properties: + dnd_enabled: + type: boolean + next_dnd_start_ts: + type: number + next_dnd_end_ts: + type: number + snooze_enabled: + type: boolean + snooze_endtime: + type: number + dndUpdatedUser: + summary: 'Do not Disturb settings changed for a member.' + payload: + type: object + properties: + type: + type: string + enum: + - dnd_updated_user + user: + type: string + dnd_status: + type: object + properties: + dnd_enabled: + type: boolean + next_dnd_start_ts: + type: number + next_dnd_end_ts: + type: number + emailDomainChanged: + summary: 'The workspace email domain has changed.' + payload: + type: object + properties: + type: + type: string + enum: + - email_domain_changed + email_domain: + type: string + event_ts: + type: string + emojiRemoved: + summary: 'A custom emoji has been removed.' + payload: + type: object + properties: + type: + type: string + enum: + - emoji_changed + subtype: + type: string + enum: + - remove + names: + type: array + items: + type: string + event_ts: + type: string + emojiAdded: + summary: 'A custom emoji has been added.' + payload: + type: object + properties: + type: + type: string + enum: + - emoji_changed + subtype: + type: string + enum: + - add + name: + type: string + value: + type: string + format: uri + event_ts: + type: string + fileChange: + summary: 'A file was changed.' + payload: + type: object + properties: + type: + type: string + enum: + - file_change + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentAdded: + summary: 'A file comment was added.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_added + comment: {} + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentDeleted: + summary: 'A file comment was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_deleted + comment: + type: string + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentEdited: + summary: 'A file comment was edited.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_edited + comment: {} + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCreated: + summary: 'A file was created.' + payload: + type: object + properties: + type: + type: string + enum: + - file_created + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileDeleted: + summary: 'A file was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - file_deleted + file_id: + type: string + event_ts: + type: string + filePublic: + summary: 'A file was made public.' + payload: + type: object + properties: + type: + type: string + enum: + - file_public + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileShared: + summary: 'A file was shared.' + payload: + type: object + properties: + type: + type: string + enum: + - file_shared + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileUnshared: + summary: 'A file was unshared.' + payload: + type: object + properties: + type: + type: string + enum: + - file_unshared + file_id: + type: string + file: + type: object + properties: + id: + type: string + goodbye: + summary: 'The server intends to close the connection soon.' + payload: + type: object + properties: + type: + type: string + enum: + - goodbye + groupArchive: + summary: 'A private channel was archived.' + payload: + type: object + properties: + type: + type: string + enum: + - group_archive + channel: + type: string + groupClose: + summary: 'You closed a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_close + user: + type: string + channel: + type: string + groupHistoryChanged: + summary: 'Bulk updates were made to a private channel''s history.' + payload: + type: object + properties: + type: + type: string + enum: + - group_history_changed + latest: + type: string + ts: + type: string + event_ts: + type: string + groupJoined: + summary: 'You joined a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_joined + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + groupLeft: + summary: 'You left a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_left + channel: + type: string + groupMarked: + summary: 'A private channel read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - group_marked + channel: + type: string + ts: + type: string + groupOpen: + summary: 'You opened a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_open + user: + type: string + channel: + type: string + groupRename: + summary: 'A private channel was renamed.' + payload: + type: object + properties: + type: + type: string + enum: + - group_rename + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + groupUnarchive: + summary: 'A private channel was unarchived.' + payload: + type: object + properties: + type: + type: string + enum: + - group_unarchive + channel: + type: string + user: + type: string + imClose: + summary: 'You closed a DM.' + payload: + type: object + properties: + type: + type: string + enum: + - im_close + channel: + type: string + user: + type: string + imCreated: + summary: 'A DM was created.' + payload: + type: object + properties: + type: + type: string + enum: + - im_created + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + user: + type: string + imMarked: + summary: 'A direct message read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - im_marked + channel: + type: string + ts: + type: string + imOpen: + summary: 'You opened a DM.' + payload: + type: object + properties: + type: + type: string + enum: + - im_open + channel: + type: string + user: + type: string + manualPresenceChange: + summary: 'You manually updated your presence.' + payload: + type: object + properties: + type: + type: string + enum: + - manual_presence_change + presence: + type: string + memberJoinedChannel: + summary: 'A user joined a public or private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - member_joined_channel + user: + type: string + channel: + type: string + channel_type: + type: string + enum: + - C + - G + team: + type: string + inviter: + type: string + memberLeftChannel: + summary: 'A user left a public or private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - member_left_channel + user: + type: string + channel: + type: string + channel_type: + type: string + enum: + - C + - G + team: + type: string + message: + summary: 'A message was sent to a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - message + user: + type: string + channel: + type: string + text: + type: string + ts: + type: string + attachments: + type: array + items: + $ref: '#/components/schemas/attachment' + edited: + type: object + properties: + user: + type: string + ts: + type: string + outgoingMessage: + summary: 'A message was sent to a channel.' + payload: + type: object + properties: + id: + type: number + type: + type: string + enum: + - message + channel: + type: string + text: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-kafka.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-kafka.yml new file mode 100644 index 00000000..4d09a978 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-kafka.yml @@ -0,0 +1,174 @@ +asyncapi: "2.0.0" +info: + title: Streetlights Kafka API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + scram-connections: + url: test.mykafkacluster.org:18092 + protocol: kafka-secure + description: Test broker secured with scramSha256 + security: + - saslScram: [] + mtls-connections: + url: test.mykafkacluster.org:28092 + protocol: kafka-secure + description: Test broker secured with X509 + security: + - certs: [] + +defaultContentType: application/json + +channels: + smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting.streetlights.1.0.action.{streetlightId}.dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + saslScram: + type: scramSha256 + description: Provide your username and password for SASL/SCRAM authentication + certs: + type: X509 + description: Download the certificate files from service provider + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + kafka: + bindings: + kafka: + clientId: + type: string + enum: ['my-app-id'] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-mqtt.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-mqtt.yml new file mode 100644 index 00000000..a5b402d1 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-mqtt.yml @@ -0,0 +1,209 @@ +asyncapi: "2.0.0" +info: + title: Streetlights MQTT API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + +defaultContentType: application/json + +channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + mqtt: + bindings: + mqtt: + qos: 1 \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-operation-security.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-operation-security.yml new file mode 100644 index 00000000..28168528 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/streetlights-operation-security.yml @@ -0,0 +1,183 @@ +asyncapi: "2.0.0" +info: + title: Streetlights Kafka API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + test: + url: test.mykafkacluster.org:8092 + protocol: kafka-secure + description: Test broker + security: + - saslScram: [] + test_oauth: + url: test.mykafkacluster.org:8093 + protocol: kafka-secure + description: Test port for oauth + security: + - streetlights_auth: + - streetlights:write + - streetlights:read + + +defaultContentType: application/json + +channels: + smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + smartylighting.streetlights.1.0.action.{streetlightId}.dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dimLight' + + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + saslScram: + type: scramSha256 + description: Provide your username and password for SASL/SCRAM authentication + streetlights_auth: + type: oauth2 + description: The oauth security descriptions + flows: + clientCredentials: + tokenUrl: 'https://example.com/api/oauth/dialog' + scopes: + streetlights:read: Scope required for subscribing to channel + streetlights:write: Scope required for publishing to channel + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + kafka: + bindings: + kafka: + clientId: + type: string + enum: ['my-app-id'] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.0.0/websocket-gemini.yml b/asyncapi-core/src/test/resources/examples/v2.0.0/websocket-gemini.yml new file mode 100644 index 00000000..22e860ab --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.0.0/websocket-gemini.yml @@ -0,0 +1,209 @@ +# +# +# +# This example showcases usage of AsyncAPI for the purpose of describing a WebSocket API. It is based on a real public service maintained by company called Gemini that provides cryptocurency trading products. It uses AsyncAPI bindings. +# +# This AsyncAPI document describes their v1 of the API. The v2 is also available and changes in the way that it provides a multimessage channel, where you subscribe for messages by sending a subscription message instead of using query parameters. For example with multimessage channel check out this article https://www.asyncapi.com/blog/websocket-part2 about another real public API called Kraken +# +# All available learning materials about AsyncAPI and WebSocket are: +# - WebSocket, Shrek, and AsyncAPI - An Opinionated Intro article: https://www.asyncapi.com/blog/websocket-part1 +# - Creating AsyncAPI for WebSocket API - Step by Step article: https://www.asyncapi.com/blog/websocket-part2 +# - From API-First to Code Generation - A WebSocket Use Case article: https://www.asyncapi.com/blog/websocket-part3 +# - Live stream about topics mentioned in part 1 and 2 articles: https://www.youtube.com/watch?v=8tFBcf31e_c +# + +asyncapi: "2.0.0" + +# +# Overal information for users of the application +# +info: + title: Gemini Market Data Websocket API + version: '1.0.0' + contact: + name: Gemini + url: https://www.gemini.com/ + description: | + Market data is a public API that streams all the market data on a given symbol. + + You can quickly play with the API using [websocat](https://github.com/vi/websocat#installation) like this: + ```bash + websocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S + ``` + +# +# Link to external docs +# +externalDocs: + url: https://docs.sandbox.gemini.com/websocket-api/#market-data + +# +# Details on how to connect to the application +# +servers: + public: + url: wss://api.gemini.com + protocol: wss + +# +# Details about all the channels that you can listen to or send to messages +# +channels: + /v1/marketdata/{symbol}: + parameters: + symbol: + description: | + Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. To read more click [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums). + schema: + type: string + enum: ['btcusd', 'ethbtc', 'ethusd', 'zecusd', 'zecbtc', 'zeceth', 'zecbch', 'zecltc', 'bchusd', 'bchbtc', 'bcheth', 'ltcusd', 'ltcbtc', 'ltceth', 'ltcbch', 'batusd', 'daiusd', 'linkusd', 'oxtusd', 'batbtc', 'linkbtc', 'oxtbtc', 'bateth', 'linketh', 'oxteth', 'ampusd', 'compusd', 'paxgusd', 'mkrusd', 'zrxusd', 'kncusd', 'manausd', 'storjusd', 'snxusd', 'crvusd', 'balusd', 'uniusd', 'renusd', 'umausd', 'yfiusd', 'btcdai', 'ethdai', 'aaveusd', 'filusd', 'btceur', 'btcgbp', 'etheur', 'ethgbp', 'btcsgd', 'ethsgd', 'sklusd', 'grtusd', 'bntusd', '1inchusd', 'enjusd', 'lrcusd', 'sandusd', 'cubeusd', 'lptusd', 'bondusd', 'maticusd', 'injusd', 'sushiusd'] + bindings: + ws: + bindingVersion: 0.1.0 + query: + type: object + description: | + The semantics of entry type filtering is: + + If any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response + If no entry types filtering parameters are included in the url, then all entry types will appear in the response + + NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified + properties: + heartbeat: + type: boolean + default: false + description: Optionally add this parameter and set to true to receive a heartbeat every 5 seconds + top_of_book: + type: boolean + default: false + description: If absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers. + bids: + type: boolean + default: true + description: Include bids in change events + offers: + type: boolean + default: true + description: Include asks in change events + trades: + type: boolean + default: true + description: Include trade events + auctions: + type: boolean + default: true + description: Include auction events + subscribe: + summary: Receive market updates on a given symbol + message: + $ref: '#/components/messages/marketData' + +# +# All reusable parts for readability and staying DRY +# +components: + messages: + marketData: + summary: Message with marked data information. + description: | + The initial response message will show the existing state of the order book. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled. + payload: + $ref: '#/components/schemas/market' + examples: + - name: updateMessage + summary: Example of an update message that contains a change in price information. + payload: + type: update + eventId: 36902233362 + timestamp: 1619769673 + timestampms: 1619769673527 + socket_sequence: 661 + events: + - type: change + side: bid + price: 54350.40 + remaining: 0.002 + delta: 0.002 + reason: place + - name: heartbeatMessage + summary: Example of additional heartbeat message when you enable them. + payload: + type: heartbeat + socket_sequence: 1656 + schemas: + market: + type: object + oneOf: + - $ref: '#/components/schemas/heartbeat' + - $ref: '#/components/schemas/update' + heartbeat: + allOf: + - properties: + type: + type: string + const: heartbeat + required: + - type + - $ref: '#/components/schemas/default' + update: + allOf: + - properties: + type: + type: string + const: update + eventId: + type: integer + description: A monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections. + events: + $ref: '#/components/schemas/events' + timestamp: + type: number + description: The timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead. + timestampms: + type: number + description: The timestamp in milliseconds for this group of events. + required: + - type + - eventId + - events + - timestamp + - timestampms + - $ref: '#/components/schemas/default' + default: + type: object + description: This object is always part of the payload. In case of type=heartbeat, these are the only fields. + required: + - type + - socket_sequence + properties: + socket_sequence: + type: integer + description: zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. If you choose to enable heartbeats, then heartbeat and update messages will share a single increasing sequence. See [Sequence Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers) for more information. + events: + type: array + description: Either a change to the order book, or the indication that a trade has occurred. + items: + type: object + additionalProperties: false + properties: + type: + type: string + enum: ['trade', 'change', 'auction, block_trade'] + price: + type: number + multipleOf: 0.01 + description: The price of this order book entry. + side: + type: string + enum: ['bid', 'side'] + reason: + type: string + enum: ['place', 'trade', 'cancel', 'initial'] + description: Indicates why the change has occurred. initial is for the initial response message, which will show the entire existing state of the order book. + remaining: + type: number + description: The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled. + delta: + type: number + description: The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining. \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.6.0/slack-rtm.yml b/asyncapi-core/src/test/resources/examples/v2.6.0/slack-rtm.yml new file mode 100644 index 00000000..4c0deadd --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.6.0/slack-rtm.yml @@ -0,0 +1,884 @@ +asyncapi: "2.6.0" +id: 'wss://wss-primary.slack.com/websocket' +info: + title: Slack Real Time Messaging API + version: '1.0.0' + +servers: + production: + url: https://slack.com/api/rtm.connect + protocol: https + protocolVersion: '1.1' + security: + - token: [] + +channels: + /: + publish: + message: + $ref: '#/components/messages/outgoingMessage' + subscribe: + message: + oneOf: + - $ref: '#/components/messages/hello' + - $ref: '#/components/messages/connectionError' + - $ref: '#/components/messages/accountsChanged' + - $ref: '#/components/messages/botAdded' + - $ref: '#/components/messages/botChanged' + - $ref: '#/components/messages/channelArchive' + - $ref: '#/components/messages/channelCreated' + - $ref: '#/components/messages/channelDeleted' + - $ref: '#/components/messages/channelHistoryChanged' + - $ref: '#/components/messages/channelJoined' + - $ref: '#/components/messages/channelLeft' + - $ref: '#/components/messages/channelMarked' + - $ref: '#/components/messages/channelRename' + - $ref: '#/components/messages/channelUnarchive' + - $ref: '#/components/messages/commandsChanged' + - $ref: '#/components/messages/dndUpdated' + - $ref: '#/components/messages/dndUpdatedUser' + - $ref: '#/components/messages/emailDomainChanged' + - $ref: '#/components/messages/emojiRemoved' + - $ref: '#/components/messages/emojiAdded' + - $ref: '#/components/messages/fileChange' + - $ref: '#/components/messages/fileCommentAdded' + - $ref: '#/components/messages/fileCommentDeleted' + - $ref: '#/components/messages/fileCommentEdited' + - $ref: '#/components/messages/fileCreated' + - $ref: '#/components/messages/fileDeleted' + - $ref: '#/components/messages/filePublic' + - $ref: '#/components/messages/fileShared' + - $ref: '#/components/messages/fileUnshared' + - $ref: '#/components/messages/goodbye' + - $ref: '#/components/messages/groupArchive' + - $ref: '#/components/messages/groupClose' + - $ref: '#/components/messages/groupHistoryChanged' + - $ref: '#/components/messages/groupJoined' + - $ref: '#/components/messages/groupLeft' + - $ref: '#/components/messages/groupMarked' + - $ref: '#/components/messages/groupOpen' + - $ref: '#/components/messages/groupRename' + - $ref: '#/components/messages/groupUnarchive' + - $ref: '#/components/messages/imClose' + - $ref: '#/components/messages/imCreated' + - $ref: '#/components/messages/imMarked' + - $ref: '#/components/messages/imOpen' + - $ref: '#/components/messages/manualPresenceChange' + - $ref: '#/components/messages/memberJoinedChannel' + - $ref: '#/components/messages/message' + +components: + securitySchemes: + token: + type: httpApiKey + name: token + in: query + + schemas: + attachment: + type: object + properties: + fallback: + type: string + color: + type: string + pretext: + type: string + author_name: + type: string + author_link: + type: string + format: uri + author_icon: + type: string + format: uri + title: + type: string + title_link: + type: string + format: uri + text: + type: string + fields: + type: array + items: + type: object + properties: + title: + type: string + value: + type: string + short: + type: boolean + image_url: + type: string + format: uri + thumb_url: + type: string + format: uri + footer: + type: string + footer_icon: + type: string + format: uri + ts: + type: number + + messages: + hello: + summary: 'First event received upon connection.' + payload: + type: object + properties: + type: + type: string + enum: + - hello + connectionError: + summary: 'Event received when a connection error happens.' + payload: + type: object + properties: + type: + type: string + enum: + - error + error: + type: object + properties: + code: + type: number + msg: + type: string + accountsChanged: + summary: 'The list of accounts a user is signed into has changed.' + payload: + type: object + properties: + type: + type: string + enum: + - accounts_changed + botAdded: + summary: 'A bot user was added.' + payload: + type: object + properties: + type: + type: string + enum: + - bot_added + bot: + type: object + properties: + id: + type: string + app_id: + type: string + name: + type: string + icons: + type: object + additionalProperties: + type: string + botChanged: + summary: 'A bot user was changed.' + payload: + type: object + properties: + type: + type: string + enum: + - bot_added + bot: + type: object + properties: + id: + type: string + app_id: + type: string + name: + type: string + icons: + type: object + additionalProperties: + type: string + channelArchive: + summary: 'A channel was archived.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_archive + channel: + type: string + user: + type: string + channelCreated: + summary: 'A channel was created.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_created + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + channelDeleted: + summary: 'A channel was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_deleted + channel: + type: string + channelHistoryChanged: + summary: 'Bulk updates were made to a channel''s history.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_history_changed + latest: + type: string + ts: + type: string + event_ts: + type: string + channelJoined: + summary: 'You joined a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_joined + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + channelLeft: + summary: 'You left a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_left + channel: + type: string + channelMarked: + summary: 'Your channel read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_marked + channel: + type: string + ts: + type: string + channelRename: + summary: 'A channel was renamed.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_rename + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + channelUnarchive: + summary: 'A channel was unarchived.' + payload: + type: object + properties: + type: + type: string + enum: + - channel_unarchive + channel: + type: string + user: + type: string + commandsChanged: + summary: 'A slash command has been added or changed.' + payload: + type: object + properties: + type: + type: string + enum: + - commands_changed + event_ts: + type: string + dndUpdated: + summary: 'Do not Disturb settings changed for the current user.' + payload: + type: object + properties: + type: + type: string + enum: + - dnd_updated + user: + type: string + dnd_status: + type: object + properties: + dnd_enabled: + type: boolean + next_dnd_start_ts: + type: number + next_dnd_end_ts: + type: number + snooze_enabled: + type: boolean + snooze_endtime: + type: number + dndUpdatedUser: + summary: 'Do not Disturb settings changed for a member.' + payload: + type: object + properties: + type: + type: string + enum: + - dnd_updated_user + user: + type: string + dnd_status: + type: object + properties: + dnd_enabled: + type: boolean + next_dnd_start_ts: + type: number + next_dnd_end_ts: + type: number + emailDomainChanged: + summary: 'The workspace email domain has changed.' + payload: + type: object + properties: + type: + type: string + enum: + - email_domain_changed + email_domain: + type: string + event_ts: + type: string + emojiRemoved: + summary: 'A custom emoji has been removed.' + payload: + type: object + properties: + type: + type: string + enum: + - emoji_changed + subtype: + type: string + enum: + - remove + names: + type: array + items: + type: string + event_ts: + type: string + emojiAdded: + summary: 'A custom emoji has been added.' + payload: + type: object + properties: + type: + type: string + enum: + - emoji_changed + subtype: + type: string + enum: + - add + name: + type: string + value: + type: string + format: uri + event_ts: + type: string + fileChange: + summary: 'A file was changed.' + payload: + type: object + properties: + type: + type: string + enum: + - file_change + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentAdded: + summary: 'A file comment was added.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_added + comment: {} + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentDeleted: + summary: 'A file comment was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_deleted + comment: + type: string + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCommentEdited: + summary: 'A file comment was edited.' + payload: + type: object + properties: + type: + type: string + enum: + - file_comment_edited + comment: {} + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileCreated: + summary: 'A file was created.' + payload: + type: object + properties: + type: + type: string + enum: + - file_created + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileDeleted: + summary: 'A file was deleted.' + payload: + type: object + properties: + type: + type: string + enum: + - file_deleted + file_id: + type: string + event_ts: + type: string + filePublic: + summary: 'A file was made public.' + payload: + type: object + properties: + type: + type: string + enum: + - file_public + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileShared: + summary: 'A file was shared.' + payload: + type: object + properties: + type: + type: string + enum: + - file_shared + file_id: + type: string + file: + type: object + properties: + id: + type: string + fileUnshared: + summary: 'A file was unshared.' + payload: + type: object + properties: + type: + type: string + enum: + - file_unshared + file_id: + type: string + file: + type: object + properties: + id: + type: string + goodbye: + summary: 'The server intends to close the connection soon.' + payload: + type: object + properties: + type: + type: string + enum: + - goodbye + groupArchive: + summary: 'A private channel was archived.' + payload: + type: object + properties: + type: + type: string + enum: + - group_archive + channel: + type: string + groupClose: + summary: 'You closed a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_close + user: + type: string + channel: + type: string + groupHistoryChanged: + summary: 'Bulk updates were made to a private channel''s history.' + payload: + type: object + properties: + type: + type: string + enum: + - group_history_changed + latest: + type: string + ts: + type: string + event_ts: + type: string + groupJoined: + summary: 'You joined a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_joined + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + groupLeft: + summary: 'You left a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_left + channel: + type: string + groupMarked: + summary: 'A private channel read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - group_marked + channel: + type: string + ts: + type: string + groupOpen: + summary: 'You opened a private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - group_open + user: + type: string + channel: + type: string + groupRename: + summary: 'A private channel was renamed.' + payload: + type: object + properties: + type: + type: string + enum: + - group_rename + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + groupUnarchive: + summary: 'A private channel was unarchived.' + payload: + type: object + properties: + type: + type: string + enum: + - group_unarchive + channel: + type: string + user: + type: string + imClose: + summary: 'You closed a DM.' + payload: + type: object + properties: + type: + type: string + enum: + - im_close + channel: + type: string + user: + type: string + imCreated: + summary: 'A DM was created.' + payload: + type: object + properties: + type: + type: string + enum: + - im_created + channel: + type: object + properties: + id: + type: string + name: + type: string + created: + type: number + creator: + type: string + user: + type: string + imMarked: + summary: 'A direct message read marker was updated.' + payload: + type: object + properties: + type: + type: string + enum: + - im_marked + channel: + type: string + ts: + type: string + imOpen: + summary: 'You opened a DM.' + payload: + type: object + properties: + type: + type: string + enum: + - im_open + channel: + type: string + user: + type: string + manualPresenceChange: + summary: 'You manually updated your presence.' + payload: + type: object + properties: + type: + type: string + enum: + - manual_presence_change + presence: + type: string + memberJoinedChannel: + summary: 'A user joined a public or private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - member_joined_channel + user: + type: string + channel: + type: string + channel_type: + type: string + enum: + - C + - G + team: + type: string + inviter: + type: string + memberLeftChannel: + summary: 'A user left a public or private channel.' + payload: + type: object + properties: + type: + type: string + enum: + - member_left_channel + user: + type: string + channel: + type: string + channel_type: + type: string + enum: + - C + - G + team: + type: string + message: + summary: 'A message was sent to a channel.' + payload: + type: object + properties: + type: + type: string + enum: + - message + user: + type: string + channel: + type: string + text: + type: string + ts: + type: string + attachments: + type: array + items: + $ref: '#/components/schemas/attachment' + edited: + type: object + properties: + user: + type: string + ts: + type: string + outgoingMessage: + summary: 'A message was sent to a channel.' + payload: + type: object + properties: + id: + type: number + type: + type: string + enum: + - message + channel: + type: string + text: + type: string \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-kafka.yml b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-kafka.yml new file mode 100644 index 00000000..28e66e34 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-kafka.yml @@ -0,0 +1,188 @@ +asyncapi: "2.6.0" +info: + title: Streetlights Kafka API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + scram-connections: + url: test.mykafkacluster.org:18092 + protocol: kafka-secure + description: Test broker secured with scramSha256 + security: + - saslScram: [] + tags: + - name: "env:test-scram" + description: "This environment is meant for running internal tests through scramSha256" + - name: "kind:remote" + description: "This server is a remote server. Not exposed by the application" + - name: "visibility:private" + description: "This resource is private and only available to certain users" + mtls-connections: + url: test.mykafkacluster.org:28092 + protocol: kafka-secure + description: Test broker secured with X509 + security: + - certs: [] + tags: + - name: "env:test-mtls" + description: "This environment is meant for running internal tests through mtls" + - name: "kind:remote" + description: "This server is a remote server. Not exposed by the application" + - name: "visibility:private" + description: "This resource is private and only available to certain users" + +defaultContentType: application/json + +channels: + smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting.streetlights.1.0.action.{streetlightId}.dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + saslScram: + type: scramSha256 + description: Provide your username and password for SASL/SCRAM authentication + certs: + type: X509 + description: Download the certificate files from service provider + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + kafka: + bindings: + kafka: + clientId: + type: string + enum: ['my-app-id'] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-mqtt.yml b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-mqtt.yml new file mode 100644 index 00000000..b9025981 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-mqtt.yml @@ -0,0 +1,216 @@ +asyncapi: "2.6.0" +info: + title: Streetlights MQTT API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + production: + url: test.mosquitto.org:{port} + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - apiKey: [] + - supportedOauthFlows: + - streetlights:on + - streetlights:off + - streetlights:dim + - openIdConnectWellKnown: [] + tags: + - name: "env:production" + description: "This environment is meant for production use case" + - name: "kind:remote" + description: "This server is a remote server. Not exposed by the application" + - name: "visibility:public" + description: "This resource is public and available to everyone" + +defaultContentType: application/json + +channels: + smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured: + description: The topic on which measured values may be produced and consumed. + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/on: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/turn/off: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/turnOnOff' + + smartylighting/streetlights/1/0/action/{streetlightId}/dim: + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/mqtt' + message: + $ref: '#/components/messages/dimLight' + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'streetlights:on': Ability to switch lights on + 'streetlights:off': Ability to switch lights off + 'streetlights:dim': Ability to dim the lights + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + mqtt: + bindings: + mqtt: + qos: 1 \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-operation-security.yml b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-operation-security.yml new file mode 100644 index 00000000..d5873800 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.6.0/streetlights-operation-security.yml @@ -0,0 +1,212 @@ +asyncapi: "2.6.0" +info: + title: Streetlights Kafka API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you to remotely manage the city lights. + + ### Check out its awesome features: + + * Turn a specific streetlight on/off 🌃 + * Dim a specific streetlight 😎 + * Receive real-time information about environmental lighting conditions 📈 + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + +servers: + test: + url: test.mykafkacluster.org:8092 + protocol: kafka-secure + description: Test broker + security: + - saslScram: [] + test_oauth: + url: test.mykafkacluster.org:8093 + protocol: kafka-secure + description: Test port for oauth + security: + - streetlights_auth: + - streetlights:write + - streetlights:read + + +defaultContentType: application/json + +channels: + smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured: + description: The topic on which measured values may be produced and consumed. + servers: + - test + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + publish: + summary: Inform about environmental lighting conditions of a particular streetlight. + operationId: receiveLightMeasurement + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/lightMeasured' + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.on: + servers: + - test_oauth + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOn + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + security: + # This operation level security implies the ability to subscribe to messages from + # `smartylighting.streetlights.1.0.action.{streetlightId}.turn.on` channel with Authorization headers + # that have `streetlights:read` scope. Note that an operation level security must still satisfy + # security requirements specified at the server level. + - streetlights_auth: + - streetlights:read + + smartylighting.streetlights.1.0.action.{streetlightId}.turn.off: + servers: + - test_oauth + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: turnOff + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/turnOnOff' + security: + # This operation level security implies the ability to subscribe to messages from + # `smartylighting.streetlights.1.0.action.{streetlightId}.turn.off` channel with Authorization headers + # that have `streetlights:read` scope. Note that an operation level security must still satisfy + # security options specified at the server level. + - streetlights_auth: + - streetlights:read + smartylighting.streetlights.1.0.action.{streetlightId}.dim: + servers: + - test_oauth + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + subscribe: + operationId: dimLight + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dimLight' + security: + # This operation level security implies the ability to subscribe to messages from + # `smartylighting.streetlights.1.0.action.{streetlightId}.dim` channel with Authorization headers + # that have `streetlights:read` scope. Note that an operation level security must still satisfy + # security options specified at the server level. + - streetlights_auth: + - streetlights:read + + +components: + messages: + lightMeasured: + name: lightMeasured + title: Light measured + summary: Inform about environmental lighting conditions of a particular streetlight. + contentType: application/json + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/lightMeasuredPayload" + turnOnOff: + name: turnOnOff + title: Turn on/off + summary: Command a particular streetlight to turn the lights on or off. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/turnOnOffPayload" + dimLight: + name: dimLight + title: Dim light + summary: Command a particular streetlight to dim the lights. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dimLightPayload" + + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: "#/components/schemas/sentAt" + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: "#/components/schemas/sentAt" + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: "#/components/schemas/sentAt" + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + + securitySchemes: + saslScram: + type: scramSha256 + description: Provide your username and password for SASL/SCRAM authentication + streetlights_auth: + type: oauth2 + description: The oauth security descriptions + flows: + clientCredentials: + tokenUrl: 'https://example.com/api/oauth/dialog' + scopes: + streetlights:read: Scope required for subscribing to channel + streetlights:write: Scope required for publishing to channel + + parameters: + streetlightId: + description: The ID of the streetlight. + schema: + type: string + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + + operationTraits: + kafka: + bindings: + kafka: + clientId: + type: string + enum: ['my-app-id'] \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v2.6.0/websocket-gemini.yml b/asyncapi-core/src/test/resources/examples/v2.6.0/websocket-gemini.yml new file mode 100644 index 00000000..f9512ffa --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v2.6.0/websocket-gemini.yml @@ -0,0 +1,209 @@ +# +# +# +# This example showcases usage of AsyncAPI for the purpose of describing a WebSocket API. It is based on a real public service maintained by company called Gemini that provides cryptocurency trading products. It uses AsyncAPI bindings. +# +# This AsyncAPI document describes their v1 of the API. The v2 is also available and changes in the way that it provides a multimessage channel, where you subscribe for messages by sending a subscription message instead of using query parameters. For example with multimessage channel check out this article https://www.asyncapi.com/blog/websocket-part2 about another real public API called Kraken +# +# All available learning materials about AsyncAPI and WebSocket are: +# - WebSocket, Shrek, and AsyncAPI - An Opinionated Intro article: https://www.asyncapi.com/blog/websocket-part1 +# - Creating AsyncAPI for WebSocket API - Step by Step article: https://www.asyncapi.com/blog/websocket-part2 +# - From API-First to Code Generation - A WebSocket Use Case article: https://www.asyncapi.com/blog/websocket-part3 +# - Live stream about topics mentioned in part 1 and 2 articles: https://www.youtube.com/watch?v=8tFBcf31e_c +# + +asyncapi: "2.6.0" + +# +# Overal information for users of the application +# +info: + title: Gemini Market Data Websocket API + version: '1.0.0' + contact: + name: Gemini + url: https://www.gemini.com/ + description: | + Market data is a public API that streams all the market data on a given symbol. + + You can quickly play with the API using [websocat](https://github.com/vi/websocat#installation) like this: + ```bash + websocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S + ``` + +# +# Link to external docs +# +externalDocs: + url: https://docs.sandbox.gemini.com/websocket-api/#market-data + +# +# Details on how to connect to the application +# +servers: + public: + url: wss://api.gemini.com + protocol: wss + +# +# Details about all the channels that you can listen to or send to messages +# +channels: + /v1/marketdata/{symbol}: + parameters: + symbol: + description: | + Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. To read more click [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums). + schema: + type: string + enum: ['btcusd', 'ethbtc', 'ethusd', 'zecusd', 'zecbtc', 'zeceth', 'zecbch', 'zecltc', 'bchusd', 'bchbtc', 'bcheth', 'ltcusd', 'ltcbtc', 'ltceth', 'ltcbch', 'batusd', 'daiusd', 'linkusd', 'oxtusd', 'batbtc', 'linkbtc', 'oxtbtc', 'bateth', 'linketh', 'oxteth', 'ampusd', 'compusd', 'paxgusd', 'mkrusd', 'zrxusd', 'kncusd', 'manausd', 'storjusd', 'snxusd', 'crvusd', 'balusd', 'uniusd', 'renusd', 'umausd', 'yfiusd', 'btcdai', 'ethdai', 'aaveusd', 'filusd', 'btceur', 'btcgbp', 'etheur', 'ethgbp', 'btcsgd', 'ethsgd', 'sklusd', 'grtusd', 'bntusd', '1inchusd', 'enjusd', 'lrcusd', 'sandusd', 'cubeusd', 'lptusd', 'bondusd', 'maticusd', 'injusd', 'sushiusd'] + bindings: + ws: + bindingVersion: 0.1.0 + query: + type: object + description: | + The semantics of entry type filtering is: + + If any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response + If no entry types filtering parameters are included in the url, then all entry types will appear in the response + + NOTE: top_of_book has no meaning and initial book events are empty when only trades is specified + properties: + heartbeat: + type: boolean + default: false + description: Optionally add this parameter and set to true to receive a heartbeat every 5 seconds + top_of_book: + type: boolean + default: false + description: If absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers. + bids: + type: boolean + default: true + description: Include bids in change events + offers: + type: boolean + default: true + description: Include asks in change events + trades: + type: boolean + default: true + description: Include trade events + auctions: + type: boolean + default: true + description: Include auction events + subscribe: + summary: Receive market updates on a given symbol + message: + $ref: '#/components/messages/marketData' + +# +# All reusable parts for readability and staying DRY +# +components: + messages: + marketData: + summary: Message with marked data information. + description: | + The initial response message will show the existing state of the order book. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled. + payload: + $ref: '#/components/schemas/market' + examples: + - name: updateMessage + summary: Example of an update message that contains a change in price information. + payload: + type: update + eventId: 36902233362 + timestamp: 1619769673 + timestampms: 1619769673527 + socket_sequence: 661 + events: + - type: change + side: bid + price: 54350.40 + remaining: 0.002 + delta: 0.002 + reason: place + - name: heartbeatMessage + summary: Example of additional heartbeat message when you enable them. + payload: + type: heartbeat + socket_sequence: 1656 + schemas: + market: + type: object + oneOf: + - $ref: '#/components/schemas/heartbeat' + - $ref: '#/components/schemas/update' + heartbeat: + allOf: + - properties: + type: + type: string + const: heartbeat + required: + - type + - $ref: '#/components/schemas/default' + update: + allOf: + - properties: + type: + type: string + const: update + eventId: + type: integer + description: A monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections. + events: + $ref: '#/components/schemas/events' + timestamp: + type: number + description: The timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead. + timestampms: + type: number + description: The timestamp in milliseconds for this group of events. + required: + - type + - eventId + - events + - timestamp + - timestampms + - $ref: '#/components/schemas/default' + default: + type: object + description: This object is always part of the payload. In case of type=heartbeat, these are the only fields. + required: + - type + - socket_sequence + properties: + socket_sequence: + type: integer + description: zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. If you choose to enable heartbeats, then heartbeat and update messages will share a single increasing sequence. See [Sequence Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers) for more information. + events: + type: array + description: Either a change to the order book, or the indication that a trade has occurred. + items: + type: object + additionalProperties: false + properties: + type: + type: string + enum: ['trade', 'change', 'auction, block_trade'] + price: + type: number + multipleOf: 0.01 + description: The price of this order book entry. + side: + type: string + enum: ['bid', 'side'] + reason: + type: string + enum: ['place', 'trade', 'cancel', 'initial'] + description: Indicates why the change has occurred. initial is for the initial response message, which will show the entire existing state of the order book. + remaining: + type: number + description: The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled. + delta: + type: number + description: The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining. \ No newline at end of file diff --git a/pom.xml b/pom.xml index cd008e0b..d833a672 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.asyncapi asyncapi - 1.0.0-EAP-3-SNAPSHOT + 1.0.0-EAP-3 AsyncAPI @@ -38,7 +38,7 @@ https://github.com/asyncapi/java-asyncapi - scm:git:https://github.com/asyncapi/java-asyncapi.git + scm:git:https://github.com/asyncapi/jasyncapi.git HEAD