From 0623badd46d4401ae0208224999e92a25efe3e24 Mon Sep 17 00:00:00 2001 From: arielmirra Date: Tue, 26 Mar 2024 15:56:40 -0300 Subject: [PATCH 1/4] chore: validate async 2.x APIs with 2.0 validation profile --- .../reports/async20/channel-servers.report | 16 +++++++++++++--- .../async20/messageIds-not-duplicated.report | 2 +- .../reports/async20/server-tags.report | 2 +- .../reports/async20/server-variable.report | 2 +- .../test/scala/amf/testing/ConfigProvider.scala | 6 ++++++ 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report b/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report index bc0701640e..513513a5d6 100644 --- a/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report @@ -1,4 +1,14 @@ ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/channel-servers.yaml -Profile: -Conforms: true -Number of results: 0 +Profile: ASYNC 2.0 +Conforms: false +Number of results: 1 + +Level: Violation + +- Constraint: http://a.ml/vocabularies/amf/resolution#undeclared-channel-server + Message: Server 'notDefinedServer' in channel 'users/signup' is not defined in the servers root object + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/channel-servers.yaml#/async-api/endpoint/users%2Fsignup/server/null_3 + Property: + Range: + Location: diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/messageIds-not-duplicated.report b/amf-cli/shared/src/test/resources/validations/reports/async20/messageIds-not-duplicated.report index f53d274238..45b912a2a8 100644 --- a/amf-cli/shared/src/test/resources/validations/reports/async20/messageIds-not-duplicated.report +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/messageIds-not-duplicated.report @@ -1,4 +1,4 @@ ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/messageIds-not-duplicated.yaml -Profile: +Profile: ASYNC 2.0 Conforms: true Number of results: 0 diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/server-tags.report b/amf-cli/shared/src/test/resources/validations/reports/async20/server-tags.report index ba09ba7502..cae0d61a4c 100644 --- a/amf-cli/shared/src/test/resources/validations/reports/async20/server-tags.report +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/server-tags.report @@ -1,4 +1,4 @@ ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/server-tags.yaml -Profile: +Profile: ASYNC 2.0 Conforms: true Number of results: 0 diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/server-variable.report b/amf-cli/shared/src/test/resources/validations/reports/async20/server-variable.report index 1faa03d619..2235b8e6a5 100644 --- a/amf-cli/shared/src/test/resources/validations/reports/async20/server-variable.report +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/server-variable.report @@ -1,4 +1,4 @@ ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/server-variable.yaml -Profile: +Profile: ASYNC 2.0 Conforms: true Number of results: 0 diff --git a/amf-cli/shared/src/test/scala/amf/testing/ConfigProvider.scala b/amf-cli/shared/src/test/scala/amf/testing/ConfigProvider.scala index a7d0e480b5..60315de804 100644 --- a/amf-cli/shared/src/test/scala/amf/testing/ConfigProvider.scala +++ b/amf-cli/shared/src/test/scala/amf/testing/ConfigProvider.scala @@ -15,6 +15,12 @@ object ConfigProvider { case Oas20 => OASConfiguration.OAS20() case Oas30 => OASConfiguration.OAS30() case AsyncApi20 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi21 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi22 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi23 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi24 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi25 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) + case AsyncApi26 => AsyncAPIConfiguration.Async20().withPlugin(NotFinishedAsync20ParsePlugin) case Grpc => GRPCConfiguration.GRPC() case GraphQL => GraphQLConfiguration.GraphQL() case GraphQLFederation => GraphQLFederationConfiguration.GraphQLFederation() From 7eafa17d0b31010aab4d13f896978a854c9f2957 Mon Sep 17 00:00:00 2001 From: arielmirra Date: Tue, 26 Mar 2024 17:09:50 -0300 Subject: [PATCH 2/4] W-14990427: add Solace Operation Binding validations --- .../SolaceOperationBindingParser.scala | 9 ++++-- .../validation/model/APIRawValidations.scala | 21 +++++++++++++ .../solace-binding-validations.yaml | 30 +++++++++++++++++++ .../async20/solace-binding-validations.report | 30 +++++++++++++++++++ ...c20UniquePlatformUnitValidationsTest.scala | 4 +++ 5 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml create mode 100644 amf-cli/shared/src/test/resources/validations/reports/async20/solace-binding-validations.report diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/operation/SolaceOperationBindingParser.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/operation/SolaceOperationBindingParser.scala index e50408338e..eb3b66ce86 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/operation/SolaceOperationBindingParser.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/operation/SolaceOperationBindingParser.scala @@ -25,7 +25,7 @@ object SolaceOperationBindingParser extends BindingParser[SolaceOperationBinding val map = entry.value.as[YMap] map.key("destinations").foreach { entry => - val destinations = entry.value.as[Seq[YMap]].map(destinationMap => parseDestination(binding, destinationMap)) + val destinations = entry.value.as[Seq[YMap]].map(parseDestination) binding.setArrayWithoutId(SolaceOperationBindingModel.Destinations, destinations) } @@ -36,13 +36,14 @@ object SolaceOperationBindingParser extends BindingParser[SolaceOperationBinding binding } - private def parseDestination(binding: SolaceOperationBinding, map: YMap)(implicit + private def parseDestination(map: YMap)(implicit ctx: AsyncWebApiContext ): SolaceOperationDestination = { val destination = SolaceOperationDestination(Annotations()) + map.key("destinationType", SolaceOperationDestinationModel.DestinationType in destination) - map.key("deliveryMode") match { // todo validate that it can only be 'direct' or 'persistent' + map.key("deliveryMode") match { case Some(value) => Some(value).foreach(SolaceOperationDestinationModel.DeliveryMode in destination) case None => setDefaultValue(destination, SolaceOperationDestinationModel.DeliveryMode, AmfScalar("persistent")) } @@ -65,7 +66,9 @@ object SolaceOperationBindingParser extends BindingParser[SolaceOperationBinding queueMap.key("topicSubscriptions", SolaceOperationQueueModel.TopicSubscriptions in queue) queueMap.key("accessType", SolaceOperationQueueModel.AccessType in queue) + queueMap.key("maxMsgSpoolSize", SolaceOperationQueueModel.MaxMsgSpoolSize in queue) + queueMap.key("maxTtl", SolaceOperationQueueModel.MaxTtl in queue) ctx.closedShape(queue, queueMap, "SolaceOperationQueue") diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala index c4504f81f5..b71502e191 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala @@ -1088,6 +1088,27 @@ object APIRawValidations extends CommonValidationDefinitions { constraint = sh("pattern"), value = "^(Api\\sKey|OAuth\\s2.0|http|httpApiKey|openIdConnect|userPassword|X509|symmetricEncryption|asymmetricEncryption|plain|scramSha256|scramSha512|gssapi|x-.+)$" + ), + AMFValidation( + message = "Invalid 'destinationType' value. The options are: 'queue' or 'topic'.", + owlClass = apiBinding("SolaceOperationDestination"), + owlProperty = apiBinding("destinationType"), + constraint = sh("in"), + value = "queue,topic" + ), + AMFValidation( + message = "Invalid 'deliveryMode' value. The options are: 'direct' or 'persistent'.", + owlClass = apiBinding("SolaceOperationDestination"), + owlProperty = apiBinding("deliveryMode"), + constraint = sh("in"), + value = "direct,persistent" + ), + AMFValidation( + message = "Invalid 'accessType' value. The options are: 'exclusive' or 'nonexclusive'.", + owlClass = apiBinding("SolaceOperationQueue"), + owlProperty = apiBinding("accessType"), + constraint = sh("in"), + value = "exclusive,nonexclusive" ) ) ++ baseApiValidations("AsyncAPI") diff --git a/amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml b/amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml new file mode 100644 index 0000000000..d30d832ba4 --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml @@ -0,0 +1,30 @@ +asyncapi: 2.3.0 +info: + title: test solace binding + version: 1.0.0 +servers: + theName: + url: some.com + protocol: solace + bindings: + solace: + msgVpn: test + bindingVersion: 1.2.3 +channels: + some-channel: + publish: + bindings: + solace: + bindingVersion: 0.3.0 + destinations: + - destinationType: wrong destinationType # 'queue' or 'topic' + deliveryMode: wrong deliveryMode # 'direct' or 'persistent' + queue: + name: CreatedHREvents + accessType: wrong accessType # 'exclusive' or 'nonexclusive' + topicSubscriptions: + - person/*/created + - destinationType: topic + topic: + topicSubscriptions: + - person/*/updated \ No newline at end of file diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/solace-binding-validations.report b/amf-cli/shared/src/test/resources/validations/reports/async20/solace-binding-validations.report new file mode 100644 index 0000000000..27ce744991 --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/solace-binding-validations.report @@ -0,0 +1,30 @@ +ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml +Profile: ASYNC 2.0 +Conforms: false +Number of results: 3 + +Level: Violation + +- Constraint: http://a.ml/vocabularies/amf/parser#SolaceOperationDestination-destinationType-in + Message: Invalid 'destinationType' value. The options are: 'queue' or 'topic'. + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/operation-bindings/bindings/solace-operation/destinations/solace-destination + Property: http://a.ml/vocabularies/apiBinding#destinationType + Range: [(20,31)-(20,52)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#SolaceOperationDestination-deliveryMode-in + Message: Invalid 'deliveryMode' value. The options are: 'direct' or 'persistent'. + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/operation-bindings/bindings/solace-operation/destinations/solace-destination + Property: http://a.ml/vocabularies/apiBinding#deliveryMode + Range: [(21,28)-(21,46)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#SolaceOperationQueue-accessType-in + Message: Invalid 'accessType' value. The options are: 'exclusive' or 'nonexclusive'. + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/operation-bindings/bindings/solace-operation/destinations/solace-destination/solace-queue + Property: http://a.ml/vocabularies/apiBinding#accessType + Range: [(24,28)-(24,44)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/solace-binding-validations.yaml diff --git a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala index 64247428c5..0cd7b8ae2a 100644 --- a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala +++ b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala @@ -387,4 +387,8 @@ class Async20UniquePlatformUnitValidationsTest extends UniquePlatformReportGenTe test("Async 2.6+ Pulsar missing fields validation") { validate("pulsar-binding-missing-key.yaml", Some("pulsar-binding-missing-key.report")) } + + test("Async 2.3+ Solace validations") { + validate("solace-binding-validations.yaml", Some("solace-binding-validations.report")) + } } From 3351adad2aa78241eb5f7e10f8b656d69a3d1da5 Mon Sep 17 00:00:00 2001 From: arielmirra Date: Wed, 27 Mar 2024 16:34:55 -0300 Subject: [PATCH 3/4] W-14990427: add AnypointMQ Binding validations --- .../validation/model/APIRawValidations.scala | 12 ++++++ .../shacl/APICustomShaclFunctions.scala | 38 ++++++++++++++++++- .../anypoint-binding-validations.yaml | 31 +++++++++++++++ .../anypoint-binding-validations.report | 30 +++++++++++++++ .../reports/async20/channel-servers.report | 2 +- ...c20UniquePlatformUnitValidationsTest.scala | 4 ++ 6 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml create mode 100644 amf-cli/shared/src/test/resources/validations/reports/async20/anypoint-binding-validations.report diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala index b71502e191..40f8f2ca86 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala @@ -1109,6 +1109,18 @@ object APIRawValidations extends CommonValidationDefinitions { owlProperty = apiBinding("accessType"), constraint = sh("in"), value = "exclusive,nonexclusive" + ), + AMFValidation( + message = "Invalid 'destinationType' value. The options are: 'exchange', 'queue' or 'fifo-queue'.", + owlClass = apiBinding("AnypointMQChannelBinding"), + owlProperty = apiBinding("destinationType"), + constraint = sh("in"), + value = "exchange,queue,fifo-queue" + ), + AMFValidation( + owlClass = apiBinding("AnypointMQMessageBinding"), + owlProperty = apiBinding("headers"), + constraint = shape("anypointMQHeadersValidation") ) ) ++ baseApiValidations("AsyncAPI") diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala index 11821bfc76..0733c1e87b 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala @@ -2,10 +2,16 @@ package amf.apicontract.internal.validation.shacl import amf.apicontract.client.scala.model.domain.{EndPoint, Request} import amf.apicontract.client.scala.model.domain.api.{Api, WebApi} +import amf.apicontract.client.scala.model.domain.bindings.anypointmq.AnypointMQMessageBinding import amf.apicontract.client.scala.model.domain.security.{OAuth2Settings, OpenIdConnectSettings, SecurityScheme} import amf.apicontract.internal.metamodel.domain._ import amf.apicontract.internal.metamodel.domain.api.BaseApiModel -import amf.apicontract.internal.metamodel.domain.bindings.{BindingHeaders, BindingQuery, HttpMessageBindingModel} +import amf.apicontract.internal.metamodel.domain.bindings.{ + AnypointMQMessageBindingModel, + BindingHeaders, + BindingQuery, + HttpMessageBindingModel +} import amf.apicontract.internal.metamodel.domain.security.{ OAuth2SettingsModel, OpenIdConnectSettingsModel, @@ -741,6 +747,36 @@ object APICustomShaclFunctions extends BaseCustomShaclFunctions { case _ => // ignore } } + }, + new CustomShaclFunction { + override val name: String = "anypointMQHeadersValidation" + + override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = { + + element.asInstanceOf[AnypointMQMessageBinding].headers match { + case node: NodeShape => + node.fields.?[AmfArray](NodeShapeModel.Properties) match { + case Some(_) => // ignore + case None => + validate( + validationInfo( + AnypointMQMessageBindingModel.Headers, + "AnypointMQ Message Binding 'headers' field must have a 'properties' field", + element.annotations + ) + ) + } + + case elem => + validate( + validationInfo( + AnypointMQMessageBindingModel.Headers, + "AnypointMQ Message Binding 'headers' field must be an object", + elem.annotations + ) + ) + } + } } ) diff --git a/amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml b/amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml new file mode 100644 index 0000000000..2e0c8d2eaa --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml @@ -0,0 +1,31 @@ +asyncapi: 2.2.0 +info: + title: test anypoint binding + version: 1.0.0 +channels: + some-channel: + bindings: + anypointmq: + destination: user-signup-exchg + destinationType: wrong destinationType # MUST be either exchange or queue or fifo-queue + bindingVersion: '0.1.0' + publish: + message: + bindings: + anypointmq: + headers: + type: string # MUST be an object + bindingVersion: '0.1.0' + payload: + type: string + + other-channel: + publish: + message: + bindings: + anypointmq: + headers: + type: object # MUST have a 'properties' field + bindingVersion: '0.1.0' + payload: + type: string diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/anypoint-binding-validations.report b/amf-cli/shared/src/test/resources/validations/reports/async20/anypoint-binding-validations.report new file mode 100644 index 0000000000..182579d532 --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/anypoint-binding-validations.report @@ -0,0 +1,30 @@ +ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml +Profile: ASYNC 2.0 +Conforms: false +Number of results: 3 + +Level: Violation + +- Constraint: http://a.ml/vocabularies/amf/parser#AnypointMQChannelBinding-destinationType-in + Message: Invalid 'destinationType' value. The options are: 'exchange', 'queue' or 'fifo-queue'. + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/anypointmq-channel + Property: http://a.ml/vocabularies/apiBinding#destinationType + Range: [(10,25)-(10,46)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#AnypointMQMessageBinding-headers-anypointMQHeadersValidation + Message: AnypointMQ Message Binding 'headers' field must be an object + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/expects/request/message-bindings/bindings/anypointmq-message + Property: http://a.ml/vocabularies/apiBinding#headers + Range: [(16,20)-(18,0)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#AnypointMQMessageBinding-headers-anypointMQHeadersValidation + Message: AnypointMQ Message Binding 'headers' field must have a 'properties' field + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml#/async-api/endpoint/other-channel/supportedOperation/publish/expects/request/message-bindings/bindings/anypointmq-message + Property: http://a.ml/vocabularies/apiBinding#headers + Range: [(26,10)-(30,0)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/anypoint-binding-validations.yaml diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report b/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report index 513513a5d6..61a60084ec 100644 --- a/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/channel-servers.report @@ -8,7 +8,7 @@ Level: Violation - Constraint: http://a.ml/vocabularies/amf/resolution#undeclared-channel-server Message: Server 'notDefinedServer' in channel 'users/signup' is not defined in the servers root object Severity: Violation - Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/channel-servers.yaml#/async-api/endpoint/users%2Fsignup/server/null_3 + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/channel-servers.yaml#/async-api/endpoint/users%2Fsignup/servers/null_3 Property: Range: Location: diff --git a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala index 0cd7b8ae2a..eec080b520 100644 --- a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala +++ b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala @@ -391,4 +391,8 @@ class Async20UniquePlatformUnitValidationsTest extends UniquePlatformReportGenTe test("Async 2.3+ Solace validations") { validate("solace-binding-validations.yaml", Some("solace-binding-validations.report")) } + + test("Async 2.2+ AnypointMQ validations") { + validate("anypoint-binding-validations.yaml", Some("anypoint-binding-validations.report")) + } } From d11a3e9c152f4cc2cc4a38fa5b98c2107589b9e4 Mon Sep 17 00:00:00 2001 From: arielmirra Date: Wed, 3 Apr 2024 12:43:20 -0300 Subject: [PATCH 4/4] W-14990427: add IBMMQ Binding validations --- .../bindings/ibmmq/IBMMQChannelBinding.scala | 5 +- .../channel/IBMMQChannelBindingParser.scala | 5 +- .../message/IBMMQMessageBindingParser.scala | 12 +-- .../validation/model/APIRawValidations.scala | 67 +++++++++++++++ .../shacl/APICustomShaclFunctions.scala | 37 +++++++- .../ibmmq-binding-parsing-validations.yaml | 11 +++ .../ibmmq-binding-validations.yaml | 38 ++++++++ .../ibmmq-binding-parsing-validations.report | 14 +++ .../async20/ibmmq-binding-validations.report | 86 +++++++++++++++++++ ...c20UniquePlatformUnitValidationsTest.scala | 8 ++ 10 files changed, 273 insertions(+), 10 deletions(-) create mode 100644 amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml create mode 100644 amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml create mode 100644 amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-parsing-validations.report create mode 100644 amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-validations.report diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/client/scala/model/domain/bindings/ibmmq/IBMMQChannelBinding.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/client/scala/model/domain/bindings/ibmmq/IBMMQChannelBinding.scala index 1be578cb55..73381a335c 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/client/scala/model/domain/bindings/ibmmq/IBMMQChannelBinding.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/client/scala/model/domain/bindings/ibmmq/IBMMQChannelBinding.scala @@ -13,7 +13,6 @@ import amf.core.client.scala.model.{BoolField, IntField, StrField} import amf.core.internal.metamodel.Field import amf.core.internal.parser.domain.{Annotations, Fields} import amf.shapes.client.scala.model.domain.Key -import amf.core.client.scala.model.domain._ class IBMMQChannelBinding(override val fields: Fields, override val annotations: Annotations) extends ChannelBinding @@ -64,7 +63,7 @@ class IBMMQChannelQueue(override val fields: Fields, override val annotations: A def isPartitioned: BoolField = fields.field(IBMMQChannelQueueModel.IsPartitioned) def exclusive: BoolField = fields.field(IBMMQChannelQueueModel.Exclusive) - def withObjectName(objectName: String): this.type = set(IBMMQChannelQueueModel.ObjectName, objectName) + def withObjectName(objectName: String): this.type = set(IBMMQChannelQueueModel.ObjectName, objectName) def withIsPartitioned(isPartitioned: Boolean): this.type = set(IBMMQChannelQueueModel.IsPartitioned, isPartitioned) def withExclusive(exclusive: Boolean): this.type = set(IBMMQChannelQueueModel.Exclusive, exclusive) @@ -87,7 +86,7 @@ class IBMMQChannelTopic(override val fields: Fields, override val annotations: A override def nameField: Field = IBMMQChannelTopicModel.Name - def string: StrField = fields.field(IBMMQChannelTopicModel.String) + def string: StrField = fields.field(IBMMQChannelTopicModel.String) def objectName: StrField = fields.field(IBMMQChannelTopicModel.ObjectName) def durablePermitted: BoolField = fields.field(IBMMQChannelTopicModel.DurablePermitted) def lastMsgRetained: BoolField = fields.field(IBMMQChannelTopicModel.LastMsgRetained) diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/channel/IBMMQChannelBindingParser.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/channel/IBMMQChannelBindingParser.scala index 3bd325ae1d..229eae7c78 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/channel/IBMMQChannelBindingParser.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/channel/IBMMQChannelBindingParser.scala @@ -46,7 +46,10 @@ object IBMMQChannelBindingParser extends BindingParser[IBMMQChannelBinding] { val queue = IBMMQChannelQueue(Annotations(entry.value)) val queueMap = entry.value.as[YMap] - queueMap.key("objectName", IBMMQChannelQueueModel.ObjectName in queue) + queueMap.key("objectName") match { + case Some(value) => Some(value).foreach(IBMMQChannelQueueModel.ObjectName in queue) + case None => missingRequiredFieldViolation(ctx, binding, "objectName", "IBMMQ Channel Queue") + } queueMap.key("isPartitioned") match { case Some(value) => Some(value).foreach(IBMMQChannelQueueModel.IsPartitioned in queue) diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/message/IBMMQMessageBindingParser.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/message/IBMMQMessageBindingParser.scala index d553f8e2cb..36c44f9675 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/message/IBMMQMessageBindingParser.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/spec/async/parser/bindings/message/IBMMQMessageBindingParser.scala @@ -21,11 +21,13 @@ object IBMMQMessageBindingParser extends BindingParser[IBMMQMessageBinding] { map.key("headers").foreach { entry => val values = entry.value.toString.split(",").map(AmfScalar(_)).toSeq - binding.setWithoutId( - IBMMQMessageBindingModel.Headers, - AmfArray(values, Annotations.virtual()), - Annotations(entry) - ) + if (values.nonEmpty) { + binding.setWithoutId( + IBMMQMessageBindingModel.Headers, + AmfArray(values, Annotations.virtual()), + Annotations(entry) + ) + } } map.key("description", IBMMQMessageBindingModel.Description in binding) diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala index 40f8f2ca86..e9bbe110f7 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/model/APIRawValidations.scala @@ -1121,6 +1121,73 @@ object APIRawValidations extends CommonValidationDefinitions { owlClass = apiBinding("AnypointMQMessageBinding"), owlProperty = apiBinding("headers"), constraint = shape("anypointMQHeadersValidation") + ), + AMFValidation( + message = "IBMMQ Server Binding 'heartBeatInterval' field must be a number between 0-999999", + owlClass = apiBinding("IBMMQServerBinding"), + owlProperty = apiBinding("heartBeatInterval"), + constraint = sh("pattern"), + value = "^[0-999999]$" + ), + AMFValidation( + message = "IBMMQ Channel Binding 'destinationType' field must be either 'topic' or 'queue'", + owlClass = apiBinding("IBMMQChannelBinding"), + owlProperty = apiBinding("destinationType"), + constraint = sh("in"), + value = "topic,queue" + ), + AMFValidation( + message = "IBMMQ queue 'objectName' field MUST NOT exceed 48 characters in length", + owlClass = apiBinding("IBMMQChannelQueue"), + owlProperty = apiBinding("objectName"), + constraint = sh("maxLength"), + value = "48" + ), + AMFValidation( + message = "'queue' and 'topic' fields MUST NOT coexist within an IBMMQ channel binding", + owlClass = apiBinding("IBMMQChannelBinding"), + owlProperty = apiBinding("queue"), + constraint = shape("IBMMQDestinationValidation") + ), + AMFValidation( + message = "IBMMQ topic 'string' field MUST NOT exceed 10240 characters in length", + owlClass = apiBinding("IBMMQChannelTopic"), + owlProperty = apiBinding("string"), + constraint = sh("maxLength"), + value = "10240" + ), + AMFValidation( + message = "IBMMQ topic 'objectName' field MUST NOT exceed 48 characters in length", + owlClass = apiBinding("IBMMQChannelTopic"), + owlProperty = apiBinding("objectName"), + constraint = sh("maxLength"), + value = "48" + ), + AMFValidation( + message = "IBMMQ channel Binding 'maxMsgLength' field must be a number between 0-104857600 (100MB)", + owlClass = apiBinding("IBMMQChannelBinding"), + owlProperty = apiBinding("maxMsgLength"), + constraint = sh("pattern"), + value = "^[0-104857600]$" + ), + AMFValidation( + message = "IBMMQ message Binding 'type' field must be either 'string', 'jms' or 'binary'", + owlClass = apiBinding("IBMMQMessageBinding"), + owlProperty = apiBinding("messageType"), + constraint = sh("in"), + value = "string,jms,binary" + ), + AMFValidation( + message = "IBMMQ message Binding 'expiry' field must be 0 or greater", + owlClass = apiBinding("IBMMQMessageBinding"), + owlProperty = apiBinding("expiry"), + constraint = sh("minInclusive") + ), + AMFValidation( + message = "IBMMQ message Binding 'headers' MUST NOT be specified if 'type' field is 'string' or 'jms'", + owlClass = apiBinding("IBMMQMessageBinding"), + owlProperty = apiBinding("headers"), + constraint = shape("IBMMQHeadersValidation") ) ) ++ baseApiValidations("AsyncAPI") diff --git a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala index 0733c1e87b..476838973f 100644 --- a/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala +++ b/amf-api-contract/shared/src/main/scala/amf/apicontract/internal/validation/shacl/APICustomShaclFunctions.scala @@ -3,6 +3,7 @@ package amf.apicontract.internal.validation.shacl import amf.apicontract.client.scala.model.domain.{EndPoint, Request} import amf.apicontract.client.scala.model.domain.api.{Api, WebApi} import amf.apicontract.client.scala.model.domain.bindings.anypointmq.AnypointMQMessageBinding +import amf.apicontract.client.scala.model.domain.bindings.ibmmq.{IBMMQChannelBinding, IBMMQMessageBinding} import amf.apicontract.client.scala.model.domain.security.{OAuth2Settings, OpenIdConnectSettings, SecurityScheme} import amf.apicontract.internal.metamodel.domain._ import amf.apicontract.internal.metamodel.domain.api.BaseApiModel @@ -10,7 +11,9 @@ import amf.apicontract.internal.metamodel.domain.bindings.{ AnypointMQMessageBindingModel, BindingHeaders, BindingQuery, - HttpMessageBindingModel + HttpMessageBindingModel, + IBMMQChannelBindingModel, + IBMMQMessageBindingModel } import amf.apicontract.internal.metamodel.domain.security.{ OAuth2SettingsModel, @@ -777,6 +780,38 @@ object APICustomShaclFunctions extends BaseCustomShaclFunctions { ) } } + }, + new CustomShaclFunction { + override val name: String = "IBMMQDestinationValidation" + + override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = { + val binding = element.asInstanceOf[IBMMQChannelBinding] + if (binding.topic != null && binding.queue != null) { + validate( + validationInfo( + IBMMQChannelBindingModel.Queue, + "'queue' and 'topic' fields MUST NOT coexist within an IBMMQ channel binding", + element.annotations + ) + ) + } + } + }, + new CustomShaclFunction { + override val name: String = "IBMMQHeadersValidation" + + override def run(element: AmfObject, validate: Option[ValidationInfo] => Unit): Unit = { + val binding = element.asInstanceOf[IBMMQMessageBinding] + if (Seq("string", "jms").contains(binding.messageType.value()) && binding.headers.nonEmpty) { + validate( + validationInfo( + IBMMQMessageBindingModel.Headers, + "headers MUST NOT be specified if type = string or jms in an IBMMQ Message Binding", + element.annotations + ) + ) + } + } } ) diff --git a/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml b/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml new file mode 100644 index 0000000000..cbb130b573 --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml @@ -0,0 +1,11 @@ +asyncapi: 2.1.0 +info: + title: test binding + version: 1.0.0 +channels: + some-channel: + bindings: + ibmmq: + destinationType: queue + # 10. objectName is REQUIRED inside queue + queue: { } diff --git a/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml b/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml new file mode 100644 index 0000000000..481e9e2f93 --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml @@ -0,0 +1,38 @@ +asyncapi: 2.1.0 +info: + title: test binding + version: 1.0.0 +servers: + theName: + url: some.com + protocol: ibmmq + bindings: + ibmmq: + heartBeatInterval: 999999999 # 1. MUST be 0-999999 +channels: + some-channel: + bindings: + # 2. queue and topic fields MUST NOT coexist within an ibmmq channel binding + ibmmq: + destinationType: wrong destination # 3. MUST be either topic or queue + queue: + objectName: this is a very long object name that exceeds 48 chars # 4. MUST NOT exceed 48 characters in length + topic: + string: # 5. MUST NOT exceed 10240 characters in length + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris quis urna at enim ultrices finibus id id diam. Etiam nibh ex, luctus ac varius at, scelerisque in libero. Quisque porttitor enim a nulla tempus cursus. Quisque aliquam in dolor vitae suscipit. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Donec dapibus nec ligula sit amet placerat. Donec consectetur, felis et facilisis dictum, mauris leo vestibulum metus, nec posuere odio justo eget arcu. Nullam mattis ultricies iaculis. Pellentesque id nisi tortor. Cras et rhoncus tortor. In sed nisi at massa ultrices fringilla ac et turpis. Fusce ornare ultrices arcu nec lobortis. Phasellus id dolor neque. Aenean erat arcu, maximus sed sagittis sit amet, efficitur at sem. Praesent ligula nisl, ultrices id dui sed, porttitor imperdiet dolor. In ullamcorper pulvinar metus, nec auctor eros eleifend et.Sed efficitur tincidunt leo eu ullamcorper. Duis porttitor nec diam et placerat. Quisque egestas nibh non lectus finibus suscipit. Ut efficitur ullamcorper tincidunt. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis bibendum elit eget justo egestas, ac rutrum justo suscipit. Nullam lacinia lorem mi, vel interdum eros molestie non. Vestibulum euismod rutrum ante, at gravida nulla venenatis nec. Sed hendrerit interdum fermentum. In ut massa diam. Pellentesque pretium vel eros sit amet porttitor. Sed malesuada, mi eu consequat finibus, massa risus dapibus felis, quis commodo dui lectus vel nisi. Nullam at purus a neque consequat fringilla. Donec at augue lorem. Proin ut augue enim.Donec maximus ex ut urna interdum, vitae sollicitudin massa sollicitudin. Fusce porttitor mauris augue, nec dictum lorem ornare et. Vestibulum in erat a est sodales pellentesque non in ante. Nunc consectetur lobortis ex sit amet porttitor. Etiam sed dignissim augue. Sed ac sem nibh. In feugiat, nunc quis finibus interdum, nunc dui auctor felis, eu molestie leo velit sit amet elit. Morbi a vehicula neque. Phasellus vel ex semper, pellentesque est et, ullamcorper neque. Pellentesque vitae hendrerit odio. Sed nibh risus, porttitor et felis ac, eleifend rhoncus quam. Aenean malesuada euismod imperdiet. Donec neque lacus, rhoncus vel augue ut, euismod ornare metus. Curabitur tortor purus, consequat ut tortor at, vulputate tempus leo. Proin sit amet erat est.Suspendisse vehicula ultricies ornare. Sed pharetra eu tellus et dapibus. Curabitur iaculis magna vel nisl fringilla bibendum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur facilisis orci quis sollicitudin venenatis. Aliquam vel venenatis nibh. Vivamus a hendrerit velit. Suspendisse semper nec diam eu feugiat. Nulla at sem sollicitudin, gravida dolor at, pulvinar tellus. Ut tempor, lectus ut tincidunt ullamcorper, dui urna tempor mi, ut accumsan odio lectus sed libero.Praesent aliquet vel sem et fermentum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Integer leo est, iaculis nec iaculis id, tempus id mi. Etiam sit amet viverra neque. Nullam vestibulum augue eleifend, dapibus arcu ut, congue nisi. Sed nisl nisl, blandit faucibus eleifend ut, fermentum quis dui. Mauris sed sem ornare, aliquet elit et, dignissim libero. Mauris vitae mi velit. Maecenas quis est at ligula condimentum tincidunt eget sed lorem. Cras sit amet felis vehicula felis varius aliquam. Ut vehicula nisi lobortis eros euismod bibendum. Maecenas euismod quis nisi sagittis consequat.Cras euismod blandit diam et tincidunt. Donec accumsan porta felis, at auctor erat malesuada vitae. Aliquam vel nulla porttitor, pretium eros at, ornare enim. Cras ultrices turpis quis mollis consectetur. Pellentesque pretium nunc eget sodales iaculis. Praesent aliquam venenatis mi eget facilisis. Vestibulum id blandit massa. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aenean urna tellus, gravida posuere bibendum in, suscipit at sapien. In hac habitasse platea dictumst. In iaculis sodales vehicula. Suspendisse laoreet laoreet ante at sagittis.Proin congue fermentum ante eu interdum. Sed aliquet imperdiet eros vel facilisis. Donec neque enim, elementum eu porta eget, tristique id arcu. Nam faucibus nisi non tortor sollicitudin sollicitudin. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi massa quam, consectetur pulvinar accumsan nec, interdum sit amet mi. Suspendisse luctus ac magna in auctor. Donec et turpis ultrices, finibus turpis non, pulvinar purus. Vivamus volutpat nibh ex. Nunc quis velit nisl. Donec at orci ac risus luctus efficitur. Ut congue rutrum cursus. Pellentesque ultricies sagittis arcu quis volutpat. Pellentesque vel magna neque. Nulla varius dui in mi euismod, ac semper risus bibendum. Aenean at mauris posuere, aliquet sem vitae, sodales eros. Quisque ultrices sagittis enim tristique malesuada. Suspendisse libero turpis, sodales eget ornare at, mattis non felis. Sed ut enim nec tortor sodales finibus nec sed orci. Mauris ac justo vitae leo sollicitudin ultrices non gravida ante. Pellentesque pharetra orci eget dapibus scelerisque. Proin non nisi fermentum, tristique lacus ac, pellentesque lacus.Donec ac leo ultrices, mollis elit vitae, sollicitudin augue. Donec hendrerit sapien id purus cursus facilisis. Donec volutpat consequat posuere. Vivamus pellentesque ex faucibus, dignissim urna ac, consequat felis. Donec nec lobortis dolor, et mollis erat. Cras vitae aliquam justo. Curabitur ullamcorper, risus eget auctor lacinia, justo magna laoreet ante, vitae posuere ligula risus quis ex. Nunc tortor massa, tincidunt sed volutpat at, consectetur et ante. Aenean elementum magna vel est blandit, condimentum ornare erat tempor. Vivamus lacinia metus lobortis suscipit sodales. Aliquam nec eros at nunc vulputate sodales. In molestie gravida lectus, non tempus sem bibendum non. Ut vehicula velit quis porta varius. Cras pellentesque ex consectetur felis tincidunt, nec ultrices sapien bibendum. Suspendisse maximus a elit a fringilla. Nulla non felis in erat commodo tincidunt tincidunt a tellus. In augue sapien, efficitur vitae blandit sit amet, ultrices sit amet ex. Proin faucibus, augue nec viverra iaculis, ligula lorem mollis nisl, quis interdum massa sem sed turpis. Proin bibendum, orci ac sollicitudin gravida, nisl metus porttitor arcu, at ornare sem urna sed ipsum. Mauris pellentesque consequat lorem, eu interdum dolor congue sed. Sed rutrum euismod metus, ut volutpat libero dictum in. Ut ut est pulvinar, tristique massa eu, varius risus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nullam non risus nulla. Proin tristique, ligula nec dignissim lobortis, eros erat finibus ex, eu interdum dui magna et tellus.Nulla ultricies ante nunc, sed bibendum ipsum rhoncus elementum. Quisque a auctor est, sit amet condimentum felis. Sed semper nunc quis laoreet scelerisque. Integer at mi ut sem hendrerit cursus. Quisque vitae sem sit amet mi pretium posuere. Nam tortor erat, ornare sit amet lorem dignissim, ultrices bibendum nibh. Praesent hendrerit id sem sed imperdiet. Sed consectetur rhoncus neque finibus hendrerit. Aliquam porta diam quis finibus ultrices. Duis tristique dolor ut placerat sodales. Proin purus nibh, convallis in consequat quis, sagittis at velit.Sed sit amet gravida elit, in elementum dolor. In orci urna, tincidunt a ante eu, porta condimentum nisi. Duis varius nisl a tempus aliquet. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed vestibulum, lorem in dapibus viverra, tortor nibh porta ligula, sit amet ullamcorper arcu nunc vel est. Curabitur quis metus pharetra, accumsan diam non, malesuada nibh. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur arcu metus, rhoncus id aliquet a, rutrum ac lorem. Phasellus aliquam purus ac magna tincidunt faucibus. Sed mollis velit sed neque aliquam, et auctor nisl condimentum. Proin et diam condimentum, volutpat orci eu, blandit nisl. Curabitur nunc nunc, porttitor et nunc in, volutpat accumsan enim. Etiam eu sapien efficitur, elementum erat dapibus, imperdiet elit. Nunc ultricies sodales leo non facilisis.Sed rhoncus turpis eu pellentesque dignissim. Etiam augue augue, porttitor quis sapien non, iaculis venenatis neque. Sed vel neque varius, facilisis mi vel, euismod elit. Nunc congue arcu ut mauris aliquet condimentum. Vestibulum sit amet cursus turpis. Integer tincidunt venenatis pellentesque. Nunc ullamcorper magna nisl, vitae elementum felis gravida nec. Nunc id eleifend massa. Nulla id finibus odio. Cras ut interdum mi.Vestibulum ac lacus felis. Vestibulum nibh ex, condimentum et interdum ac, vestibulum gravida quam. Aenean molestie sodales urna, ut tempus risus pulvinar nec. Cras quis volutpat sapien. Phasellus quis risus ex. Nam nisl metus, egestas non rutrum a, tempus vel quam. Etiam interdum sed leo at mollis. Sed luctus lectus nulla, quis ultricies mi dictum ac. Nunc porta odio sed leo interdum, a consectetur magna ultricies. Sed accumsan felis erat, vel finibus risus pharetra sit amet.Donec lectus turpis, lobortis eget iaculis sit amet, tempus eget ante. Vestibulum at elementum orci. Phasellus ac nisl eu nisl commodo vulputate ornare ut leo. Mauris massa mi, volutpat non nibh in, accumsan auctor.Sed rhoncus turpis eu pellentesque dignissim. Etiam augue augue, porttitor quis sapien non, iaculis venenatis neque. Sed vel neque varius, facilisis mi vel, euismod elit. Nunc congue arcu ut mauris aliquet condimentum. Vestibulum sit amet cursus turpis. Integer tincidunt venenatis pellentesque. Nunc ullamcorper magna nisl, vitae elementum felis gravida nec. Nunc id eleifend massa. Nulla id finibus odio. Cras ut interdum mi.Vestibulum ac lacus felis. Vestibulum nibh ex, condimentum et interdum ac, vestibulum gravida quam. Aenean molestie sodales urna, ut tempus risus pulvinar nec. Cras quis volutpat sapien. Phasellus quis risus ex. Nam nisl metus, egestas non rutrum a, tempus vel quam. Etiam interdum sed leo at mollis. Sed luctus lectus nulla, quis ultricies mi dictum ac. Nunc porta odio sed leo interdum, a consectetur magna ultricies. Sed accumsan felis erat, vel finibus risus pharetra sit amet. + objectName: this is a very long object name that exceeds 48 chars # 6. MUST NOT exceed 48 characters in length + maxMsgLength: 104857601 # 7. MUST be 0-104,857,600 bytes (100 MB) + publish: + message: + bindings: + ibmmq: + type: test # 8. MUST be either string, jms or binary + expiry: -1 # 9. MUST be 0 or greater + + other-channel: + publish: + message: + bindings: + ibmmq: + type: jms + headers: test1, test2 # 10. MUST NOT be specified if type = string or jms diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-parsing-validations.report b/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-parsing-validations.report new file mode 100644 index 0000000000..d75c5b639c --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-parsing-validations.report @@ -0,0 +1,14 @@ +ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml +Profile: +Conforms: false +Number of results: 1 + +Level: Violation + +- Constraint: http://a.ml/vocabularies/amf/parser#required-field + Message: field 'objectName' is required in a IBMMQ Channel Queue + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel + Property: + Range: + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-parsing-validations.yaml diff --git a/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-validations.report b/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-validations.report new file mode 100644 index 0000000000..4994d47f7d --- /dev/null +++ b/amf-cli/shared/src/test/resources/validations/reports/async20/ibmmq-binding-validations.report @@ -0,0 +1,86 @@ +ModelId: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml +Profile: ASYNC 2.0 +Conforms: false +Number of results: 10 + +Level: Violation + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQServerBinding-heartBeatInterval-pattern + Message: IBMMQ Server Binding 'heartBeatInterval' field must be a number between 0-999999 + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/server/some.com/server-bindings/bindings/ibmmq-server + Property: http://a.ml/vocabularies/apiBinding#heartBeatInterval + Range: [(11,27)-(11,36)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelBinding-queue-IBMMQDestinationValidation + Message: 'queue' and 'topic' fields MUST NOT coexist within an IBMMQ channel binding + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel + Property: http://a.ml/vocabularies/apiBinding#queue + Range: [(16,6)-(25,0)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelBinding-destinationType-in + Message: IBMMQ Channel Binding 'destinationType' field must be either 'topic' or 'queue' + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel + Property: http://a.ml/vocabularies/apiBinding#destinationType + Range: [(17,25)-(17,42)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelQueue-objectName-maxLength + Message: IBMMQ queue 'objectName' field MUST NOT exceed 48 characters in length + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel/ibmmq-queue + Property: http://a.ml/vocabularies/apiBinding#objectName + Range: [(19,22)-(19,75)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelTopic-string-maxLength + Message: IBMMQ topic 'string' field MUST NOT exceed 10240 characters in length + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel/ibmmq-topic + Property: http://a.ml/vocabularies/apiBinding#string + Range: [(22,12)-(22,10279)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelTopic-objectName-maxLength + Message: IBMMQ topic 'objectName' field MUST NOT exceed 48 characters in length + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel/ibmmq-topic + Property: http://a.ml/vocabularies/apiBinding#objectName + Range: [(23,22)-(23,75)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQChannelBinding-maxMsgLength-pattern + Message: IBMMQ channel Binding 'maxMsgLength' field must be a number between 0-104857600 (100MB) + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/channel-bindings/bindings/ibmmq-channel + Property: http://a.ml/vocabularies/apiBinding#maxMsgLength + Range: [(24,22)-(24,31)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQMessageBinding-messageType-in + Message: IBMMQ message Binding 'type' field must be either 'string', 'jms' or 'binary' + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/expects/request/message-bindings/bindings/ibmmq-message + Property: http://a.ml/vocabularies/apiBinding#messageType + Range: [(29,18)-(29,22)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQMessageBinding-expiry-minInclusive + Message: IBMMQ message Binding 'expiry' field must be 0 or greater + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/some-channel/supportedOperation/publish/expects/request/message-bindings/bindings/ibmmq-message + Property: http://a.ml/vocabularies/apiBinding#expiry + Range: [(30,20)-(30,22)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml + +- Constraint: http://a.ml/vocabularies/amf/parser#IBMMQMessageBinding-headers-IBMMQHeadersValidation + Message: IBMMQ message Binding 'headers' MUST NOT be specified if 'type' field is 'string' or 'jms' + Severity: Violation + Target: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml#/async-api/endpoint/other-channel/supportedOperation/publish/expects/request/message-bindings/bindings/ibmmq-message + Property: http://a.ml/vocabularies/apiBinding#headers + Range: [(36,10)-(39,0)] + Location: file://amf-cli/shared/src/test/resources/validations/async20/validations/ibmmq-binding-validations.yaml diff --git a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala index eec080b520..649f4685e6 100644 --- a/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala +++ b/amf-cli/shared/src/test/scala/amf/validation/Async20UniquePlatformUnitValidationsTest.scala @@ -395,4 +395,12 @@ class Async20UniquePlatformUnitValidationsTest extends UniquePlatformReportGenTe test("Async 2.2+ AnypointMQ validations") { validate("anypoint-binding-validations.yaml", Some("anypoint-binding-validations.report")) } + + test("Async 2.1+ IBMMQ parsing validations") { + validate("ibmmq-binding-parsing-validations.yaml", Some("ibmmq-binding-parsing-validations.report")) + } + + test("Async 2.1+ IBMMQ validations") { + validate("ibmmq-binding-validations.yaml", Some("ibmmq-binding-validations.report")) + } }