diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 81c7b58d88..8f3c521907 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,6 +7,11 @@ assignees: '' --- + + **Describe the bug** A clear and concise description of what the bug is. @@ -23,16 +28,46 @@ A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] +**Zilla Environment:** + + +**Attach the `zilla.yaml` config file:** + +**Attach the `zilla dump` pcap file:** + +``` +ZILLA_INCUBATOR_ENABLED=true ./zilla dump --verbose --write /tmp/zilla.pcap +``` + +**Kafka Environment:** + +- Provider: [e.g. Kafka, Confluent, Redpanda] +- Version: [e.g. 22] +- Config: [e.g. log compaction, Sasl] -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] +**Client Environment:** + + - Service: [e.g. IoT, Microservice, REST client] + - Library/SDK: + - Browser: + - Version: **Additional context** Add any other context about the problem here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0e2f3c21e8..e105e8ff2f 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,11 +12,7 @@ updates: schedule: interval: daily - package-ecosystem: docker - directory: /cloud/docker-image/src/main/docker/release - schedule: - interval: daily -- package-ecosystem: docker - directory: /cloud/docker-image/src/main/docker/incubator + directory: /cloud/docker-image/src/main/docker schedule: interval: daily - package-ecosystem: github-actions diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e74b31566f..a8024d1a35 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 11, 17, 20 ] + java: [ 17, 21, 22 ] steps: - name: Checkout GitHub sources diff --git a/CHANGELOG.md b/CHANGELOG.md index 93393ccb4b..1848bc319c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,58 @@ ## [Unreleased](https://github.com/aklivity/zilla/tree/HEAD) -[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.78...HEAD) +[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.79...HEAD) + +**Breaking changes:** + +- Remove `zilla generate` command [\#960](https://github.com/aklivity/zilla/issues/960) +- Report unused properties based on binding definition [\#808](https://github.com/aklivity/zilla/issues/808) + +**Implemented enhancements:** + +- Update the Zilla issue Bug Report template with debugging info collection instructions [\#991](https://github.com/aklivity/zilla/issues/991) +- Support multiple specs in `openapi-asyncapi` binding [\#964](https://github.com/aklivity/zilla/issues/964) +- Integrate JMH into `tls` binding [\#961](https://github.com/aklivity/zilla/issues/961) +- Enhance validation for `openapi` and `asyncapi` bindings [\#950](https://github.com/aklivity/zilla/issues/950) +- Support multiple specs in `openapi` binding [\#949](https://github.com/aklivity/zilla/issues/949) +- Support multiple specs in `asyncapi` binding [\#948](https://github.com/aklivity/zilla/issues/948) +- Support `asyncapi` `mqtt` streetlights mapping to `kafka` streetlights [\#947](https://github.com/aklivity/zilla/issues/947) +- Support `mqtt` access log [\#945](https://github.com/aklivity/zilla/issues/945) +- Support `mqtt` client binding authorization [\#940](https://github.com/aklivity/zilla/issues/940) +- Resiliently handle `apicurio` catalog unreachable [\#938](https://github.com/aklivity/zilla/issues/938) +- Resiliently handle `karapace` catalog unreachable [\#937](https://github.com/aklivity/zilla/issues/937) +- Support local `zilla` installation on MacOS via `homebrew` [\#680](https://github.com/aklivity/zilla/issues/680) + +**Fixed bugs:** + +- Zilla crashes with `IllegalArgumentException` when an Avro payload is fetched as `json` [\#1025](https://github.com/aklivity/zilla/issues/1025) +- MQTT-Kafka qos2: increasing tracked producer sequence number without publishing to Kafka [\#1014](https://github.com/aklivity/zilla/issues/1014) +- OTLP `logs` signal doesn't show up in OpenTelemetry Demo [\#1006](https://github.com/aklivity/zilla/issues/1006) +- Flow control issue in openapi binding [\#1004](https://github.com/aklivity/zilla/issues/1004) +- `mqtt` connecting with longer client id fails [\#1003](https://github.com/aklivity/zilla/issues/1003) +- Running zilla with the `kafka-grpc` binding in a cluster with multiple instances results in each instance delivering a message to the configured `remote_server` [\#882](https://github.com/aklivity/zilla/issues/882) +- Using the `grpc.kafka.proxy` example setup, Zilla will periodically not deliver the message to the gRPC service defined in the `kafka-grpc` binding [\#881](https://github.com/aklivity/zilla/issues/881) +- Flaky kafka-grpc test [\#768](https://github.com/aklivity/zilla/issues/768) + +## [0.9.79](https://github.com/aklivity/zilla/tree/0.9.79) (2024-04-22) + +[Full Changelog](https://github.com/aklivity/zilla/compare/0.9.78...0.9.79) **Implemented enhancements:** - Support `filesystem` catalog for local schemas [\#908](https://github.com/aklivity/zilla/issues/908) +- Check for files on startup when the zilla.yaml specifies paths to files or directories [\#292](https://github.com/aklivity/zilla/issues/292) + +**Fixed bugs:** + +- Fix k3po does not reload labels when labels file size decreases [\#972](https://github.com/aklivity/zilla/pull/972) ([bmaidics](https://github.com/bmaidics)) + +**Merged pull requests:** + +- Support config for mqtt publish qos max [\#971](https://github.com/aklivity/zilla/pull/971) ([jfallows](https://github.com/jfallows)) +- Use default kafka client id for kafka client instance id [\#968](https://github.com/aklivity/zilla/pull/968) ([jfallows](https://github.com/jfallows)) +- Add vault parameter to exporter [\#966](https://github.com/aklivity/zilla/pull/966) ([attilakreiner](https://github.com/attilakreiner)) +- Implement filesystem catalog [\#962](https://github.com/aklivity/zilla/pull/962) ([bmaidics](https://github.com/bmaidics)) ## [0.9.78](https://github.com/aklivity/zilla/tree/0.9.78) (2024-04-16) diff --git a/build/flyweight-maven-plugin/pom.xml b/build/flyweight-maven-plugin/pom.xml index 835a1082cd..12dd0ae5c3 100644 --- a/build/flyweight-maven-plugin/pom.xml +++ b/build/flyweight-maven-plugin/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla build - 0.9.79 + 0.9.80 ../pom.xml diff --git a/build/pom.xml b/build/pom.xml index 86a6313d31..0589f7e41a 100644 --- a/build/pom.xml +++ b/build/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/cloud/docker-image/pom.xml b/cloud/docker-image/pom.xml index fb65026b3e..fdd6dd1ba0 100644 --- a/cloud/docker-image/pom.xml +++ b/cloud/docker-image/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla cloud - 0.9.79 + 0.9.80 ../pom.xml @@ -199,12 +199,6 @@ ${project.version} runtime - - ${project.groupId} - command-generate - ${project.version} - runtime - ${project.groupId} command-metrics diff --git a/cloud/docker-image/src/main/docker/Dockerfile b/cloud/docker-image/src/main/docker/Dockerfile index 876a1c77af..6717305625 100644 --- a/cloud/docker-image/src/main/docker/Dockerfile +++ b/cloud/docker-image/src/main/docker/Dockerfile @@ -25,7 +25,7 @@ RUN cat zpm.json.template | sed "s/\${VERSION}/${project.version}/g" | tee zpm.j RUN ./zpmw install --debug --exclude-remote-repositories RUN ./zpmw clean --keep-image -FROM ubuntu:jammy-20240111 +FROM ubuntu:jammy-20240427 ENV ZILLA_VERSION ${project.version} diff --git a/cloud/docker-image/src/main/docker/alpine.Dockerfile b/cloud/docker-image/src/main/docker/alpine.Dockerfile index 3103f97070..4dc74d18e9 100644 --- a/cloud/docker-image/src/main/docker/alpine.Dockerfile +++ b/cloud/docker-image/src/main/docker/alpine.Dockerfile @@ -27,7 +27,7 @@ RUN apk add --no-cache wget RUN ./zpmw install --debug --exclude-remote-repositories RUN ./zpmw clean --keep-image -FROM alpine:3.19.0 +FROM alpine:3.19.1 ENV ZILLA_VERSION ${project.version} diff --git a/cloud/docker-image/src/main/docker/zpm.json.template b/cloud/docker-image/src/main/docker/zpm.json.template index 392e048a10..46961f11bb 100644 --- a/cloud/docker-image/src/main/docker/zpm.json.template +++ b/cloud/docker-image/src/main/docker/zpm.json.template @@ -42,7 +42,6 @@ "io.aklivity.zilla:common", "io.aklivity.zilla:command", "io.aklivity.zilla:command-dump", - "io.aklivity.zilla:command-generate", "io.aklivity.zilla:command-metrics", "io.aklivity.zilla:command-start", "io.aklivity.zilla:command-stop", diff --git a/cloud/helm-chart/pom.xml b/cloud/helm-chart/pom.xml index 8867fc87fb..c01ff5d7f6 100644 --- a/cloud/helm-chart/pom.xml +++ b/cloud/helm-chart/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla cloud - 0.9.79 + 0.9.80 ../pom.xml diff --git a/cloud/pom.xml b/cloud/pom.xml index 2aeb72ff2e..d6c406172e 100644 --- a/cloud/pom.xml +++ b/cloud/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/conf/pom.xml b/conf/pom.xml index d0baf21a82..8fdd8361b7 100644 --- a/conf/pom.xml +++ b/conf/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/binding-amqp.spec/pom.xml b/incubator/binding-amqp.spec/pom.xml index 331009404b..c48b18baed 100644 --- a/incubator/binding-amqp.spec/pom.xml +++ b/incubator/binding-amqp.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/binding-amqp/pom.xml b/incubator/binding-amqp/pom.xml index d76570cb0f..61297a313b 100644 --- a/incubator/binding-amqp/pom.xml +++ b/incubator/binding-amqp/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/catalog-filesystem.spec/pom.xml b/incubator/catalog-filesystem.spec/pom.xml index 499001b2b9..68902b8bac 100644 --- a/incubator/catalog-filesystem.spec/pom.xml +++ b/incubator/catalog-filesystem.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/catalog-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/filesystem/config/event.yaml b/incubator/catalog-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/filesystem/config/event.yaml index 63872968f3..7200e67713 100644 --- a/incubator/catalog-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/filesystem/config/event.yaml +++ b/incubator/catalog-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/filesystem/config/event.yaml @@ -36,6 +36,7 @@ bindings: type: test kind: server options: - catalogs: - - catalog0 + catalog: + catalog0: + - subject: not-subject1 exit: app0 diff --git a/incubator/catalog-filesystem/pom.xml b/incubator/catalog-filesystem/pom.xml index 47e8191d91..9813714ff1 100644 --- a/incubator/catalog-filesystem/pom.xml +++ b/incubator/catalog-filesystem/pom.xml @@ -6,7 +6,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/catalog-filesystem/src/test/java/io/aklivity/zilla/runtime/catalog/filesystem/internal/EventIT.java b/incubator/catalog-filesystem/src/test/java/io/aklivity/zilla/runtime/catalog/filesystem/internal/EventIT.java index 21180d34df..e7b956eb83 100644 --- a/incubator/catalog-filesystem/src/test/java/io/aklivity/zilla/runtime/catalog/filesystem/internal/EventIT.java +++ b/incubator/catalog-filesystem/src/test/java/io/aklivity/zilla/runtime/catalog/filesystem/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/incubator/command-dump/pom.xml b/incubator/command-dump/pom.xml index f2fb397d84..7d2e7cc481 100644 --- a/incubator/command-dump/pom.xml +++ b/incubator/command-dump/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/command-dump/src/main/java/io/aklivity/zilla/runtime/command/dump/internal/airline/spy/OneToOneRingBufferSpy.java b/incubator/command-dump/src/main/java/io/aklivity/zilla/runtime/command/dump/internal/airline/spy/OneToOneRingBufferSpy.java index 81721342cd..dc5ab7394b 100644 --- a/incubator/command-dump/src/main/java/io/aklivity/zilla/runtime/command/dump/internal/airline/spy/OneToOneRingBufferSpy.java +++ b/incubator/command-dump/src/main/java/io/aklivity/zilla/runtime/command/dump/internal/airline/spy/OneToOneRingBufferSpy.java @@ -42,7 +42,7 @@ public OneToOneRingBufferSpy( final AtomicBuffer buffer) { this.buffer = buffer; - checkCapacity(buffer.capacity()); + checkCapacity(buffer.capacity(), 0); capacity = buffer.capacity() - TRAILER_LENGTH; buffer.verifyAlignment(); diff --git a/incubator/command-generate/COPYRIGHT b/incubator/command-generate/COPYRIGHT deleted file mode 100644 index 0cb10b6f62..0000000000 --- a/incubator/command-generate/COPYRIGHT +++ /dev/null @@ -1,12 +0,0 @@ -Copyright ${copyrightYears} Aklivity Inc - -Licensed under the Aklivity Community License (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - https://www.aklivity.io/aklivity-community-license/ - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. diff --git a/incubator/command-generate/LICENSE b/incubator/command-generate/LICENSE deleted file mode 100644 index f6abb6327b..0000000000 --- a/incubator/command-generate/LICENSE +++ /dev/null @@ -1,114 +0,0 @@ - Aklivity Community License Agreement - Version 1.0 - -This Aklivity Community License Agreement Version 1.0 (the “Agreement”) sets -forth the terms on which Aklivity, Inc. (“Aklivity”) makes available certain -software made available by Aklivity under this Agreement (the “Software”). BY -INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF THE SOFTWARE, -YOU AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE TO -SUCH TERMS AND CONDITIONS, YOU MUST NOT USE THE SOFTWARE. IF YOU ARE RECEIVING -THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU -HAVE THE ACTUAL AUTHORITY TO AGREE TO THE TERMS AND CONDITIONS OF THIS -AGREEMENT ON BEHALF OF SUCH ENTITY. “Licensee” means you, an individual, or -the entity on whose behalf you are receiving the Software. - - 1. LICENSE GRANT AND CONDITIONS. - - 1.1 License. Subject to the terms and conditions of this Agreement, - Aklivity hereby grants to Licensee a non-exclusive, royalty-free, - worldwide, non-transferable, non-sublicenseable license during the term - of this Agreement to: (a) use the Software; (b) prepare modifications and - derivative works of the Software; (c) distribute the Software (including - without limitation in source code or object code form); and (d) reproduce - copies of the Software (the “License”). Licensee is not granted the - right to, and Licensee shall not, exercise the License for an Excluded - Purpose. For purposes of this Agreement, “Excluded Purpose” means making - available any software-as-a-service, platform-as-a-service, - infrastructure-as-a-service or other similar online service that competes - with Aklivity products or services that provide the Software. - - 1.2 Conditions. In consideration of the License, Licensee’s distribution - of the Software is subject to the following conditions: - - (a) Licensee must cause any Software modified by Licensee to carry - prominent notices stating that Licensee modified the Software. - - (b) On each Software copy, Licensee shall reproduce and not remove or - alter all Aklivity or third party copyright or other proprietary - notices contained in the Software, and Licensee must provide the - notice below with each copy. - - “This software is made available by Aklivity, Inc., under the - terms of the Aklivity Community License Agreement, Version 1.0 - located at http://www.Aklivity.io/Aklivity-community-license. BY - INSTALLING, DOWNLOADING, ACCESSING, USING OR DISTRIBUTING ANY OF - THE SOFTWARE, YOU AGREE TO THE TERMS OF SUCH LICENSE AGREEMENT.” - - 1.3 Licensee Modifications. Licensee may add its own copyright notices - to modifications made by Licensee and may provide additional or different - license terms and conditions for use, reproduction, or distribution of - Licensee’s modifications. While redistributing the Software or - modifications thereof, Licensee may choose to offer, for a fee or free of - charge, support, warranty, indemnity, or other obligations. Licensee, and - not Aklivity, will be responsible for any such obligations. - - 1.4 No Sublicensing. The License does not include the right to - sublicense the Software, however, each recipient to which Licensee - provides the Software may exercise the Licenses so long as such recipient - agrees to the terms and conditions of this Agreement. - - 2. TERM AND TERMINATION. This Agreement will continue unless and until - earlier terminated as set forth herein. If Licensee breaches any of its - conditions or obligations under this Agreement, this Agreement will - terminate automatically and the License will terminate automatically and - permanently. - - 3. INTELLECTUAL PROPERTY. As between the parties, Aklivity will retain all - right, title, and interest in the Software, and all intellectual property - rights therein. Aklivity hereby reserves all rights not expressly granted - to Licensee in this Agreement. Aklivity hereby reserves all rights in its - trademarks and service marks, and no licenses therein are granted in this - Agreement. - - 4. DISCLAIMER. Aklivity HEREBY DISCLAIMS ANY AND ALL WARRANTIES AND - CONDITIONS, EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, AND SPECIFICALLY - DISCLAIMS ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR - PURPOSE, WITH RESPECT TO THE SOFTWARE. - - 5. LIMITATION OF LIABILITY. Aklivity WILL NOT BE LIABLE FOR ANY DAMAGES OF - ANY KIND, INCLUDING BUT NOT LIMITED TO, LOST PROFITS OR ANY CONSEQUENTIAL, - SPECIAL, INCIDENTAL, INDIRECT, OR DIRECT DAMAGES, HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, ARISING OUT OF THIS AGREEMENT. THE FOREGOING SHALL - APPLY TO THE EXTENT PERMITTED BY APPLICABLE LAW. - - 6.GENERAL. - - 6.1 Governing Law. This Agreement will be governed by and interpreted in - accordance with the laws of the state of California, without reference to - its conflict of laws principles. If Licensee is located within the - United States, all disputes arising out of this Agreement are subject to - the exclusive jurisdiction of courts located in Santa Clara County, - California. USA. If Licensee is located outside of the United States, - any dispute, controversy or claim arising out of or relating to this - Agreement will be referred to and finally determined by arbitration in - accordance with the JAMS International Arbitration Rules. The tribunal - will consist of one arbitrator. The place of arbitration will be Palo - Alto, California. The language to be used in the arbitral proceedings - will be English. Judgment upon the award rendered by the arbitrator may - be entered in any court having jurisdiction thereof. - - 6.2 Assignment. Licensee is not authorized to assign its rights under - this Agreement to any third party. Aklivity may freely assign its rights - under this Agreement to any third party. - - 6.3 Other. This Agreement is the entire agreement between the parties - regarding the subject matter hereof. No amendment or modification of - this Agreement will be valid or binding upon the parties unless made in - writing and signed by the duly authorized representatives of both - parties. In the event that any provision, including without limitation - any condition, of this Agreement is held to be unenforceable, this - Agreement and all licenses and rights granted hereunder will immediately - terminate. Waiver by Aklivity of a breach of any provision of this - Agreement or the failure by Aklivity to exercise any right hereunder - will not be construed as a waiver of any subsequent breach of that right - or as a waiver of any other right. \ No newline at end of file diff --git a/incubator/command-generate/NOTICE b/incubator/command-generate/NOTICE deleted file mode 100644 index 17478992e3..0000000000 --- a/incubator/command-generate/NOTICE +++ /dev/null @@ -1,18 +0,0 @@ -Licensed under the Aklivity Community License (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - https://www.aklivity.io/aklivity-community-license/ - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. - -This project includes: - Jackson-annotations under The Apache Software License, Version 2.0 - Jackson-core under The Apache Software License, Version 2.0 - jackson-databind under The Apache Software License, Version 2.0 - Jackson-dataformat-YAML under The Apache Software License, Version 2.0 - SnakeYAML under Apache License, Version 2.0 - diff --git a/incubator/command-generate/NOTICE.template b/incubator/command-generate/NOTICE.template deleted file mode 100644 index 209ca12f74..0000000000 --- a/incubator/command-generate/NOTICE.template +++ /dev/null @@ -1,13 +0,0 @@ -Licensed under the Aklivity Community License (the "License"); you may not use -this file except in compliance with the License. You may obtain a copy of the -License at - - https://www.aklivity.io/aklivity-community-license/ - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OF ANY KIND, either express or implied. See the License for the -specific language governing permissions and limitations under the License. - -This project includes: -#GENERATED_NOTICES# diff --git a/incubator/command-generate/mvnw b/incubator/command-generate/mvnw deleted file mode 100755 index d2f0ea3808..0000000000 --- a/incubator/command-generate/mvnw +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/incubator/command-generate/mvnw.cmd b/incubator/command-generate/mvnw.cmd deleted file mode 100644 index b26ab24f03..0000000000 --- a/incubator/command-generate/mvnw.cmd +++ /dev/null @@ -1,182 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/incubator/command-generate/pom.xml b/incubator/command-generate/pom.xml deleted file mode 100644 index 5d21938023..0000000000 --- a/incubator/command-generate/pom.xml +++ /dev/null @@ -1,213 +0,0 @@ - - - - 4.0.0 - - io.aklivity.zilla - incubator - 0.9.79 - ../pom.xml - - - command-generate - zilla::incubator::command-generate - - - - Aklivity Community License Agreement - https://www.aklivity.io/aklivity-community-license/ - repo - - - - - 11 - 11 - 0.60 - 4 - - - - - ${project.groupId} - engine.spec - ${project.version} - provided - - - ${project.groupId} - engine - ${project.version} - provided - - - ${project.groupId} - command - ${project.version} - provided - - - io.aklivity.zilla - binding-http - ${project.version} - provided - - - io.aklivity.zilla - binding-mqtt - ${project.version} - provided - - - io.aklivity.zilla - binding-tcp - ${project.version} - provided - - - io.aklivity.zilla - binding-tls - ${project.version} - provided - - - io.aklivity.zilla - guard-jwt - ${project.version} - provided - - - io.aklivity.zilla - catalog-inline - ${project.version} - provided - - - io.aklivity.zilla - model-avro - ${project.version} - provided - - - io.aklivity.zilla - model-core - ${project.version} - provided - - - io.aklivity.zilla - model-json - ${project.version} - provided - - - io.aklivity.zilla - model-protobuf - ${project.version} - provided - - - io.aklivity.zilla - vault-filesystem - ${project.version} - provided - - - com.fasterxml.jackson.dataformat - jackson-dataformat-yaml - 2.16.1 - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - - org.jasig.maven - maven-notice-plugin - - - com.mycila - license-maven-plugin - - - src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/**/* - src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/**/* - - - - - maven-checkstyle-plugin - - - org.apache.maven.plugins - maven-compiler-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - org.moditect - moditect-maven-plugin - - - org.apache.maven.plugins - maven-failsafe-plugin - - - org.jacoco - jacoco-maven-plugin - - - io/aklivity/zilla/runtime/command/generate/internal/types/**/*.class - io/aklivity/zilla/runtime/command/generate/internal/openapi/model/*.class - io/aklivity/zilla/runtime/command/generate/internal/openapi/model2/*.class - io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/*.class - io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model2/*.class - - - - BUNDLE - - - INSTRUCTION - COVEREDRATIO - ${jacoco.coverage.ratio} - - - CLASS - MISSEDCOUNT - ${jacoco.missed.count} - - - - - - - - ${project.groupId} - flyweight-maven-plugin - ${project.version} - - core - io.aklivity.zilla.runtime.command.generate.internal.types - - - - - generate - - - - - - - diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java deleted file mode 100644 index 836a0d113e..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ConfigGenerator.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.airline; - -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import jakarta.json.bind.Jsonb; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; - -import io.aklivity.zilla.runtime.engine.config.ModelConfig; -import io.aklivity.zilla.runtime.model.core.config.Int32ModelConfig; -import io.aklivity.zilla.runtime.model.core.config.StringModelConfig; - -public abstract class ConfigGenerator -{ - protected static final String INLINE_CATALOG_NAME = "catalog0"; - protected static final String INLINE_CATALOG_TYPE = "inline"; - protected static final String APPLICATION_JSON = "application/json"; - protected static final String VERSION_LATEST = "latest"; - protected static final Pattern JSON_CONTENT_TYPE = Pattern.compile("^application/(?:.+\\+)?json$"); - - protected final Map models = Map.of( - "string", StringModelConfig.builder().build(), - "integer", Int32ModelConfig.builder().build() - ); - protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher(""); - - public abstract String generate(); - - protected static String writeSchemaYaml( - Jsonb jsonb, - YAMLMapper yaml, - Object schema) - { - String result = null; - try - { - String schemaJson = jsonb.toJson(schema); - JsonNode json = new ObjectMapper().readTree(schemaJson); - result = yaml.writeValueAsString(json); - } - catch (JsonProcessingException ex) - { - rethrowUnchecked(ex); - } - return result; - } - - protected final String unquoteEnvVars( - String yaml, - List unquotedEnvVars) - { - for (String envVar : unquotedEnvVars) - { - yaml = yaml.replaceAll( - Pattern.quote(String.format("\"${{env.%s}}\"", envVar)), - String.format("\\${{env.%s}}", envVar) - ); - } - return yaml; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommand.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommand.java deleted file mode 100644 index c0a08a7400..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommand.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.airline; - -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.io.FileInputStream; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Map; -import java.util.function.Function; - -import com.github.rvesse.airline.annotations.Command; -import com.github.rvesse.airline.annotations.Option; -import com.github.rvesse.airline.annotations.restrictions.AllowedValues; -import com.github.rvesse.airline.annotations.restrictions.Required; - -import io.aklivity.zilla.runtime.command.ZillaCommand; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.http.proxy.AsyncApiHttpProxyConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.mqtt.proxy.AsyncApiMqttProxyConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.http.proxy.OpenApiHttpProxyConfigGenerator; - -@Command(name = "generate", description = "Generate configuration file") -public final class ZillaConfigCommand extends ZillaCommand -{ - private static final Map> GENERATORS = Map.of( - "openapi.http.proxy", OpenApiHttpProxyConfigGenerator::new, - "asyncapi.http.proxy", AsyncApiHttpProxyConfigGenerator::new, - "asyncapi.mqtt.proxy", AsyncApiMqttProxyConfigGenerator::new - ); - - @Option(name = {"-t", "--template"}, - description = "Template name") - @Required - @AllowedValues(allowedValues = { - "openapi.http.proxy", - "asyncapi.http.proxy", - "asyncapi.mqtt.proxy" - }) - public String template; - - @Option(name = {"-i", "--input"}, - description = "Input filename", - typeConverterProvider = ZillaConfigCommandPathConverterProvider.class) - public Path input; - - @Option(name = {"-o", "--output"}, - description = "Output filename", - typeConverterProvider = ZillaConfigCommandPathConverterProvider.class) - public Path output = Paths.get("zilla.yaml"); - - @Override - public void run() - { - try (InputStream inputStream = new FileInputStream(input.toFile())) - { - ConfigGenerator generator = GENERATORS.get(template).apply(inputStream); - Files.writeString(output, generator.generate()); - } - catch (Exception ex) - { - ex.printStackTrace(); - rethrowUnchecked(ex); - } - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommandPathConverterProvider.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommandPathConverterProvider.java deleted file mode 100644 index 403fdc7755..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/airline/ZillaConfigCommandPathConverterProvider.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.airline; - -import java.nio.file.Paths; - -import com.github.rvesse.airline.model.ArgumentsMetadata; -import com.github.rvesse.airline.model.OptionMetadata; -import com.github.rvesse.airline.parser.ParseState; -import com.github.rvesse.airline.types.TypeConverter; -import com.github.rvesse.airline.types.TypeConverterProvider; -import com.github.rvesse.airline.types.numerics.NumericTypeConverter; - -public final class ZillaConfigCommandPathConverterProvider implements TypeConverterProvider -{ - private final ZillaDumpCommandPathConverter converter = new ZillaDumpCommandPathConverter(); - - private final class ZillaDumpCommandPathConverter implements TypeConverter - { - @Override - public void setNumericConverter( - NumericTypeConverter converter) - { - } - - @Override - public Object convert( - String name, - Class type, - String value) - { - return Paths.get(value); - } - } - - @Override - public TypeConverter getTypeConverter( - OptionMetadata option, - ParseState state) - { - return converter; - } - - @Override - public TypeConverter getTypeConverter( - ArgumentsMetadata arguments, - ParseState state) - { - return converter; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/AsyncApiConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/AsyncApiConfigGenerator.java deleted file mode 100644 index 243d29dcaa..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/AsyncApiConfigGenerator.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi; - -import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.MINIMIZE_QUOTES; -import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER; -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.util.Map; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; - -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; - -import io.aklivity.zilla.runtime.catalog.inline.config.InlineOptionsConfig; -import io.aklivity.zilla.runtime.catalog.inline.config.InlineSchemaConfigBuilder; -import io.aklivity.zilla.runtime.command.generate.internal.airline.ConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.AsyncApi; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Message; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Schema; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.MessageView; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.SchemaView; -import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; - -public abstract class AsyncApiConfigGenerator extends ConfigGenerator -{ - protected AsyncApi asyncApi; - - protected boolean hasJsonContentType() - { - String contentType = null; - if (asyncApi.components != null && asyncApi.components.messages != null && !asyncApi.components.messages.isEmpty()) - { - Message firstMessage = asyncApi.components.messages.entrySet().stream().findFirst().get().getValue(); - contentType = MessageView.of(asyncApi.components.messages, firstMessage).contentType(); - } - return contentType != null && jsonContentType.reset(contentType).matches(); - } - - protected NamespaceConfigBuilder injectCatalog( - NamespaceConfigBuilder namespace) - { - if (asyncApi.components != null && asyncApi.components.schemas != null && !asyncApi.components.schemas.isEmpty()) - { - namespace - .catalog() - .name(INLINE_CATALOG_NAME) - .type(INLINE_CATALOG_TYPE) - .options(InlineOptionsConfig::builder) - .subjects() - .inject(this::injectSubjects) - .build() - .build() - .build(); - - } - return namespace; - } - - protected InlineSchemaConfigBuilder injectSubjects( - InlineSchemaConfigBuilder subjects) - { - try (Jsonb jsonb = JsonbBuilder.create()) - { - YAMLMapper yaml = YAMLMapper.builder() - .disable(WRITE_DOC_START_MARKER) - .enable(MINIMIZE_QUOTES) - .build(); - for (Map.Entry entry : asyncApi.components.schemas.entrySet()) - { - SchemaView schema = SchemaView.of(asyncApi.components.schemas, entry.getValue()); - subjects - .subject(entry.getKey()) - .version(VERSION_LATEST) - .schema(writeSchemaYaml(jsonb, yaml, schema)) - .build(); - } - } - catch (Exception ex) - { - rethrowUnchecked(ex); - } - return subjects; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java deleted file mode 100644 index cba4f9c148..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGenerator.java +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.http.proxy; - -import static io.aklivity.zilla.runtime.binding.http.config.HttpPolicyConfig.CROSS_ORIGIN; -import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT; -import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER; -import static java.util.Objects.requireNonNull; -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.io.InputStream; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import jakarta.json.Json; -import jakarta.json.JsonPatch; -import jakarta.json.JsonPatchBuilder; -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; - -import io.aklivity.zilla.runtime.binding.http.config.HttpConditionConfig; -import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig; -import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfigBuilder; -import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfig.Method; -import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfigBuilder; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpConditionConfig; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig; -import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.AsyncApiConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.AsyncApi; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Item; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Message; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Operation; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Parameter; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Server; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.ChannelView; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.MessageView; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.ServerView; -import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.EngineConfig; -import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter; -import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.ModelConfig; -import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder; -import io.aklivity.zilla.runtime.guard.jwt.config.JwtOptionsConfig; -import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; -import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig; - -public class AsyncApiHttpProxyConfigGenerator extends AsyncApiConfigGenerator -{ - private final InputStream input; - - private int[] allPorts; - private int[] httpPorts; - private int[] httpsPorts; - private boolean isPlainEnabled; - private boolean isTlsEnabled; - private Map securitySchemes; - private String authorizationHeader; - private boolean isJwtEnabled; - - public AsyncApiHttpProxyConfigGenerator( - InputStream input) - { - this.input = input; - } - - @Override - public String generate() - { - this.asyncApi = parseAsyncApi(input); - this.allPorts = resolveAllPorts(); - this.httpPorts = resolvePortsForScheme("http"); - this.httpsPorts = resolvePortsForScheme("https"); - this.isPlainEnabled = httpPorts != null; - this.isTlsEnabled = httpsPorts != null; - this.securitySchemes = resolveSecuritySchemes(); - this.authorizationHeader = resolveAuthorizationHeader(); - this.isJwtEnabled = !securitySchemes.isEmpty(); - EngineConfigWriter configWriter = new EngineConfigWriter(null); - String yaml = configWriter.write(createConfig(), createEnvVarsPatch()); - return unquoteEnvVars(yaml, unquotedEnvVars()); - } - - private AsyncApi parseAsyncApi( - InputStream inputStream) - { - AsyncApi asyncApi = null; - try (Jsonb jsonb = JsonbBuilder.create()) - { - asyncApi = jsonb.fromJson(inputStream, AsyncApi.class); - } - catch (Exception ex) - { - rethrowUnchecked(ex); - } - return asyncApi; - } - - private int[] resolveAllPorts() - { - int[] ports = new int[asyncApi.servers.size()]; - String[] keys = asyncApi.servers.keySet().toArray(String[]::new); - for (int i = 0; i < asyncApi.servers.size(); i++) - { - ServerView server = ServerView.of(asyncApi.servers.get(keys[i])); - URI url = server.url(); - ports[i] = url.getPort(); - } - return ports; - } - - private int[] resolvePortsForScheme( - String scheme) - { - requireNonNull(scheme); - int[] ports = null; - URI url = findFirstServerUrlWithScheme(scheme); - if (url != null) - { - ports = new int[] {url.getPort()}; - } - return ports; - } - - private URI findFirstServerUrlWithScheme( - String scheme) - { - requireNonNull(scheme); - URI result = null; - for (String key : asyncApi.servers.keySet()) - { - ServerView server = ServerView.of(asyncApi.servers.get(key)); - if (scheme.equals(server.url().getScheme())) - { - result = server.url(); - break; - } - } - return result; - } - - private Map resolveSecuritySchemes() - { - requireNonNull(asyncApi); - Map result = new HashMap<>(); - if (asyncApi.components != null && asyncApi.components.securitySchemes != null) - { - for (String securitySchemeName : asyncApi.components.securitySchemes.keySet()) - { - String guardType = asyncApi.components.securitySchemes.get(securitySchemeName).bearerFormat; - if ("jwt".equals(guardType)) - { - result.put(securitySchemeName, guardType); - } - } - } - return result; - } - - private String resolveAuthorizationHeader() - { - requireNonNull(asyncApi); - requireNonNull(asyncApi.components); - String result = null; - if (asyncApi.components.messages != null) - { - for (Map.Entry entry : asyncApi.components.messages.entrySet()) - { - Message message = entry.getValue(); - if (message.headers != null && message.headers.properties != null) - { - Item authorization = message.headers.properties.get("authorization"); - if (authorization != null) - { - result = authorization.description; - break; - } - } - } - } - return result; - } - - private EngineConfig createConfig() - { - return EngineConfig.builder() - .namespace() - .name("example") - .binding() - .name("tcp_server0") - .type("tcp") - .kind(SERVER) - .options(TcpOptionsConfig::builder) - .host("0.0.0.0") - .ports(allPorts) - .build() - .inject(this::injectPlainTcpRoute) - .inject(this::injectTlsTcpRoute) - .build() - .inject(this::injectTlsServer) - .binding() - .name("http_server0") - .type("http") - .kind(SERVER) - .options(HttpOptionsConfig::builder) - .access() - .policy(CROSS_ORIGIN) - .build() - .inject(this::injectHttpServerOptions) - .inject(this::injectHttpServerRequests) - .build() - .inject(this::injectHttpServerRoutes) - .build() - .binding() - .name("http_client0") - .type("http") - .kind(CLIENT) - .exit(isTlsEnabled ? "tls_client0" : "tcp_client0") - .build() - .inject(this::injectTlsClient) - .binding() - .name("tcp_client0") - .type("tcp") - .kind(CLIENT) - .options(TcpOptionsConfig::builder) - .host("") // env - .ports(new int[]{0}) // env - .build() - .build() - .inject(this::injectGuard) - .inject(this::injectVaults) - .inject(this::injectCatalog) - .build() - .build(); - } - - private BindingConfigBuilder injectPlainTcpRoute( - BindingConfigBuilder binding) - { - if (isPlainEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(httpPorts) - .build() - .exit("http_server0") - .build(); - } - return binding; - } - - private BindingConfigBuilder injectTlsTcpRoute( - BindingConfigBuilder binding) - { - if (isTlsEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(httpsPorts) - .build() - .exit("tls_server0") - .build(); - } - return binding; - } - - private NamespaceConfigBuilder injectTlsServer( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_server0") - .type("tls") - .kind(SERVER) - .options(TlsOptionsConfig::builder) - .keys(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .build() - .vault("server") - .exit("http_server0") - .build(); - } - return namespace; - } - - private HttpOptionsConfigBuilder injectHttpServerOptions( - HttpOptionsConfigBuilder options) - { - if (isJwtEnabled) - { - options - .authorization() - .name("jwt0") - .credentials() - .header() - .name("authorization") - .pattern(authorizationHeader) - .build() - .build() - .build(); - } - return options; - } - - private HttpOptionsConfigBuilder injectHttpServerRequests( - HttpOptionsConfigBuilder options) - { - for (String name : asyncApi.operations.keySet()) - { - Operation operation = asyncApi.operations.get(name); - ChannelView channel = ChannelView.of(asyncApi.channels, operation.channel); - String path = channel.address(); - Method method = Method.valueOf(operation.bindings.get("http").method); - if (channel.messages() != null && !channel.messages().isEmpty() || - channel.parameters() != null && !channel.parameters().isEmpty()) - { - options - .request() - .path(path) - .method(method) - .inject(request -> injectContent(request, channel.messages())) - .inject(request -> injectPathParams(request, channel.parameters())) - .build(); - } - } - return options; - } - - private HttpRequestConfigBuilder injectContent( - HttpRequestConfigBuilder request, - Map messages) - { - if (messages != null) - { - if (hasJsonContentType()) - { - request. - content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .inject(catalog -> injectSchemas(catalog, messages)) - .build() - .build(); - } - } - return request; - } - - private CatalogedConfigBuilder injectSchemas( - CatalogedConfigBuilder catalog, - Map messages) - { - for (String name : messages.keySet()) - { - MessageView message = MessageView.of(asyncApi.components.messages, messages.get(name)); - String subject = message.refKey() != null ? message.refKey() : name; - catalog - .schema() - .subject(subject) - .build() - .build(); - } - return catalog; - } - - private HttpRequestConfigBuilder injectPathParams( - HttpRequestConfigBuilder request, - Map parameters) - { - if (parameters != null) - { - for (String name : parameters.keySet()) - { - Parameter parameter = parameters.get(name); - if (parameter.schema != null && parameter.schema.type != null) - { - ModelConfig model = models.get(parameter.schema.type); - if (model != null) - { - request - .pathParam() - .name(name) - .model(model) - .build(); - } - } - } - } - return request; - } - - - private BindingConfigBuilder injectHttpServerRoutes( - BindingConfigBuilder binding) - { - for (Map.Entry entry : asyncApi.servers.entrySet()) - { - ServerView server = ServerView.of(entry.getValue()); - for (String name : asyncApi.operations.keySet()) - { - Operation operation = asyncApi.operations.get(name); - ChannelView channel = ChannelView.of(asyncApi.channels, operation.channel); - String path = channel.address().replaceAll("\\{[^}]+\\}", "*"); - String method = operation.bindings.get("http").method; - binding - .route() - .exit("http_client0") - .when(HttpConditionConfig::builder) - .header(":scheme", server.scheme()) - .header(":authority", server.authority()) - .header(":path", path) - .header(":method", method) - .build() - .inject(route -> injectHttpServerRouteGuarded(route, server)) - .build(); - } - } - return binding; - } - - private RouteConfigBuilder injectHttpServerRouteGuarded( - RouteConfigBuilder route, - ServerView server) - { - if (server.security() != null) - { - for (Map> securityItem : server.security()) - { - for (String securityItemLabel : securityItem.keySet()) - { - if (isJwtEnabled && "jwt".equals(securitySchemes.get(securityItemLabel))) - { - route - .guarded() - .name("jwt0") - .inject(guarded -> injectGuardedRoles(guarded, securityItem.get(securityItemLabel))) - .build(); - break; - } - } - } - } - return route; - } - - private GuardedConfigBuilder injectGuardedRoles( - GuardedConfigBuilder guarded, - List roles) - { - for (String role : roles) - { - guarded.role(role); - } - return guarded; - } - - private NamespaceConfigBuilder injectTlsClient( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_client0") - .type("tls") - .kind(CLIENT) - .options(TlsOptionsConfig::builder) - .trust(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .trustcacerts(true) - .build() - .vault("client") - .exit("tcp_client0") - .build(); - } - return namespace; - } - - private NamespaceConfigBuilder injectGuard( - NamespaceConfigBuilder namespace) - { - if (isJwtEnabled) - { - namespace - .guard() - .name("jwt0") - .type("jwt") - .options(JwtOptionsConfig::builder) - .issuer("") // env - .audience("") // env - .key() - .alg("").kty("").kid("").use("").n("").e("").crv("").x("").y("") // env - .build() - .build() - .build(); - } - return namespace; - } - - private NamespaceConfigBuilder injectVaults( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .vault() - .name("client") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .trust() - .store("") // env - .type("") // env - .password("") // env - .build() - .build() - .build() - .vault() - .name("server") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .keys() - .store("") // env - .type("") // env - .password("") //env - .build() - .build() - .build(); - } - return namespace; - } - - private JsonPatch createEnvVarsPatch() - { - JsonPatchBuilder patch = Json.createPatchBuilder(); - patch.replace("/bindings/tcp_client0/options/host", "${{env.TCP_CLIENT_HOST}}"); - patch.replace("/bindings/tcp_client0/options/port", "${{env.TCP_CLIENT_PORT}}"); - - if (isJwtEnabled) - { - // jwt0 guard - patch.replace("/guards/jwt0/options/issuer", "${{env.JWT_ISSUER}}"); - patch.replace("/guards/jwt0/options/audience", "${{env.JWT_AUDIENCE}}"); - patch.replace("/guards/jwt0/options/keys/0/alg", "${{env.JWT_ALG}}"); - patch.replace("/guards/jwt0/options/keys/0/kty", "${{env.JWT_KTY}}"); - patch.replace("/guards/jwt0/options/keys/0/kid", "${{env.JWT_KID}}"); - patch.replace("/guards/jwt0/options/keys/0/use", "${{env.JWT_USE}}"); - patch.replace("/guards/jwt0/options/keys/0/n", "${{env.JWT_N}}"); - patch.replace("/guards/jwt0/options/keys/0/e", "${{env.JWT_E}}"); - patch.replace("/guards/jwt0/options/keys/0/crv", "${{env.JWT_CRV}}"); - patch.replace("/guards/jwt0/options/keys/0/x", "${{env.JWT_X}}"); - patch.replace("/guards/jwt0/options/keys/0/y", "${{env.JWT_Y}}"); - } - - if (isTlsEnabled) - { - // tls_server0 binding - patch.replace("/bindings/tls_server0/options/keys/0", "${{env.TLS_SERVER_KEY}}"); - patch.replace("/bindings/tls_server0/options/sni/0", "${{env.TLS_SERVER_SNI}}"); - patch.replace("/bindings/tls_server0/options/alpn/0", "${{env.TLS_SERVER_ALPN}}"); - // tls_client0 binding - patch.replace("/bindings/tls_client0/options/trust/0", "${{env.TLS_CLIENT_TRUST}}"); - patch.replace("/bindings/tls_client0/options/sni/0", "${{env.TLS_CLIENT_SNI}}"); - patch.replace("/bindings/tls_client0/options/alpn/0", "${{env.TLS_CLIENT_ALPN}}"); - // client vault - patch.replace("/vaults/client/options/trust/store", "${{env.TRUSTSTORE_PATH}}"); - patch.replace("/vaults/client/options/trust/type", "${{env.TRUSTSTORE_TYPE}}"); - patch.replace("/vaults/client/options/trust/password", "${{env.TRUSTSTORE_PASSWORD}}"); - // server vault - patch.replace("/vaults/server/options/keys/store", "${{env.KEYSTORE_PATH}}"); - patch.replace("/vaults/server/options/keys/type", "${{env.KEYSTORE_TYPE}}"); - patch.replace("/vaults/server/options/keys/password", "${{env.KEYSTORE_PASSWORD}}"); - } - - return patch.build(); - } - - private List unquotedEnvVars() - { - return List.of("TCP_CLIENT_PORT"); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/AsyncApi.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/AsyncApi.java deleted file mode 100644 index 3379ddefd8..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/AsyncApi.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.Map; - -public class AsyncApi -{ - public Map servers; - public Map channels; - public Map operations; - public Components components; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Binding.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Binding.java deleted file mode 100644 index 0e15d732e4..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Binding.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -public class Binding -{ - public String method; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Channel.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Channel.java deleted file mode 100644 index 29ed4bc9e0..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Channel.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.LinkedHashMap; - -import jakarta.json.bind.annotation.JsonbProperty; - -public class Channel -{ - public String address; - public LinkedHashMap messages; - public LinkedHashMap parameters; - - @JsonbProperty("$ref") - public String ref; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Components.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Components.java deleted file mode 100644 index 9288e3e2a6..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Components.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.SecurityScheme; - -public class Components -{ - public Map securitySchemes; - public Map messages; - public Map schemas; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Item.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Item.java deleted file mode 100644 index 42ed3d6c2d..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Item.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -public class Item -{ - public String type; - public String description; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Message.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Message.java deleted file mode 100644 index 18011a28f6..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Message.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import jakarta.json.bind.annotation.JsonbProperty; - -public class Message -{ - public Schema headers; - public String contentType; - - @JsonbProperty("$ref") - public String ref; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Operation.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Operation.java deleted file mode 100644 index 89551a6cc0..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Operation.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.Map; - -public class Operation -{ - public Map bindings; - public Channel channel; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Parameter.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Parameter.java deleted file mode 100644 index 7048bf9784..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Parameter.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -public class Parameter -{ - public Schema schema; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Schema.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Schema.java deleted file mode 100644 index be52cda60e..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Schema.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.List; -import java.util.Map; - -import jakarta.json.bind.annotation.JsonbProperty; - -public class Schema -{ - public String type; - public Schema items; - public Map properties; - public List required; - - @JsonbProperty("$ref") - public String ref; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/SecurityScheme.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/SecurityScheme.java deleted file mode 100644 index 137c290af5..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/SecurityScheme.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -public class SecurityScheme -{ - public String bearerFormat; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Server.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Server.java deleted file mode 100644 index 73e0eec68c..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/model/Server.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - -import java.util.List; -import java.util.Map; - -public class Server -{ - public String host; - public List>> security; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java deleted file mode 100644 index edc1d1d971..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGenerator.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.mqtt.proxy; - -import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT; -import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER; -import static java.util.Objects.requireNonNull; -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.io.InputStream; -import java.net.URI; -import java.util.List; -import java.util.Map; - -import jakarta.json.Json; -import jakarta.json.JsonPatch; -import jakarta.json.JsonPatchBuilder; -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; - -import io.aklivity.zilla.runtime.binding.mqtt.config.MqttConditionConfig; -import io.aklivity.zilla.runtime.binding.mqtt.config.MqttOptionsConfig; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpConditionConfig; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig; -import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.AsyncApiConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.AsyncApi; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Channel; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Message; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.MessageView; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view.ServerView; -import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.EngineConfig; -import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter; -import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; -import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; -import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig; - -public class AsyncApiMqttProxyConfigGenerator extends AsyncApiConfigGenerator -{ - private final InputStream input; - - private int[] allPorts; - private int[] mqttPorts; - private int[] mqttsPorts; - private boolean isPlainEnabled; - private boolean isTlsEnabled; - - public AsyncApiMqttProxyConfigGenerator( - InputStream input) - { - this.input = input; - } - - @Override - public String generate() - { - this.asyncApi = parseAsyncApi(input); - this.allPorts = resolveAllPorts(); - this.mqttPorts = resolvePortsForScheme("mqtt"); - this.mqttsPorts = resolvePortsForScheme("mqtts"); - this.isPlainEnabled = mqttPorts != null; - this.isTlsEnabled = mqttsPorts != null; - EngineConfigWriter configWriter = new EngineConfigWriter(null); - String yaml = configWriter.write(createConfig(), createEnvVarsPatch()); - return unquoteEnvVars(yaml, unquotedEnvVars()); - } - - private AsyncApi parseAsyncApi( - InputStream inputStream) - { - AsyncApi asyncApi = null; - try (Jsonb jsonb = JsonbBuilder.create()) - { - asyncApi = jsonb.fromJson(inputStream, AsyncApi.class); - } - catch (Exception ex) - { - rethrowUnchecked(ex); - } - return asyncApi; - } - - private int[] resolveAllPorts() - { - int[] ports = new int[asyncApi.servers.size()]; - String[] keys = asyncApi.servers.keySet().toArray(String[]::new); - for (int i = 0; i < asyncApi.servers.size(); i++) - { - ServerView server = ServerView.of(asyncApi.servers.get(keys[i])); - URI url = server.url(); - ports[i] = url.getPort(); - } - return ports; - } - - private int[] resolvePortsForScheme( - String scheme) - { - requireNonNull(scheme); - int[] ports = null; - URI url = findFirstServerUrlWithScheme(scheme); - if (url != null) - { - ports = new int[] {url.getPort()}; - } - return ports; - } - - private URI findFirstServerUrlWithScheme( - String scheme) - { - requireNonNull(scheme); - URI result = null; - for (String key : asyncApi.servers.keySet()) - { - ServerView server = ServerView.of(asyncApi.servers.get(key)); - if (scheme.equals(server.url().getScheme())) - { - result = server.url(); - break; - } - } - return result; - } - - private EngineConfig createConfig() - { - return EngineConfig.builder() - .namespace() - .name("example") - .binding() - .name("tcp_server0") - .type("tcp") - .kind(SERVER) - .options(TcpOptionsConfig::builder) - .host("0.0.0.0") - .ports(allPorts) - .build() - .inject(this::injectPlainTcpRoute) - .inject(this::injectTlsTcpRoute) - .build() - .inject(this::injectTlsServer) - .binding() - .name("mqtt_server0") - .type("mqtt") - .kind(SERVER) - .inject(this::injectMqttServerOptions) - .inject(this::injectMqttServerRoutes) - .build() - .binding() - .name("mqtt_client0") - .type("mqtt") - .kind(CLIENT) - .exit(isTlsEnabled ? "tls_client0" : "tcp_client0") - .build() - .inject(this::injectTlsClient) - .binding() - .name("tcp_client0") - .type("tcp") - .kind(CLIENT) - .options(TcpOptionsConfig::builder) - .host("") // env - .ports(new int[]{0}) // env - .build() - .build() - .inject(this::injectVaults) - .inject(this::injectCatalog) - .build() - .build(); - } - - private BindingConfigBuilder injectPlainTcpRoute( - BindingConfigBuilder binding) - { - if (isPlainEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(mqttPorts) - .build() - .exit("mqtt_server0") - .build(); - } - return binding; - } - - private BindingConfigBuilder injectTlsTcpRoute( - BindingConfigBuilder binding) - { - if (isTlsEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(mqttsPorts) - .build() - .exit("tls_server0") - .build(); - } - return binding; - } - - private NamespaceConfigBuilder injectTlsServer( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_server0") - .type("tls") - .kind(SERVER) - .options(TlsOptionsConfig::builder) - .keys(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .build() - .vault("server") - .exit("mqtt_server0") - .build(); - } - return namespace; - } - - private BindingConfigBuilder injectMqttServerOptions( - BindingConfigBuilder binding) - { - for (Map.Entry channelEntry : asyncApi.channels.entrySet()) - { - String topic = channelEntry.getValue().address.replaceAll("\\{[^}]+\\}", "*"); - Map messages = channelEntry.getValue().messages; - if (hasJsonContentType()) - { - binding - .options(MqttOptionsConfig::builder) - .topic() - .name(topic) - .content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .inject(cataloged -> injectJsonSchemas(cataloged, messages, APPLICATION_JSON)) - .build() - .build() - .build() - .build() - .build(); - } - } - return binding; - } - - private CatalogedConfigBuilder injectJsonSchemas( - CatalogedConfigBuilder cataloged, - Map messages, - String contentType) - { - for (Map.Entry messageEntry : messages.entrySet()) - { - MessageView message = MessageView.of(asyncApi.components.messages, messageEntry.getValue()); - String schema = messageEntry.getKey(); - if (message.contentType().equals(contentType)) - { - cataloged - .schema() - .subject(schema) - .build() - .build(); - } - else - { - throw new RuntimeException("Invalid content type"); - } - } - return cataloged; - } - - private BindingConfigBuilder injectMqttServerRoutes( - BindingConfigBuilder binding) - { - for (Map.Entry entry : asyncApi.channels.entrySet()) - { - String topic = entry.getValue().address.replaceAll("\\{[^}]+\\}", "*"); - binding - .route() - .when(MqttConditionConfig::builder) - .publish() - .topic(topic) - .build() - .build() - .when(MqttConditionConfig::builder) - .subscribe() - .topic(topic) - .build() - .build() - .exit("mqtt_client0") - .build(); - } - return binding; - } - - private NamespaceConfigBuilder injectTlsClient( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_client0") - .type("tls") - .kind(CLIENT) - .options(TlsOptionsConfig::builder) - .trust(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .trustcacerts(true) - .build() - .vault("client") - .exit("tcp_client0") - .build(); - } - return namespace; - } - - private NamespaceConfigBuilder injectVaults( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .vault() - .name("client") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .trust() - .store("") // env - .type("") // env - .password("") // env - .build() - .build() - .build() - .vault() - .name("server") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .keys() - .store("") // env - .type("") // env - .password("") //env - .build() - .build() - .build(); - } - return namespace; - } - - private JsonPatch createEnvVarsPatch() - { - JsonPatchBuilder patch = Json.createPatchBuilder(); - patch.replace("/bindings/tcp_client0/options/host", "${{env.TCP_CLIENT_HOST}}"); - patch.replace("/bindings/tcp_client0/options/port", "${{env.TCP_CLIENT_PORT}}"); - - if (isTlsEnabled) - { - // tls_server0 binding - patch.replace("/bindings/tls_server0/options/keys/0", "${{env.TLS_SERVER_KEY}}"); - patch.replace("/bindings/tls_server0/options/sni/0", "${{env.TLS_SERVER_SNI}}"); - patch.replace("/bindings/tls_server0/options/alpn/0", "${{env.TLS_SERVER_ALPN}}"); - // tls_client0 binding - patch.replace("/bindings/tls_client0/options/trust/0", "${{env.TLS_CLIENT_TRUST}}"); - patch.replace("/bindings/tls_client0/options/sni/0", "${{env.TLS_CLIENT_SNI}}"); - patch.replace("/bindings/tls_client0/options/alpn/0", "${{env.TLS_CLIENT_ALPN}}"); - // client vault - patch.replace("/vaults/client/options/trust/store", "${{env.TRUSTSTORE_PATH}}"); - patch.replace("/vaults/client/options/trust/type", "${{env.TRUSTSTORE_TYPE}}"); - patch.replace("/vaults/client/options/trust/password", "${{env.TRUSTSTORE_PASSWORD}}"); - // server vault - patch.replace("/vaults/server/options/keys/store", "${{env.KEYSTORE_PATH}}"); - patch.replace("/vaults/server/options/keys/type", "${{env.KEYSTORE_TYPE}}"); - patch.replace("/vaults/server/options/keys/password", "${{env.KEYSTORE_PASSWORD}}"); - } - - return patch.build(); - } - - private List unquotedEnvVars() - { - return List.of("TCP_CLIENT_PORT"); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ChannelView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ChannelView.java deleted file mode 100644 index bd0c7140d2..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ChannelView.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Channel; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Message; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Parameter; - -public final class ChannelView extends Resolvable -{ - private final Channel channel; - - private ChannelView( - Map channels, - Channel channel) - { - super(channels, "#/channels/(\\w+)"); - this.channel = channel.ref == null ? channel : resolveRef(channel.ref); - } - - public String address() - { - return channel.address; - } - - public Map messages() - { - return channel.messages; - } - - public Map parameters() - { - return channel.parameters; - } - - public static ChannelView of( - Map channels, - Channel channel) - { - return new ChannelView(channels, channel); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/MessageView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/MessageView.java deleted file mode 100644 index 6efa633313..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/MessageView.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Message; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Schema; - -public final class MessageView extends Resolvable -{ - private final Message message; - - private MessageView( - Map messages, - Message message) - { - super(messages, "#/components/messages/(\\w+)"); - this.message = message.ref == null ? message : resolveRef(message.ref); - } - - public String refKey() - { - return key; - } - - public Schema headers() - { - return message.headers; - } - - public String contentType() - { - return message.contentType; - } - - public static MessageView of( - Map messages, - Message message) - { - return new MessageView(messages, message); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/Resolvable.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/Resolvable.java deleted file mode 100644 index 70e2366cd3..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/Resolvable.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class Resolvable -{ - private final Map map; - private final Matcher matcher; - - protected String key; - - public Resolvable( - Map map, - String regex) - { - this.map = map; - this.matcher = Pattern.compile(regex).matcher(""); - } - - protected T resolveRef( - String ref) - { - T result = null; - if (matcher.reset(ref).matches()) - { - key = matcher.group(1); - result = map.get(key); - } - return result; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/SchemaView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/SchemaView.java deleted file mode 100644 index 71c633b2c1..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/SchemaView.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - -import java.util.List; -import java.util.Map; - -import jakarta.json.bind.annotation.JsonbPropertyOrder; - -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Item; -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Schema; - -@JsonbPropertyOrder({ - "type", - "items", - "properties", - "required" -}) -public final class SchemaView extends Resolvable -{ - private static final String ARRAY_TYPE = "array"; - - private final Schema schema; - private final Map schemas; - - private SchemaView( - Map schemas, - Schema schema) - { - super(schemas, "#/components/schemas/(\\w+)"); - if (schema.ref != null) - { - schema = resolveRef(schema.ref); - } - else if (ARRAY_TYPE.equals(schema.type) && schema.items != null && schema.items.ref != null) - { - schema.items = resolveRef(schema.items.ref); - } - this.schemas = schemas; - this.schema = schema; - } - - public String getType() - { - return schema.type; - } - - public SchemaView getItems() - { - return schema.items == null ? null : SchemaView.of(schemas, schema.items); - } - - public Map getProperties() - { - return schema.properties; - } - - public List getRequired() - { - return schema.required; - } - - public static SchemaView of( - Map schemas, - Schema schema) - { - return new SchemaView(schemas, schema); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ServerView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ServerView.java deleted file mode 100644 index 7cf4fb977d..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/view/ServerView.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - -import java.net.URI; -import java.util.List; -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model.Server; - -public final class ServerView -{ - private final Server server; - - private ServerView( - Server server) - { - this.server = server; - } - - public URI url() - { - return URI.create(server.host); - } - - public List>> security() - { - return server.security; - } - - public String scheme() - { - return url().getScheme(); - } - - public String authority() - { - return String.format("%s:%d", url().getHost(), url().getPort()); - } - - public static ServerView of( - Server server) - { - return new ServerView(server); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/OpenApiConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/OpenApiConfigGenerator.java deleted file mode 100644 index 25befc3f50..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/OpenApiConfigGenerator.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi; - -import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.MINIMIZE_QUOTES; -import static com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature.WRITE_DOC_START_MARKER; -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.util.Map; - -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; - -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; - -import io.aklivity.zilla.runtime.catalog.inline.config.InlineOptionsConfig; -import io.aklivity.zilla.runtime.catalog.inline.config.InlineSchemaConfigBuilder; -import io.aklivity.zilla.runtime.command.generate.internal.airline.ConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.MediaType; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.OpenApi; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Schema; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.SchemaView; -import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; - -public abstract class OpenApiConfigGenerator extends ConfigGenerator -{ - protected OpenApi openApi; - - protected SchemaView resolveSchemaForJsonContentType( - Map content) - { - MediaType mediaType = null; - if (content != null) - { - for (String contentType : content.keySet()) - { - if (jsonContentType.reset(contentType).matches()) - { - mediaType = content.get(contentType); - break; - } - } - } - return mediaType == null ? null : SchemaView.of(openApi.components.schemas, mediaType.schema); - } - - protected NamespaceConfigBuilder injectCatalog( - NamespaceConfigBuilder namespace) - { - if (openApi.components != null && openApi.components.schemas != null && !openApi.components.schemas.isEmpty()) - { - namespace - .catalog() - .name(INLINE_CATALOG_NAME) - .type(INLINE_CATALOG_TYPE) - .options(InlineOptionsConfig::builder) - .subjects() - .inject(this::injectSubjects) - .build() - .build() - .build(); - } - return namespace; - } - - protected InlineSchemaConfigBuilder injectSubjects( - InlineSchemaConfigBuilder subjects) - { - try (Jsonb jsonb = JsonbBuilder.create()) - { - YAMLMapper yaml = YAMLMapper.builder() - .disable(WRITE_DOC_START_MARKER) - .enable(MINIMIZE_QUOTES) - .build(); - for (Map.Entry entry : openApi.components.schemas.entrySet()) - { - SchemaView schema = SchemaView.of(openApi.components.schemas, entry.getValue()); - subjects - .subject(entry.getKey()) - .version(VERSION_LATEST) - .schema(writeSchemaYaml(jsonb, yaml, schema)) - .build(); - } - } - catch (Exception ex) - { - rethrowUnchecked(ex); - } - return subjects; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java deleted file mode 100644 index 50b86387a9..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGenerator.java +++ /dev/null @@ -1,677 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.http.proxy; - -import static io.aklivity.zilla.runtime.binding.http.config.HttpPolicyConfig.CROSS_ORIGIN; -import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT; -import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER; -import static java.util.Objects.requireNonNull; -import static org.agrona.LangUtil.rethrowUnchecked; - -import java.io.InputStream; -import java.net.URI; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import jakarta.json.Json; -import jakarta.json.JsonPatch; -import jakarta.json.JsonPatchBuilder; -import jakarta.json.bind.Jsonb; -import jakarta.json.bind.JsonbBuilder; - -import io.aklivity.zilla.runtime.binding.http.config.HttpConditionConfig; -import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig; -import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfigBuilder; -import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfig; -import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfigBuilder; -import io.aklivity.zilla.runtime.binding.http.config.HttpResponseConfigBuilder; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpConditionConfig; -import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig; -import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.OpenApiConfigGenerator; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Header; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.OpenApi; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Operation; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Parameter; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Response; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.ResponseByContentType; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Server; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.OperationView; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.OperationsView; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.PathView; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.SchemaView; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.view.ServerView; -import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.EngineConfig; -import io.aklivity.zilla.runtime.engine.config.EngineConfigWriter; -import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.ModelConfig; -import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder; -import io.aklivity.zilla.runtime.guard.jwt.config.JwtOptionsConfig; -import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; -import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig; - -public class OpenApiHttpProxyConfigGenerator extends OpenApiConfigGenerator -{ - private final InputStream inputStream; - - private int[] allPorts; - private int[] httpPorts; - private int[] httpsPorts; - private boolean isPlainEnabled; - private boolean isTlsEnabled; - private Map securitySchemes; - private boolean isJwtEnabled; - - public OpenApiHttpProxyConfigGenerator( - InputStream inputStream) - { - this.inputStream = inputStream; - } - - @Override - public String generate() - { - this.openApi = parseOpenApi(inputStream); - this.allPorts = resolveAllPorts(); - this.httpPorts = resolvePortsForScheme("http"); - this.httpsPorts = resolvePortsForScheme("https"); - this.isPlainEnabled = httpPorts != null; - this.isTlsEnabled = httpsPorts != null; - this.securitySchemes = resolveSecuritySchemes(); - this.isJwtEnabled = !securitySchemes.isEmpty(); - EngineConfigWriter configWriter = new EngineConfigWriter(null); - String yaml = configWriter.write(createConfig(), createEnvVarsPatch()); - return unquoteEnvVars(yaml, unquotedEnvVars()); - } - - private OpenApi parseOpenApi( - InputStream inputStream) - { - OpenApi openApi = null; - try (Jsonb jsonb = JsonbBuilder.create()) - { - openApi = jsonb.fromJson(inputStream, OpenApi.class); - } - catch (Exception ex) - { - rethrowUnchecked(ex); - } - return openApi; - } - - private int[] resolveAllPorts() - { - int[] ports = new int[openApi.servers.size()]; - for (int i = 0; i < openApi.servers.size(); i++) - { - ServerView server = ServerView.of(openApi.servers.get(i)); - URI url = server.url(); - ports[i] = url.getPort(); - } - return ports; - } - - private int[] resolvePortsForScheme( - String scheme) - { - requireNonNull(scheme); - int[] ports = null; - URI url = findFirstServerUrlWithScheme(scheme); - if (url != null) - { - ports = new int[] {url.getPort()}; - } - return ports; - } - - private URI findFirstServerUrlWithScheme( - String scheme) - { - requireNonNull(scheme); - URI result = null; - for (Server item : openApi.servers) - { - ServerView server = ServerView.of(item); - if (scheme.equals(server.url().getScheme())) - { - result = server.url(); - break; - } - } - return result; - } - - private Map resolveSecuritySchemes() - { - requireNonNull(openApi); - Map result = new HashMap<>(); - if (openApi.components != null && openApi.components.securitySchemes != null) - { - for (String securitySchemeName : openApi.components.securitySchemes.keySet()) - { - String guardType = openApi.components.securitySchemes.get(securitySchemeName).bearerFormat; - if ("jwt".equals(guardType)) - { - result.put(securitySchemeName, guardType); - } - } - } - return result; - } - - private EngineConfig createConfig() - { - return EngineConfig.builder() - .namespace() - .name("example") - .binding() - .name("tcp_server0") - .type("tcp") - .kind(SERVER) - .options(TcpOptionsConfig::builder) - .host("0.0.0.0") - .ports(allPorts) - .build() - .inject(this::injectPlainTcpRoute) - .inject(this::injectTlsTcpRoute) - .build() - .inject(this::injectTlsServer) - .binding() - .name("http_server0") - .type("http") - .kind(SERVER) - .options(HttpOptionsConfig::builder) - .access() - .policy(CROSS_ORIGIN) - .build() - .inject(this::injectHttpServerOptions) - .inject(this::injectHttpServerRequests) - .build() - .inject(this::injectHttpServerRoutes) - .build() - .binding() - .name("http_client0") - .type("http") - .kind(CLIENT) - .inject(this::injectHttpClientOptions) - .exit(isTlsEnabled ? "tls_client0" : "tcp_client0") - .build() - .inject(this::injectTlsClient) - .binding() - .name("tcp_client0") - .type("tcp") - .kind(CLIENT) - .options(TcpOptionsConfig::builder) - .host("") // env - .ports(new int[]{0}) // env - .build() - .build() - .inject(this::injectGuard) - .inject(this::injectVaults) - .inject(this::injectCatalog) - .build() - .build(); - } - - private BindingConfigBuilder injectPlainTcpRoute( - BindingConfigBuilder binding) - { - if (isPlainEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(httpPorts) - .build() - .exit("http_server0") - .build(); - } - return binding; - } - - private BindingConfigBuilder injectTlsTcpRoute( - BindingConfigBuilder binding) - { - if (isTlsEnabled) - { - binding - .route() - .when(TcpConditionConfig::builder) - .ports(httpsPorts) - .build() - .exit("tls_server0") - .build(); - } - return binding; - } - - private NamespaceConfigBuilder injectTlsServer( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_server0") - .type("tls") - .kind(SERVER) - .options(TlsOptionsConfig::builder) - .keys(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .build() - .vault("server") - .exit("http_server0") - .build(); - } - return namespace; - } - - private HttpOptionsConfigBuilder injectHttpServerOptions( - HttpOptionsConfigBuilder options) - { - if (isJwtEnabled) - { - options - .authorization() - .name("jwt0") - .credentials() - .header() - .name("authorization") - .pattern("Bearer {credentials}") - .build() - .build() - .build(); - } - return options; - } - - private HttpOptionsConfigBuilder injectHttpServerRequests( - HttpOptionsConfigBuilder options) - { - for (String pathName : openApi.paths.keySet()) - { - PathView path = PathView.of(openApi.paths.get(pathName)); - for (String methodName : path.methods().keySet()) - { - Operation operation = path.methods().get(methodName); - if (operation.requestBody != null || operation.parameters != null && !operation.parameters.isEmpty()) - { - options - .request() - .path(pathName) - .method(HttpRequestConfig.Method.valueOf(methodName)) - .inject(request -> injectContent(request, operation)) - .inject(request -> injectParams(request, operation)) - .build(); - } - } - } - return options; - } - - private HttpRequestConfigBuilder injectContent( - HttpRequestConfigBuilder request, - Operation operation) - { - if (operation.requestBody != null && operation.requestBody.content != null && !operation.requestBody.content.isEmpty()) - { - SchemaView schema = resolveSchemaForJsonContentType(operation.requestBody.content); - if (schema != null) - { - request. - content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .schema() - .subject(schema.refKey()) - .build() - .build() - .build(); - } - } - return request; - } - - private HttpRequestConfigBuilder injectParams( - HttpRequestConfigBuilder request, - Operation operation) - { - if (operation != null && operation.parameters != null) - { - for (Parameter parameter : operation.parameters) - { - if (parameter.schema != null && parameter.schema.type != null) - { - ModelConfig model = models.get(parameter.schema.type); - if (model != null) - { - switch (parameter.in) - { - case "path": - request. - pathParam() - .name(parameter.name) - .model(model) - .build(); - break; - case "query": - request. - queryParam() - .name(parameter.name) - .model(model) - .build(); - break; - case "header": - request. - header() - .name(parameter.name) - .model(model) - .build(); - break; - } - } - } - } - } - return request; - } - - private BindingConfigBuilder injectHttpClientOptions( - BindingConfigBuilder binding) - { - OperationsView operations = OperationsView.of(openApi.paths); - if (operations.hasResponses()) - { - binding. - options(HttpOptionsConfig::builder) - .inject(options -> injectHttpClientRequests(operations, options)) - .build(); - } - return binding; - } - - private HttpOptionsConfigBuilder injectHttpClientRequests( - OperationsView operations, - HttpOptionsConfigBuilder options) - { - for (String pathName : openApi.paths.keySet()) - { - PathView path = PathView.of(openApi.paths.get(pathName)); - for (String methodName : path.methods().keySet()) - { - OperationView operation = operations.operation(pathName, methodName); - if (operation.hasResponses()) - { - options - .request() - .path(pathName) - .method(HttpRequestConfig.Method.valueOf(methodName)) - .inject(request -> injectResponses(request, operation)) - .build() - .build(); - } - } - } - return options; - } - - private HttpRequestConfigBuilder injectResponses( - HttpRequestConfigBuilder request, - OperationView operation) - { - if (operation != null && operation.responsesByStatus() != null) - { - for (Map.Entry responses0 : operation.responsesByStatus().entrySet()) - { - String status = responses0.getKey(); - ResponseByContentType responses1 = responses0.getValue(); - if (!(OperationView.DEFAULT.equals(status)) && responses1.content != null) - { - for (Map.Entry response2 : responses1.content.entrySet()) - { - SchemaView schema = SchemaView.of(openApi.components.schemas, response2.getValue().schema); - request - .response() - .status(Integer.parseInt(status)) - .contentType(response2.getKey()) - .inject(response -> injectResponseHeaders(responses1, response)) - .content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .schema() - .subject(schema.refKey()) - .build() - .build() - .build() - .build(); - } - } - } - } - return request; - } - - private HttpResponseConfigBuilder injectResponseHeaders( - ResponseByContentType responses, - HttpResponseConfigBuilder response) - { - if (responses.headers != null && !responses.headers.isEmpty()) - { - for (Map.Entry header : responses.headers.entrySet()) - { - String name = header.getKey(); - ModelConfig model = models.get(header.getValue().schema.type); - if (model != null) - { - response - .header() - .name(name) - .model(model) - .build(); - } - } - } - return response; - } - - private BindingConfigBuilder injectHttpServerRoutes( - BindingConfigBuilder binding) - { - for (String item : openApi.paths.keySet()) - { - PathView path = PathView.of(openApi.paths.get(item)); - for (String method : path.methods().keySet()) - { - binding - .route() - .exit("http_client0") - .when(HttpConditionConfig::builder) - .header(":path", item.replaceAll("\\{[^}]+\\}", "*")) - .header(":method", method) - .build() - .inject(route -> injectHttpServerRouteGuarded(route, path, method)) - .build(); - } - } - return binding; - } - - private RouteConfigBuilder injectHttpServerRouteGuarded( - RouteConfigBuilder route, - PathView path, - String method) - { - List>> security = path.methods().get(method).security; - if (security != null) - { - for (Map> securityItem : security) - { - for (String securityItemLabel : securityItem.keySet()) - { - if (isJwtEnabled && "jwt".equals(securitySchemes.get(securityItemLabel))) - { - route - .guarded() - .name("jwt0") - .inject(guarded -> injectGuardedRoles(guarded, securityItem.get(securityItemLabel))) - .build(); - } - } - } - } - return route; - } - - private GuardedConfigBuilder injectGuardedRoles( - GuardedConfigBuilder guarded, - List roles) - { - for (String role : roles) - { - guarded.role(role); - } - return guarded; - } - - private NamespaceConfigBuilder injectTlsClient( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .binding() - .name("tls_client0") - .type("tls") - .kind(CLIENT) - .options(TlsOptionsConfig::builder) - .trust(List.of("")) // env - .sni(List.of("")) // env - .alpn(List.of("")) // env - .trustcacerts(true) - .build() - .vault("client") - .exit("tcp_client0") - .build(); - } - return namespace; - } - - private NamespaceConfigBuilder injectGuard( - NamespaceConfigBuilder namespace) - { - if (isJwtEnabled) - { - namespace - .guard() - .name("jwt0") - .type("jwt") - .options(JwtOptionsConfig::builder) - .issuer("") // env - .audience("") // env - .key() - .alg("").kty("").kid("").use("").n("").e("").crv("").x("").y("") // env - .build() - .build() - .build(); - } - return namespace; - } - - private NamespaceConfigBuilder injectVaults( - NamespaceConfigBuilder namespace) - { - if (isTlsEnabled) - { - namespace - .vault() - .name("client") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .trust() - .store("") // env - .type("") // env - .password("") // env - .build() - .build() - .build() - .vault() - .name("server") - .type("filesystem") - .options(FileSystemOptionsConfig::builder) - .keys() - .store("") // env - .type("") // env - .password("") //env - .build() - .build() - .build(); - } - return namespace; - } - - private JsonPatch createEnvVarsPatch() - { - JsonPatchBuilder patch = Json.createPatchBuilder(); - patch.replace("/bindings/tcp_client0/options/host", "${{env.TCP_CLIENT_HOST}}"); - patch.replace("/bindings/tcp_client0/options/port", "${{env.TCP_CLIENT_PORT}}"); - - if (isJwtEnabled) - { - // jwt0 guard - patch.replace("/guards/jwt0/options/issuer", "${{env.JWT_ISSUER}}"); - patch.replace("/guards/jwt0/options/audience", "${{env.JWT_AUDIENCE}}"); - patch.replace("/guards/jwt0/options/keys/0/alg", "${{env.JWT_ALG}}"); - patch.replace("/guards/jwt0/options/keys/0/kty", "${{env.JWT_KTY}}"); - patch.replace("/guards/jwt0/options/keys/0/kid", "${{env.JWT_KID}}"); - patch.replace("/guards/jwt0/options/keys/0/use", "${{env.JWT_USE}}"); - patch.replace("/guards/jwt0/options/keys/0/n", "${{env.JWT_N}}"); - patch.replace("/guards/jwt0/options/keys/0/e", "${{env.JWT_E}}"); - patch.replace("/guards/jwt0/options/keys/0/crv", "${{env.JWT_CRV}}"); - patch.replace("/guards/jwt0/options/keys/0/x", "${{env.JWT_X}}"); - patch.replace("/guards/jwt0/options/keys/0/y", "${{env.JWT_Y}}"); - } - - if (isTlsEnabled) - { - // tls_server0 binding - patch.replace("/bindings/tls_server0/options/keys/0", "${{env.TLS_SERVER_KEY}}"); - patch.replace("/bindings/tls_server0/options/sni/0", "${{env.TLS_SERVER_SNI}}"); - patch.replace("/bindings/tls_server0/options/alpn/0", "${{env.TLS_SERVER_ALPN}}"); - // tls_client0 binding - patch.replace("/bindings/tls_client0/options/trust/0", "${{env.TLS_CLIENT_TRUST}}"); - patch.replace("/bindings/tls_client0/options/sni/0", "${{env.TLS_CLIENT_SNI}}"); - patch.replace("/bindings/tls_client0/options/alpn/0", "${{env.TLS_CLIENT_ALPN}}"); - // client vault - patch.replace("/vaults/client/options/trust/store", "${{env.TRUSTSTORE_PATH}}"); - patch.replace("/vaults/client/options/trust/type", "${{env.TRUSTSTORE_TYPE}}"); - patch.replace("/vaults/client/options/trust/password", "${{env.TRUSTSTORE_PASSWORD}}"); - // server vault - patch.replace("/vaults/server/options/keys/store", "${{env.KEYSTORE_PATH}}"); - patch.replace("/vaults/server/options/keys/type", "${{env.KEYSTORE_TYPE}}"); - patch.replace("/vaults/server/options/keys/password", "${{env.KEYSTORE_PASSWORD}}"); - } - - return patch.build(); - } - - private List unquotedEnvVars() - { - return List.of("TCP_CLIENT_PORT"); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/BearerAuth.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/BearerAuth.java deleted file mode 100644 index eb6cd10616..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/BearerAuth.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class BearerAuth -{ - public String bearerFormat; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Components.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Components.java deleted file mode 100644 index 4860ee6faf..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Components.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.Map; - -public class Components -{ - public Map securitySchemes; - public Map schemas; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Header.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Header.java deleted file mode 100644 index fba798dbb3..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Header.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class Header -{ - public Schema schema; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Item.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Item.java deleted file mode 100644 index 37fffd07ed..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Item.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class Item -{ - public String type; - public String description; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/MediaType.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/MediaType.java deleted file mode 100644 index aa0638a493..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/MediaType.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class MediaType -{ - public Schema schema; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/OpenApi.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/OpenApi.java deleted file mode 100644 index e9c7bb614c..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/OpenApi.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.LinkedHashMap; -import java.util.List; - -public class OpenApi -{ - public String openapi; - public List servers; - public LinkedHashMap paths; - public Components components; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Operation.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Operation.java deleted file mode 100644 index f1ae876364..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Operation.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.List; -import java.util.Map; - -public class Operation -{ - public List>> security; - public RequestBody requestBody; - public List parameters; - public Map responses; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Parameter.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Parameter.java deleted file mode 100644 index 45cb554380..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Parameter.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class Parameter -{ - public String name; - public String in; - public boolean required; - public Schema schema; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/PathItem.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/PathItem.java deleted file mode 100644 index 1f881ebe68..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/PathItem.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class PathItem -{ - public Operation get; - public Operation put; - public Operation post; - public Operation delete; - public Operation options; - public Operation head; - public Operation patch; - public Operation trace; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/RequestBody.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/RequestBody.java deleted file mode 100644 index 3a1122d4bc..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/RequestBody.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.LinkedHashMap; - -public class RequestBody -{ - public LinkedHashMap content; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Response.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Response.java deleted file mode 100644 index 07550f035d..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Response.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class Response -{ - public Schema schema; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/ResponseByContentType.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/ResponseByContentType.java deleted file mode 100644 index b71c02d401..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/ResponseByContentType.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.LinkedHashMap; - -public class ResponseByContentType -{ - public LinkedHashMap headers; - public LinkedHashMap content; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Schema.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Schema.java deleted file mode 100644 index d1e652312b..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Schema.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -import java.util.List; -import java.util.Map; - -import jakarta.json.bind.annotation.JsonbProperty; - -public class Schema -{ - public String type; - public Schema items; - public Map properties; - public List required; - - @JsonbProperty("$ref") - public String ref; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/SecurityScheme.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/SecurityScheme.java deleted file mode 100644 index a411b5a6b2..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/SecurityScheme.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class SecurityScheme -{ - public String bearerFormat; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Server.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Server.java deleted file mode 100644 index 5c4faf4b4a..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/model/Server.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - -public class Server -{ - public String url; -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationView.java deleted file mode 100644 index 5c5fa2015d..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationView.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Operation; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.ResponseByContentType; - -public class OperationView -{ - public static final String DEFAULT = "default"; - - private final Operation operation; - private final boolean hasResponses; - - public OperationView( - Operation operation) - { - this.operation = operation; - this.hasResponses = initHasResponses(); - } - - public Map responsesByStatus() - { - return operation.responses; - } - - public boolean hasResponses() - { - return hasResponses; - } - - private boolean initHasResponses() - { - boolean result = false; - if (operation != null && operation.responses != null) - { - for (Map.Entry response0 : operation.responses.entrySet()) - { - String status = response0.getKey(); - ResponseByContentType response1 = response0.getValue(); - if (!(DEFAULT.equals(status)) && response1.content != null) - { - result = true; - break; - } - } - } - return result; - } - - public static OperationView of( - Operation operation) - { - return new OperationView(operation); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationsView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationsView.java deleted file mode 100644 index 0dd701b471..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/OperationsView.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - -import java.util.LinkedHashMap; -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.PathItem; - -public final class OperationsView -{ - private final Map> operationsPerPath; - private final boolean hasResponses; - - private OperationsView( - LinkedHashMap paths) - { - this.operationsPerPath = new LinkedHashMap<>(); - boolean hasResponses = false; - for (String pathName : paths.keySet()) - { - PathView path = PathView.of(paths.get(pathName)); - for (String methodName : path.methods().keySet()) - { - OperationView operation = OperationView.of(path.methods().get(methodName)); - hasResponses |= operation.hasResponses(); - if (operationsPerPath.containsKey(pathName)) - { - operationsPerPath.get(pathName).put(methodName, operation); - } - else - { - Map operationsPerMethod = new LinkedHashMap<>(); - operationsPerMethod.put(methodName, operation); - operationsPerPath.put(pathName, operationsPerMethod); - } - } - } - this.hasResponses = hasResponses; - } - - public boolean hasResponses() - { - return this.hasResponses; - } - - public OperationView operation( - String pathName, - String methodName) - { - return operationsPerPath.get(pathName).get(methodName); - } - - public static OperationsView of( - LinkedHashMap paths) - { - return new OperationsView(paths); - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/PathView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/PathView.java deleted file mode 100644 index 50f94d442f..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/PathView.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - -import java.util.LinkedHashMap; -import java.util.Map; - -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Operation; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.PathItem; - -public class PathView -{ - private final LinkedHashMap methods; - - public PathView( - PathItem pathItem) - { - this.methods = new LinkedHashMap<>(); - putIfNotNull(methods, "GET", pathItem.get); - putIfNotNull(methods, "PUT", pathItem.put); - putIfNotNull(methods, "POST", pathItem.post); - putIfNotNull(methods, "DELETE", pathItem.delete); - putIfNotNull(methods, "OPTIONS", pathItem.options); - putIfNotNull(methods, "HEAD", pathItem.head); - putIfNotNull(methods, "PATCH", pathItem.patch); - putIfNotNull(methods, "TRACE", pathItem.trace); - } - - public Map methods() - { - return methods; - } - - public static PathView of( - PathItem pathItem) - { - return new PathView(pathItem); - } - - private static void putIfNotNull( - Map methods, - String method, - Operation operation) - { - if (operation != null) - { - methods.put(method, operation); - } - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/Resolvable.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/Resolvable.java deleted file mode 100644 index 173bfd019c..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/Resolvable.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class Resolvable -{ - private final Map map; - private final Matcher matcher; - - protected String key; - - public Resolvable( - Map map, - String regex) - { - this.map = map; - this.matcher = Pattern.compile(regex).matcher(""); - } - - protected T resolveRef( - String ref) - { - T result = null; - if (matcher.reset(ref).matches()) - { - key = matcher.group(1); - result = map.get(key); - } - return result; - } -} diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/SchemaView.java b/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/SchemaView.java deleted file mode 100644 index d823fb76a6..0000000000 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/SchemaView.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - -import java.util.List; -import java.util.Map; - -import jakarta.json.bind.annotation.JsonbPropertyOrder; - -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Item; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Schema; - -@JsonbPropertyOrder({ - "type", - "items", - "properties", - "required" -}) -public final class SchemaView extends Resolvable -{ - private static final String ARRAY_TYPE = "array"; - - private final Schema schema; - private final Map schemas; - - private SchemaView( - Map schemas, - Schema schema) - { - super(schemas, "#/components/schemas/(\\w+)"); - if (schema.ref != null) - { - schema = resolveRef(schema.ref); - } - else if (ARRAY_TYPE.equals(schema.type) && schema.items != null && schema.items.ref != null) - { - schema.items = resolveRef(schema.items.ref); - } - this.schemas = schemas; - this.schema = schema; - } - - public String refKey() - { - return key; - } - - public String getType() - { - return schema.type; - } - - public SchemaView getItems() - { - return schema.items == null ? null : SchemaView.of(schemas, schema.items); - } - - public Map getProperties() - { - return schema.properties; - } - - public List getRequired() - { - return schema.required; - } - - public static SchemaView of( - Map schemas, - Schema schema) - { - return new SchemaView(schemas, schema); - } -} diff --git a/incubator/command-generate/src/main/moditect/module-info.java b/incubator/command-generate/src/main/moditect/module-info.java deleted file mode 100644 index 0c03ce63de..0000000000 --- a/incubator/command-generate/src/main/moditect/module-info.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -module io.aklivity.zilla.runtime.command.generate -{ - requires io.aklivity.zilla.runtime.command; - requires io.aklivity.zilla.runtime.engine; - requires io.aklivity.zilla.runtime.binding.http; - requires io.aklivity.zilla.runtime.binding.mqtt; - requires io.aklivity.zilla.runtime.binding.tcp; - requires io.aklivity.zilla.runtime.binding.tls; - requires io.aklivity.zilla.runtime.catalog.inline; - requires io.aklivity.zilla.runtime.guard.jwt; - requires io.aklivity.zilla.runtime.vault.filesystem; - requires io.aklivity.zilla.runtime.model.avro; - requires io.aklivity.zilla.runtime.model.core; - requires io.aklivity.zilla.runtime.model.json; - requires io.aklivity.zilla.runtime.model.protobuf; - - requires com.fasterxml.jackson.dataformat.yaml; - requires com.fasterxml.jackson.databind; - - opens io.aklivity.zilla.runtime.command.generate.internal.airline - to com.github.rvesse.airline; - - opens io.aklivity.zilla.runtime.command.generate.internal.openapi.model; - opens io.aklivity.zilla.runtime.command.generate.internal.openapi.view; - opens io.aklivity.zilla.runtime.command.generate.internal.asyncapi.model; - opens io.aklivity.zilla.runtime.command.generate.internal.asyncapi.view; - - provides io.aklivity.zilla.runtime.command.ZillaCommandSpi - with io.aklivity.zilla.runtime.command.generate.internal.ZillaConfigCommandSpi; -} diff --git a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGeneratorTest.java b/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGeneratorTest.java deleted file mode 100644 index f0003b4340..0000000000 --- a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/AsyncApiHttpProxyConfigGeneratorTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.http.proxy; - -import static org.junit.Assert.assertEquals; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.junit.jupiter.api.Test; - -import io.aklivity.zilla.runtime.command.generate.internal.airline.ConfigGenerator; - -public class AsyncApiHttpProxyConfigGeneratorTest -{ - @Test - public void shouldGeneratePlainConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("plain/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("plain/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateValidatorConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("validator/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("validator/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateJwtConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("jwt/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("jwt/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateTlsConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("tls/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("tls/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateCompleteConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("complete/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("complete/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } -} diff --git a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGeneratorTest.java b/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGeneratorTest.java deleted file mode 100644 index ebbbba9fbb..0000000000 --- a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/AsyncApiMqttProxyConfigGeneratorTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.asyncapi.mqtt.proxy; - -import static org.junit.Assert.assertEquals; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.junit.jupiter.api.Test; - -import io.aklivity.zilla.runtime.command.generate.internal.airline.ConfigGenerator; - -public class AsyncApiMqttProxyConfigGeneratorTest -{ - @Test - public void shouldGeneratePlainConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("plain/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("plain/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiMqttProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateValidatorConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("validator/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("validator/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiMqttProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateTlsConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("tls/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("tls/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiMqttProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateCompleteConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("complete/asyncapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("complete/zilla.yaml").getFile())); - ConfigGenerator generator = new AsyncApiMqttProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } -} diff --git a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGeneratorTest.java b/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGeneratorTest.java deleted file mode 100644 index 04c3aa44c5..0000000000 --- a/incubator/command-generate/src/test/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/OpenApiHttpProxyConfigGeneratorTest.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.http.proxy; - -import static org.junit.Assert.assertEquals; - -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; - -import org.junit.jupiter.api.Test; - -import io.aklivity.zilla.runtime.command.generate.internal.airline.ConfigGenerator; - -public class OpenApiHttpProxyConfigGeneratorTest -{ - @Test - public void shouldGeneratePlainConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("plain/openapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("plain/zilla.yaml").getFile())); - ConfigGenerator generator = new OpenApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateValidateConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("validator/openapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("validator/zilla.yaml").getFile())); - ConfigGenerator generator = new OpenApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateJwtConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("jwt/openapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("jwt/zilla.yaml").getFile())); - ConfigGenerator generator = new OpenApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateTlsConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("tls/openapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("tls/zilla.yaml").getFile())); - ConfigGenerator generator = new OpenApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } - - @Test - public void shouldGenerateCompleteConfig() throws Exception - { - try (InputStream input = getClass().getResourceAsStream("complete/openapi.yaml")) - { - // GIVEN - String expected = Files.readString(Path.of(getClass().getResource("complete/zilla.yaml").getFile())); - ConfigGenerator generator = new OpenApiHttpProxyConfigGenerator(input); - - // WHEN - String actual = generator.generate(); - - // THEN - assertEquals(expected, actual); - } - } -} diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/asyncapi.yaml deleted file mode 100644 index d2e61e7de5..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/asyncapi.yaml +++ /dev/null @@ -1,98 +0,0 @@ -asyncapi: 3.0.0 -info: - title: HTTP Zilla Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - secure: - host: https://localhost:9090 - protocol: http - protocolVersion: '1.1' - security: - - httpBearerToken: - - public - plain: - host: http://localhost:8080 - protocol: http - protocolVersion: '1.1' -defaultContentType: application/json - -channels: - items: - address: /items - messages: - items: - $ref: '#/components/messages/item' - itemsbyid: - address: /items/{id} - parameters: - id: - description: Event ID. - schema: - type: string - messages: - items: - $ref: '#/components/messages/item' - -operations: - postEvents: - action: send - bindings: - http: - type: request - method: POST - channel: - $ref: '#/channels/items' - getEvents: - action: receive - bindings: - http: - type: request - method: GET - query: - type: object - properties: - limit: - type: number - channel: - $ref: '#/channels/itemsbyid' - -components: - correlationIds: - itemsCorrelationId: - location: '$message.header#/idempotency-key' - messages: - item: - name: event - title: An event - correlationId: - $ref: "#/components/correlationIds/itemsCorrelationId" - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - authorization: - description: Bearer {credentials} - type: string - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/item" - schemas: - item: - type: object - properties: - greeting: - type: string - required: - - greeting - securitySchemes: - httpBearerToken: - type: http - scheme: bearer - bearerFormat: jwt diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml deleted file mode 100644 index 14c6d158ef..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/complete/zilla.yaml +++ /dev/null @@ -1,161 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: - - 8080 - - 9090 - routes: - - exit: http_server0 - when: - - port: 8080 - - exit: tls_server0 - when: - - port: 9090 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: http_server0 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - authorization: - jwt0: - credentials: - headers: - authorization: "Bearer {credentials}" - requests: - - path: "/items/{id}" - method: GET - params: - path: - id: string - content: - model: json - catalog: - catalog0: - - subject: item - - path: /items - method: POST - content: - model: json - catalog: - catalog0: - - subject: item - routes: - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items - :method: POST - - exit: http_client0 - when: - - headers: - :scheme: https - :authority: localhost:9090 - :path: /items/* - :method: GET - guarded: - jwt0: - - public - - exit: http_client0 - when: - - headers: - :scheme: https - :authority: localhost:9090 - :path: /items - :method: POST - guarded: - jwt0: - - public - http_client0: - type: http - kind: client - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -guards: - jwt0: - type: jwt - options: - issuer: "${{env.JWT_ISSUER}}" - audience: "${{env.JWT_AUDIENCE}}" - keys: - - kty: "${{env.JWT_KTY}}" - "n": "${{env.JWT_N}}" - e: "${{env.JWT_E}}" - alg: "${{env.JWT_ALG}}" - crv: "${{env.JWT_CRV}}" - x: "${{env.JWT_X}}" - "y": "${{env.JWT_Y}}" - use: "${{env.JWT_USE}}" - kid: "${{env.JWT_KID}}" -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" -catalogs: - catalog0: - type: inline - options: - subjects: - item: - schema: | - type: object - properties: - greeting: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/asyncapi.yaml deleted file mode 100644 index 8984af8dfd..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/asyncapi.yaml +++ /dev/null @@ -1,72 +0,0 @@ -asyncapi: 3.0.0 -info: - title: HTTP Zilla Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - plain: - host: http://localhost:8080 - protocol: http - protocolVersion: '1.1' - security: - - httpBearerToken: - - public -defaultContentType: application/json - -channels: - items: - address: /items - itemsbyid: - address: /items/{id} - -operations: - postEvents: - action: send - bindings: - http: - type: request - method: POST - channel: - $ref: '#/channels/items' - getEvents: - action: receive - bindings: - http: - type: request - method: GET - query: - type: object - properties: - limit: - type: number - channel: - $ref: '#/channels/itemsbyid' - -components: - correlationIds: - itemsCorrelationId: - location: '$message.header#/idempotency-key' - messages: - item: - name: event - title: An event - correlationId: - $ref: "#/components/correlationIds/itemsCorrelationId" - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - authorization: - description: Bearer {credentials} - type: string - contentType: application/json - payload: - type: object - securitySchemes: - httpBearerToken: - type: http - scheme: bearer - bearerFormat: jwt diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/zilla.yaml deleted file mode 100644 index 880a24f184..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/jwt/zilla.yaml +++ /dev/null @@ -1,70 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - authorization: - jwt0: - credentials: - headers: - authorization: "Bearer {credentials}" - routes: - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items/* - :method: GET - guarded: - jwt0: - - public - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items - :method: POST - guarded: - jwt0: - - public - http_client0: - type: http - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -guards: - jwt0: - type: jwt - options: - issuer: "${{env.JWT_ISSUER}}" - audience: "${{env.JWT_AUDIENCE}}" - keys: - - kty: "${{env.JWT_KTY}}" - "n": "${{env.JWT_N}}" - e: "${{env.JWT_E}}" - alg: "${{env.JWT_ALG}}" - crv: "${{env.JWT_CRV}}" - x: "${{env.JWT_X}}" - "y": "${{env.JWT_Y}}" - use: "${{env.JWT_USE}}" - kid: "${{env.JWT_KID}}" diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/asyncapi.yaml deleted file mode 100644 index 92696f10b9..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/asyncapi.yaml +++ /dev/null @@ -1,46 +0,0 @@ -asyncapi: 3.0.0 -info: - title: HTTP Zilla Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - plain: - host: http://localhost:8080 - protocol: http - protocolVersion: '1.1' -defaultContentType: application/json - -channels: - items: - address: /items - itemsbyid: - address: /items/{id} - -operations: - postEvents: - action: send - bindings: - http: - type: request - method: POST - channel: - $ref: '#/channels/items' - getEvents: - action: receive - bindings: - http: - type: request - method: GET - query: - type: object - properties: - limit: - type: number - channel: - $ref: '#/channels/itemsbyid' - -components: - correlationIds: - itemsCorrelationId: - location: '$message.header#/idempotency-key' diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/zilla.yaml deleted file mode 100644 index d1ff8a09cd..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/plain/zilla.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - routes: - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items - :method: POST - http_client0: - type: http - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/asyncapi.yaml deleted file mode 100644 index ed3fdcca47..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/asyncapi.yaml +++ /dev/null @@ -1,59 +0,0 @@ -asyncapi: 3.0.0 -info: - title: HTTP Zilla Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - secure: - host: https://localhost:9090 - protocol: http - protocolVersion: '1.1' -defaultContentType: application/json - -channels: - items: - address: /items - itemsbyid: - address: /items/{id} - -operations: - postEvents: - action: send - bindings: - http: - type: request - method: POST - channel: - $ref: '#/channels/items' - getEvents: - action: receive - bindings: - http: - type: request - method: GET - query: - type: object - properties: - limit: - type: number - channel: - $ref: '#/channels/itemsbyid' - -components: - correlationIds: - itemsCorrelationId: - location: '$message.header#/idempotency-key' - messages: - item: - name: event - title: An event - correlationId: - $ref: "#/components/correlationIds/itemsCorrelationId" - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - contentType: application/json diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/zilla.yaml deleted file mode 100644 index d1a5f47409..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/tls/zilla.yaml +++ /dev/null @@ -1,83 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 9090 - routes: - - exit: tls_server0 - when: - - port: 9090 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: http_server0 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - routes: - - exit: http_client0 - when: - - headers: - :scheme: https - :authority: localhost:9090 - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :scheme: https - :authority: localhost:9090 - :path: /items - :method: POST - http_client0: - type: http - kind: client - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/asyncapi.yaml deleted file mode 100644 index e5b6e54ced..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/asyncapi.yaml +++ /dev/null @@ -1,83 +0,0 @@ -asyncapi: 3.0.0 -info: - title: HTTP Zilla Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - plain: - host: http://localhost:8080 - protocol: http - protocolVersion: '1.1' -defaultContentType: application/json - -channels: - items: - address: /items - messages: - items: - $ref: '#/components/messages/item' - itemsbyid: - address: /items/{id} - parameters: - id: - description: Event ID. - schema: - type: string - messages: - items: - $ref: '#/components/messages/item' - -operations: - postEvents: - action: send - bindings: - http: - type: request - method: POST - channel: - $ref: '#/channels/items' - getEvents: - action: receive - bindings: - http: - type: request - method: GET - query: - type: object - properties: - limit: - type: number - channel: - $ref: '#/channels/itemsbyid' - -components: - correlationIds: - itemsCorrelationId: - location: '$message.header#/idempotency-key' - messages: - item: - name: event - title: An event - correlationId: - $ref: "#/components/correlationIds/itemsCorrelationId" - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/item" - schemas: - item: - type: object - properties: - greeting: - type: string - required: - - greeting diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml deleted file mode 100644 index d97ca1fed1..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/http/proxy/validator/zilla.yaml +++ /dev/null @@ -1,75 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - requests: - - path: "/items/{id}" - method: GET - params: - path: - id: string - content: - model: json - catalog: - catalog0: - - subject: item - - path: /items - method: POST - content: - model: json - catalog: - catalog0: - - subject: item - routes: - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :scheme: http - :authority: localhost:8080 - :path: /items - :method: POST - http_client0: - type: http - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -catalogs: - catalog0: - type: inline - options: - subjects: - item: - schema: | - type: object - properties: - greeting: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/asyncapi.yaml deleted file mode 100644 index 33e3411f30..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/asyncapi.yaml +++ /dev/null @@ -1,86 +0,0 @@ -asyncapi: 3.0.0 -info: - title: Zilla MQTT Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - secure: - host: mqtts://localhost:8883 - protocol: secure-mqtt - plain: - host: mqtt://localhost:1883 - protocol: mqtt -defaultContentType: application/json - -channels: - smartylighting: - address: "smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured" - title: MQTT Topic to produce & consume topic. - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - messages: - items: - $ref: '#/components/messages/item' - -operations: - sendEvents: - action: send - channel: - $ref: '#/channels/smartylighting' - - receiveEvents: - action: receive - channel: - $ref: '#/channels/smartylighting' - -components: - parameters: - streetlightId: - description: Street Light ID - location: $message.header#/id - messages: - item: - name: event - title: An event - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - id: - description: Street Light ID - type: string - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/item" - thing: - name: thing - title: A thing - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/thing" - schemas: - item: - type: object - properties: - id: - type: string - status: - type: string - required: - - id - - status - thing: - type: object - properties: - sunshine: - type: integer diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml deleted file mode 100644 index 630cd6ddf8..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/complete/zilla.yaml +++ /dev/null @@ -1,109 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: - - 1883 - - 8883 - routes: - - exit: mqtt_server0 - when: - - port: 1883 - - exit: tls_server0 - when: - - port: 8883 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: mqtt_server0 - mqtt_server0: - type: mqtt - kind: server - options: - topics: - - name: smartylighting/streetlights/1/0/event/*/lighting/measured - content: - model: json - catalog: - catalog0: - - subject: items - routes: - - exit: mqtt_client0 - when: - - publish: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - - subscribe: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - mqtt_client0: - type: mqtt - kind: client - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" -catalogs: - catalog0: - type: inline - options: - subjects: - item: - schema: | - type: object - properties: - id: - type: string - status: - type: string - required: - - id - - status - version: latest - thing: - schema: | - type: object - properties: - sunshine: - type: integer - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/asyncapi.yaml deleted file mode 100644 index 9135f5aad4..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/asyncapi.yaml +++ /dev/null @@ -1,52 +0,0 @@ -asyncapi: 3.0.0 -info: - title: Zilla MQTT Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - plain: - host: mqtt://localhost:1883 - protocol: mqtt -defaultContentType: application/json - -channels: - smartylighting: - address: "smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured" - title: MQTT Topic to produce & consume topic. - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - messages: - items: - $ref: '#/components/messages/item' - -operations: - sendEvents: - action: send - channel: - $ref: '#/channels/smartylighting' - - receiveEvents: - action: receive - channel: - $ref: '#/channels/smartylighting' - -components: - parameters: - streetlightId: - description: Street Light ID - location: $message.header#/id - messages: - item: - name: event - title: An event - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - id: - description: Street Light ID - type: string diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/zilla.yaml deleted file mode 100644 index 9ed3ffa917..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/plain/zilla.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 1883 - routes: - - exit: mqtt_server0 - when: - - port: 1883 - mqtt_server0: - type: mqtt - kind: server - routes: - - exit: mqtt_client0 - when: - - publish: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - - subscribe: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - mqtt_client0: - type: mqtt - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/asyncapi.yaml deleted file mode 100644 index 7b25e0f46c..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/asyncapi.yaml +++ /dev/null @@ -1,52 +0,0 @@ -asyncapi: 3.0.0 -info: - title: Zilla MQTT Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - secure: - host: mqtts://localhost:8883 - protocol: secure-mqtt -defaultContentType: application/json - -channels: - smartylighting: - address: "smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured" - title: MQTT Topic to produce & consume topic. - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - messages: - items: - $ref: '#/components/messages/item' - -operations: - sendEvents: - action: send - channel: - $ref: '#/channels/smartylighting' - - receiveEvents: - action: receive - channel: - $ref: '#/channels/smartylighting' - -components: - parameters: - streetlightId: - description: Street Light ID - location: $message.header#/id - messages: - item: - name: event - title: An event - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - id: - description: Street Light ID - type: string diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/zilla.yaml deleted file mode 100644 index ea7615f996..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/tls/zilla.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8883 - routes: - - exit: tls_server0 - when: - - port: 8883 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: mqtt_server0 - mqtt_server0: - type: mqtt - kind: server - routes: - - exit: mqtt_client0 - when: - - publish: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - - subscribe: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - mqtt_client0: - type: mqtt - kind: client - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/asyncapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/asyncapi.yaml deleted file mode 100644 index 9684991956..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/asyncapi.yaml +++ /dev/null @@ -1,85 +0,0 @@ -asyncapi: 3.0.0 -info: - title: Zilla MQTT Proxy - version: 1.0.0 - license: - name: Aklivity Community License -servers: - plain: - host: mqtt://localhost:1883 - protocol: mqtt -defaultContentType: application/json - -channels: - smartylighting: - address: "smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured" - title: MQTT Topic to produce & consume topic. - parameters: - streetlightId: - $ref: '#/components/parameters/streetlightId' - messages: - items: - $ref: '#/components/messages/item' - things: - $ref: '#/components/messages/thing' - -operations: - sendEvents: - action: send - channel: - $ref: '#/channels/smartylighting' - - receiveEvents: - action: receive - channel: - $ref: '#/channels/smartylighting' - -components: - parameters: - streetlightId: - description: Street Light ID - location: $message.header#/id - messages: - item: - name: event - title: An event - headers: - type: object - properties: - idempotency-key: - description: Unique identifier for a given event - type: string - id: - description: Street Light ID - type: string - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/item" - thing: - name: thing - title: A thing - contentType: application/json - payload: - type: object - properties: - item: - $ref: "#/components/schemas/thing" - schemas: - item: - type: object - properties: - id: - type: string - status: - type: string - required: - - id - - status - thing: - type: object - properties: - sunshine: - type: integer diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml deleted file mode 100644 index 8f8348a2f0..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/asyncapi/mqtt/proxy/validator/zilla.yaml +++ /dev/null @@ -1,65 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 1883 - routes: - - exit: mqtt_server0 - when: - - port: 1883 - mqtt_server0: - type: mqtt - kind: server - options: - topics: - - name: smartylighting/streetlights/1/0/event/*/lighting/measured - content: - model: json - catalog: - catalog0: - - subject: items - - subject: things - routes: - - exit: mqtt_client0 - when: - - publish: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - - subscribe: - - topic: smartylighting/streetlights/1/0/event/*/lighting/measured - mqtt_client0: - type: mqtt - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -catalogs: - catalog0: - type: inline - options: - subjects: - item: - schema: | - type: object - properties: - id: - type: string - status: - type: string - required: - - id - - status - version: latest - thing: - schema: | - type: object - properties: - sunshine: - type: integer - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/openapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/openapi.yaml deleted file mode 100644 index 13a73200b5..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/openapi.yaml +++ /dev/null @@ -1,173 +0,0 @@ -openapi: 3.1.0 -hello: $.openapi -info: - version: 1.0.0 - title: Zilla CRUD V1 - license: - name: Aklivity Community License -servers: - - url: http://localhost:8080 - - url: https://localhost:9090 -paths: - /items: - post: - summary: Create an item - operationId: createItem - tags: - - items - requestBody: - content: - 'application/json': - schema: - $ref: '#/components/schemas/Item' - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - security: - - bearerAuth: - - create:items - get: - summary: List all items - operationId: listItems - tags: - - items - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - maximum: 100 - format: int32 - responses: - '200': - description: A paged array of items - headers: - x-pages: - description: Total number of pages - schema: - type: integer - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Items" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - security: - - bearerAuth: - - list:items - /items/{id}: - get: - summary: Get an item - operationId: showItemById - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Item" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - put: - summary: Update an item by key - operationId: updateItem - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to update - schema: - type: string - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - delete: - summary: Delete an item by key - operationId: deleteItem - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to delete - schema: - type: string - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Item: - type: object - required: - - greeting - properties: - greeting: - type: string - tag: - type: string - Items: - type: array - maxItems: 100 - items: - $ref: "#/components/schemas/Item" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: jwt diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml deleted file mode 100644 index 887dcbdc11..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/complete/zilla.yaml +++ /dev/null @@ -1,222 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: - - 8080 - - 9090 - routes: - - exit: http_server0 - when: - - port: 8080 - - exit: tls_server0 - when: - - port: 9090 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: http_server0 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - authorization: - jwt0: - credentials: - headers: - authorization: "Bearer {credentials}" - requests: - - path: /items - method: GET - params: - query: - limit: int32 - - path: /items - method: POST - content: - model: json - catalog: - catalog0: - - subject: Item - - path: "/items/{id}" - method: GET - params: - path: - id: string - - path: "/items/{id}" - method: PUT - params: - path: - id: string - - path: "/items/{id}" - method: DELETE - params: - path: - id: string - routes: - - exit: http_client0 - when: - - headers: - :path: /items - :method: GET - guarded: - jwt0: - - list:items - - exit: http_client0 - when: - - headers: - :path: /items - :method: POST - guarded: - jwt0: - - create:items - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: PUT - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: DELETE - http_client0: - type: http - kind: client - options: - requests: - - path: /items - method: GET - responses: - - status: 200 - content-type: - - application/json - headers: - x-pages: int32 - x-next: string - content: - model: json - catalog: - catalog0: - - subject: Items - - path: "/items/{id}" - method: GET - responses: - - status: 200 - content-type: - - application/json - content: - model: json - catalog: - catalog0: - - subject: Item - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -guards: - jwt0: - type: jwt - options: - issuer: "${{env.JWT_ISSUER}}" - audience: "${{env.JWT_AUDIENCE}}" - keys: - - kty: "${{env.JWT_KTY}}" - "n": "${{env.JWT_N}}" - e: "${{env.JWT_E}}" - alg: "${{env.JWT_ALG}}" - crv: "${{env.JWT_CRV}}" - x: "${{env.JWT_X}}" - "y": "${{env.JWT_Y}}" - use: "${{env.JWT_USE}}" - kid: "${{env.JWT_KID}}" -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" -catalogs: - catalog0: - type: inline - options: - subjects: - Item: - schema: | - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest - Error: - schema: | - type: object - properties: - code: - type: integer - message: - type: string - required: - - code - - message - version: latest - Items: - schema: | - type: array - items: - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/openapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/openapi.yaml deleted file mode 100644 index 16bb52f2c4..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/openapi.yaml +++ /dev/null @@ -1,82 +0,0 @@ -openapi: 3.1.0 -hello: $.openapi -info: - version: 1.0.0 - title: Zilla CRUD V1 - license: - name: Aklivity Community License -servers: - - url: http://localhost:8080 -paths: - /items: - post: - summary: Create an item - operationId: createItem - tags: - - items - requestBody: - content: - 'application/json': - schema: - $ref: '#/components/schemas/Item' - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - security: - - bearerAuth: - - create:items - get: - summary: List all items - operationId: listItems - tags: - - items - responses: - '200': - description: A paged array of items - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - security: - - bearerAuth: - - list:items -components: - schemas: - Item: - type: object - required: - - greeting - properties: - greeting: - type: string - tag: - type: string - Items: - type: array - maxItems: 100 - items: - $ref: "#/components/schemas/Item" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: jwt diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml deleted file mode 100644 index 65dc139e8c..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/jwt/zilla.yaml +++ /dev/null @@ -1,115 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - authorization: - jwt0: - credentials: - headers: - authorization: "Bearer {credentials}" - requests: - - path: /items - method: POST - content: - model: json - catalog: - catalog0: - - subject: Item - routes: - - exit: http_client0 - when: - - headers: - :path: /items - :method: GET - guarded: - jwt0: - - list:items - - exit: http_client0 - when: - - headers: - :path: /items - :method: POST - guarded: - jwt0: - - create:items - http_client0: - type: http - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -guards: - jwt0: - type: jwt - options: - issuer: "${{env.JWT_ISSUER}}" - audience: "${{env.JWT_AUDIENCE}}" - keys: - - kty: "${{env.JWT_KTY}}" - "n": "${{env.JWT_N}}" - e: "${{env.JWT_E}}" - alg: "${{env.JWT_ALG}}" - crv: "${{env.JWT_CRV}}" - x: "${{env.JWT_X}}" - "y": "${{env.JWT_Y}}" - use: "${{env.JWT_USE}}" - kid: "${{env.JWT_KID}}" -catalogs: - catalog0: - type: inline - options: - subjects: - Item: - schema: | - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest - Error: - schema: | - type: object - properties: - code: - type: integer - message: - type: string - required: - - code - - message - version: latest - Items: - schema: | - type: array - items: - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/openapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/openapi.yaml deleted file mode 100644 index dd1e252656..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/openapi.yaml +++ /dev/null @@ -1,52 +0,0 @@ -openapi: 3.1.0 -hello: $.openapi -info: - version: 1.0.0 - title: Zilla CRUD V1 - license: - name: Aklivity Community License -servers: - - url: http://localhost:8080 -paths: - /items: - get: - summary: List all items - operationId: listItems - tags: - - items - responses: - '200': - description: A paged array of items - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Item: - type: object - required: - - greeting - properties: - greeting: - type: string - tag: - type: string - Items: - type: array - maxItems: 100 - items: - $ref: "#/components/schemas/Item" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/zilla.yaml deleted file mode 100644 index 7a2da21a59..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/plain/zilla.yaml +++ /dev/null @@ -1,75 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - routes: - - exit: http_client0 - when: - - headers: - :path: /items - :method: GET - http_client0: - type: http - kind: client - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -catalogs: - catalog0: - type: inline - options: - subjects: - Item: - schema: | - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest - Error: - schema: | - type: object - properties: - code: - type: integer - message: - type: string - required: - - code - - message - version: latest - Items: - schema: | - type: array - items: - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/openapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/openapi.yaml deleted file mode 100644 index 7ff62c148c..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/openapi.yaml +++ /dev/null @@ -1,52 +0,0 @@ -openapi: 3.1.0 -hello: $.openapi -info: - version: 1.0.0 - title: Zilla CRUD V1 - license: - name: Aklivity Community License -servers: - - url: https://localhost:9090 -paths: - /items: - get: - summary: List all items - operationId: listItems - tags: - - items - responses: - '200': - description: A paged array of items - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Item: - type: object - required: - - greeting - properties: - greeting: - type: string - tag: - type: string - Items: - type: array - maxItems: 100 - items: - $ref: "#/components/schemas/Item" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/zilla.yaml deleted file mode 100644 index 5a7a8b176f..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/tls/zilla.yaml +++ /dev/null @@ -1,115 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 9090 - routes: - - exit: tls_server0 - when: - - port: 9090 - tls_server0: - type: tls - kind: server - vault: server - options: - keys: - - "${{env.TLS_SERVER_KEY}}" - sni: - - "${{env.TLS_SERVER_SNI}}" - alpn: - - "${{env.TLS_SERVER_ALPN}}" - exit: http_server0 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - routes: - - exit: http_client0 - when: - - headers: - :path: /items - :method: GET - http_client0: - type: http - kind: client - exit: tls_client0 - tls_client0: - type: tls - kind: client - vault: client - options: - trust: - - "${{env.TLS_CLIENT_TRUST}}" - trustcacerts: true - sni: - - "${{env.TLS_CLIENT_SNI}}" - alpn: - - "${{env.TLS_CLIENT_ALPN}}" - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -vaults: - client: - type: filesystem - options: - trust: - store: "${{env.TRUSTSTORE_PATH}}" - type: "${{env.TRUSTSTORE_TYPE}}" - password: "${{env.TRUSTSTORE_PASSWORD}}" - server: - type: filesystem - options: - keys: - store: "${{env.KEYSTORE_PATH}}" - type: "${{env.KEYSTORE_TYPE}}" - password: "${{env.KEYSTORE_PASSWORD}}" -catalogs: - catalog0: - type: inline - options: - subjects: - Item: - schema: | - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest - Error: - schema: | - type: object - properties: - code: - type: integer - message: - type: string - required: - - code - - message - version: latest - Items: - schema: | - type: array - items: - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/openapi.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/openapi.yaml deleted file mode 100644 index d9d2e52300..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/openapi.yaml +++ /dev/null @@ -1,179 +0,0 @@ -openapi: 3.1.0 -hello: $.openapi -info: - version: 1.0.0 - title: Zilla CRUD V1 - license: - name: Aklivity Community License -servers: - - url: http://localhost:8080 -paths: - /items: - post: - summary: Create an item - operationId: createItem - tags: - - items - requestBody: - content: - 'application/json': - schema: - $ref: '#/components/schemas/Item' - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - get: - summary: List all items - operationId: listItems - tags: - - items - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - maximum: 100 - format: int32 - responses: - '200': - description: A paged array of items - headers: - x-pages: - description: Total number of pages - schema: - type: integer - x-next: - description: A link to the next page of responses - schema: - type: string - content: - application/json: - schema: - $ref: "#/components/schemas/Items" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - /items/{id}: - get: - summary: Get an item - operationId: showItemById - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to retrieve - schema: - type: string - responses: - '200': - description: Expected response to a valid request - content: - application/json: - schema: - $ref: "#/components/schemas/Item" - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - put: - summary: Update an item by key - operationId: updateItem - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to update - schema: - type: string - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: integer - - name: hello - in: header - description: Example header parameter - required: false - schema: - type: integer - - name: ciao - in: query - description: Example query parameter - required: false - schema: - type: string - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - delete: - summary: Delete an item by key - operationId: deleteItem - tags: - - items - parameters: - - name: id - in: path - required: true - description: The id of the item to delete - schema: - type: string - responses: - '204': - description: No Content - default: - description: unexpected error - content: - application/json: - schema: - $ref: "#/components/schemas/Error" -components: - schemas: - Item: - type: object - required: - - greeting - properties: - greeting: - type: string - tag: - type: string - Items: - type: array - maxItems: 100 - items: - $ref: "#/components/schemas/Item" - Error: - type: object - required: - - code - - message - properties: - code: - type: integer - format: int32 - message: - type: string diff --git a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml b/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml deleted file mode 100644 index fd56f8f75e..0000000000 --- a/incubator/command-generate/src/test/resources/io/aklivity/zilla/runtime/command/generate/internal/openapi/http/proxy/validator/zilla.yaml +++ /dev/null @@ -1,155 +0,0 @@ -name: example -bindings: - tcp_server0: - type: tcp - kind: server - options: - host: 0.0.0.0 - port: 8080 - routes: - - exit: http_server0 - when: - - port: 8080 - http_server0: - type: http - kind: server - options: - access-control: - policy: cross-origin - requests: - - path: /items - method: GET - params: - query: - limit: int32 - - path: /items - method: POST - content: - model: json - catalog: - catalog0: - - subject: Item - - path: "/items/{id}" - method: GET - params: - path: - id: string - - path: "/items/{id}" - method: PUT - headers: - hello: int32 - params: - path: - id: string - query: - limit: int32 - ciao: string - - path: "/items/{id}" - method: DELETE - params: - path: - id: string - routes: - - exit: http_client0 - when: - - headers: - :path: /items - :method: GET - - exit: http_client0 - when: - - headers: - :path: /items - :method: POST - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: GET - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: PUT - - exit: http_client0 - when: - - headers: - :path: /items/* - :method: DELETE - http_client0: - type: http - kind: client - options: - requests: - - path: /items - method: GET - responses: - - status: 200 - content-type: - - application/json - headers: - x-pages: int32 - x-next: string - content: - model: json - catalog: - catalog0: - - subject: Items - - path: "/items/{id}" - method: GET - responses: - - status: 200 - content-type: - - application/json - content: - model: json - catalog: - catalog0: - - subject: Item - exit: tcp_client0 - tcp_client0: - type: tcp - kind: client - options: - host: "${{env.TCP_CLIENT_HOST}}" - port: ${{env.TCP_CLIENT_PORT}} -catalogs: - catalog0: - type: inline - options: - subjects: - Item: - schema: | - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest - Error: - schema: | - type: object - properties: - code: - type: integer - message: - type: string - required: - - code - - message - version: latest - Items: - schema: | - type: array - items: - type: object - properties: - greeting: - type: string - tag: - type: string - required: - - greeting - version: latest diff --git a/incubator/command-log/pom.xml b/incubator/command-log/pom.xml index 3d744fdef0..c61ceb505e 100644 --- a/incubator/command-log/pom.xml +++ b/incubator/command-log/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml @@ -81,7 +81,7 @@ commons-cli commons-cli - 1.6.0 + 1.7.0 diff --git a/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/spy/OneToOneRingBufferSpy.java b/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/spy/OneToOneRingBufferSpy.java index 6dadb41525..ae9a79c437 100644 --- a/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/spy/OneToOneRingBufferSpy.java +++ b/incubator/command-log/src/main/java/io/aklivity/zilla/runtime/command/log/internal/spy/OneToOneRingBufferSpy.java @@ -43,7 +43,7 @@ public OneToOneRingBufferSpy( final AtomicBuffer buffer) { this.buffer = buffer; - checkCapacity(buffer.capacity()); + checkCapacity(buffer.capacity(), 0); capacity = buffer.capacity() - TRAILER_LENGTH; buffer.verifyAlignment(); diff --git a/incubator/command-tune/pom.xml b/incubator/command-tune/pom.xml index e825cd9bba..2e21fbc789 100644 --- a/incubator/command-tune/pom.xml +++ b/incubator/command-tune/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla incubator - 0.9.79 + 0.9.80 ../pom.xml diff --git a/incubator/pom.xml b/incubator/pom.xml index 39560cbeef..c5aa4a3344 100644 --- a/incubator/pom.xml +++ b/incubator/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml @@ -26,7 +26,6 @@ command-log command-dump - command-generate command-tune @@ -57,11 +56,6 @@ command-dump ${project.version} - - ${project.groupId} - command-generate - ${project.version} - diff --git a/manager/pom.xml b/manager/pom.xml index b35ea225b9..d68c61b0e2 100644 --- a/manager/pom.xml +++ b/manager/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/pom.xml b/pom.xml index 5634a743ef..1e79eab3d8 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 io.aklivity.zilla zilla - 0.9.79 + 0.9.80 pom zilla https://github.com/aklivity/zilla @@ -45,9 +45,9 @@ io/aklivity/zilla/conf/checkstyle/configuration.xml io/aklivity/zilla/conf/checkstyle/suppressions.xml 4.13.0 - 1.6.0 + 1.21.1 1.7.36 - 5.10.1 + 5.10.2 4.0.22 2.6.0 5.8.0 diff --git a/runtime/binding-asyncapi/pom.xml b/runtime/binding-asyncapi/pom.xml index 8f5cbd55b3..9967789f3e 100644 --- a/runtime/binding-asyncapi/pom.xml +++ b/runtime/binding-asyncapi/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java index 9f026a3355..e8b130ec05 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiBindingConfig.java @@ -47,6 +47,7 @@ import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.String16FW; import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.String8FW; import io.aklivity.zilla.runtime.binding.asyncapi.internal.types.stream.HttpBeginExFW; +import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.KindConfig; @@ -222,39 +223,55 @@ private void attachProxyBinding( (existingValue, newValue) -> existingValue, Object2ObjectHashMap::new)); + namespaceGenerator.init(binding); final NamespaceConfig composite = namespaceGenerator.generateProxy(binding, asyncapis, schemaIdsByApiId::get); composite.readURL = binding.readURL; attach.accept(composite); - for (AsyncapiSchemaConfig config : configs) - { - Asyncapi asyncapi = config.asyncapi; - updateNamespace(config, composite, asyncapi); - } + updateNamespace(configs, composite, new ArrayList<>(asyncapis.values())); } private void attachServerClientBinding( BindingConfig binding, List configs) { + final Map namespaceConfigs = new HashMap<>(); for (AsyncapiSchemaConfig config : configs) { + namespaceGenerator.init(binding); Asyncapi asyncapi = config.asyncapi; - final NamespaceConfig composite = namespaceGenerator.generate(binding, asyncapi); + final List servers = + namespaceGenerator.filterAsyncapiServers(asyncapi, options.asyncapis.stream() + .filter(a -> a.apiLabel.equals(config.apiLabel)) + .flatMap(a -> a.servers.stream()) + .collect(Collectors.toList())); + + servers.stream().collect(Collectors.groupingBy(AsyncapiServerView::getPort)).forEach((k, v) -> + namespaceConfigs.computeIfAbsent(k, s -> new AsyncapiNamespaceConfig()).addSpecForNamespace(v, config, asyncapi)); + } + + for (AsyncapiNamespaceConfig namespaceConfig : namespaceConfigs.values()) + { + namespaceConfig.servers.forEach(s -> s.setAsyncapiProtocol( + namespaceGenerator.resolveProtocol(s.protocol(), options, namespaceConfig.asyncapis, namespaceConfig.servers))); + final NamespaceConfig composite = namespaceGenerator.generate(binding, namespaceConfig); composite.readURL = binding.readURL; attach.accept(composite); - updateNamespace(config, composite, asyncapi); + updateNamespace(namespaceConfig.configs, composite, namespaceConfig.asyncapis); } } private void updateNamespace( - AsyncapiSchemaConfig config, + List configs, NamespaceConfig composite, - Asyncapi asyncapi) + List asyncapis) { - composites.put(config.schemaId, composite); - schemaIdsByApiId.put(config.apiLabel, config.schemaId); - extractChannels(asyncapi); - extractOperations(asyncapi); + configs.forEach(c -> + { + composites.put(c.schemaId, composite); + schemaIdsByApiId.put(c.apiLabel, c.schemaId); + }); + asyncapis.forEach(this::extractChannels); + asyncapis.forEach(this::extractOperations); } private void extractNamespace( diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiClientNamespaceGenerator.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiClientNamespaceGenerator.java index ced6b768af..e1f2908402 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiClientNamespaceGenerator.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiClientNamespaceGenerator.java @@ -18,10 +18,8 @@ import static java.util.Collections.emptyList; import java.util.List; -import java.util.stream.Collectors; import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig; -import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.MetricRefConfig; @@ -32,33 +30,24 @@ public class AsyncapiClientNamespaceGenerator extends AsyncapiNamespaceGenerator { public NamespaceConfig generate( BindingConfig binding, - Asyncapi asyncapi) + AsyncapiNamespaceConfig namespaceConfig) { + List servers = namespaceConfig.servers; AsyncapiOptionsConfig options = binding.options != null ? (AsyncapiOptionsConfig) binding.options : EMPTY_OPTION; final List metricRefs = binding.telemetryRef != null ? binding.telemetryRef.metricRefs : emptyList(); - this.asyncapi = asyncapi; - this.qname = binding.qname; - this.namespace = binding.namespace; - this.qvault = binding.qvault; - this.vault = binding.vault; - final List servers = - filterAsyncapiServers(asyncapi.servers, options.asyncapis.stream() - .flatMap(a -> a.servers.stream()) - .collect(Collectors.toList())); - servers.forEach(s -> s.setAsyncapiProtocol(resolveProtocol(s.protocol(), options, servers))); - //TODO: keep it until we support different protocols on the same composite binding AsyncapiServerView serverView = servers.get(0); this.protocol = serverView.getAsyncapiProtocol(); int[] compositeSecurePorts = resolvePorts(servers, true); this.isTlsEnabled = compositeSecurePorts.length > 0; + final String namespace = String.join("+", namespaceConfig.asyncapiLabels); return NamespaceConfig.builder() - .name(String.format("%s.%s", qname, "$composite")) + .name(String.format("%s.%s-%s", qname, "$composite", namespace)) .inject(n -> this.injectNamespaceMetric(n, !metricRefs.isEmpty())) - .inject(n -> this.injectCatalog(n, asyncapi)) + .inject(n -> this.injectCatalog(n, namespaceConfig.asyncapis)) .inject(n -> protocol.injectProtocolClientCache(n, metricRefs)) .binding() .name(String.format("%s_client0", protocol.scheme)) diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiHttpProtocol.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiHttpProtocol.java index 271be8235e..5f959d2628 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiHttpProtocol.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiHttpProtocol.java @@ -14,6 +14,7 @@ */ package io.aklivity.zilla.runtime.binding.asyncapi.internal.config; +import static io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiNamespaceGenerator.APPLICATION_JSON; import static io.aklivity.zilla.runtime.binding.http.config.HttpPolicyConfig.CROSS_ORIGIN; import java.util.List; @@ -24,9 +25,9 @@ import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage; import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiOperation; import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiParameter; +import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiSchema; import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiServer; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiChannelView; -import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiMessageView; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; import io.aklivity.zilla.runtime.binding.http.config.HttpAuthorizationConfig; import io.aklivity.zilla.runtime.binding.http.config.HttpConditionConfig; @@ -35,23 +36,33 @@ import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfig.Method; import io.aklivity.zilla.runtime.binding.http.config.HttpRequestConfigBuilder; import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder; -import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder; import io.aklivity.zilla.runtime.engine.config.GuardedConfigBuilder; import io.aklivity.zilla.runtime.engine.config.ModelConfig; import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.DoubleModelConfig; +import io.aklivity.zilla.runtime.model.core.config.FloatModelConfig; import io.aklivity.zilla.runtime.model.core.config.Int32ModelConfig; +import io.aklivity.zilla.runtime.model.core.config.Int64ModelConfig; import io.aklivity.zilla.runtime.model.core.config.StringModelConfig; +import io.aklivity.zilla.runtime.model.core.config.StringModelConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.StringPattern; +import io.aklivity.zilla.runtime.model.core.internal.StringModel; import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; public class AsyncapiHttpProtocol extends AsyncapiProtocol { - private static final Map MODELS = Map.of( - "string", StringModelConfig.builder().build(), - "integer", Int32ModelConfig.builder().build() - ); private static final String SCHEME = "http"; private static final String SECURE_PROTOCOL = "https"; + protected static final Map MODELS = Map.of( + "integer", Int32ModelConfig.builder().build(), + "integer:int32", Int32ModelConfig.builder().build(), + "integer:int64", Int64ModelConfig.builder().build(), + "number", FloatModelConfig.builder().build(), + "number:float", FloatModelConfig.builder().build(), + "number:double", DoubleModelConfig.builder().build() + ); + private static final String SECURE_SCHEME = "https"; private final Map securitySchemes; private final boolean isJwtEnabled; @@ -60,11 +71,11 @@ public class AsyncapiHttpProtocol extends AsyncapiProtocol protected AsyncapiHttpProtocol( String qname, - Asyncapi asyncApi, + List asyncapis, AsyncapiOptionsConfig options, String protocol) { - super(qname, asyncApi, protocol, SCHEME); + super(qname, asyncapis, protocol, SCHEME); this.securitySchemes = resolveSecuritySchemes(); this.isJwtEnabled = !securitySchemes.isEmpty(); @@ -91,26 +102,27 @@ public BindingConfigBuilder injectProtocolServerOptions( public BindingConfigBuilder injectProtocolServerRoutes( BindingConfigBuilder binding) { - for (Map.Entry entry : asyncApi.servers.entrySet()) + for (Asyncapi asyncapi : asyncapis) { - AsyncapiServerView server = AsyncapiServerView.of(entry.getValue()); - for (String name : asyncApi.operations.keySet()) + for (Map.Entry entry : asyncapi.servers.entrySet()) { - AsyncapiOperation operation = asyncApi.operations.get(name); - AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel); - String path = channel.address().replaceAll("\\{[^}]+\\}", "*"); - String method = operation.bindings.get("http").method; - binding - .route() + AsyncapiServerView server = AsyncapiServerView.of(entry.getValue()); + for (String name : asyncapi.operations.keySet()) + { + AsyncapiOperation operation = asyncapi.operations.get(name); + AsyncapiChannelView channel = AsyncapiChannelView.of(asyncapi.channels, operation.channel); + String path = channel.address().replaceAll("\\{[^}]+\\}", "*"); + String method = operation.bindings.get("http").method; + binding + .route() .exit(qname) .when(HttpConditionConfig::builder) - .header(":scheme", server.scheme()) - .header(":authority", server.authority()) .header(":path", path) .header(":method", method) .build() .inject(route -> injectHttpServerRouteGuarded(route, server)) - .build(); + .build(); + } } } return binding; @@ -135,22 +147,25 @@ private HttpOptionsConfigBuilder injectHttpServerOptions( private HttpOptionsConfigBuilder injectHttpServerRequests( HttpOptionsConfigBuilder options) { - for (String name : asyncApi.operations.keySet()) + for (Asyncapi asyncapi : asyncapis) { - AsyncapiOperation operation = asyncApi.operations.get(name); - AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel); - String path = channel.address(); - Method method = Method.valueOf(operation.bindings.get("http").method); - if (channel.messages() != null && !channel.messages().isEmpty() || - channel.parameters() != null && !channel.parameters().isEmpty()) + for (String name : asyncapi.operations.keySet()) { - options - .request() - .path(path) - .method(method) - .inject(request -> injectContent(request, channel.messages())) - .inject(request -> injectPathParams(request, channel.parameters())) + AsyncapiOperation operation = asyncapi.operations.get(name); + AsyncapiChannelView channel = AsyncapiChannelView.of(asyncapi.channels, operation.channel); + String path = channel.address(); + Method method = Method.valueOf(operation.bindings.get("http").method); + if (channel.messages() != null && !channel.messages().isEmpty() || + channel.parameters() != null && !channel.parameters().isEmpty()) + { + options + .request() + .path(path) + .method(method) + .inject(request -> injectContent(request, asyncapi, channel.messages())) + .inject(request -> injectPathParams(request, channel.parameters())) .build(); + } } } return options; @@ -158,41 +173,25 @@ private HttpOptionsConfigBuilder injectHttpServerRequests( private HttpRequestConfigBuilder injectContent( HttpRequestConfigBuilder request, + Asyncapi asyncapi, Map messages) { if (messages != null) { - if (hasJsonContentType()) + if (hasJsonContentType(asyncapi)) { request. content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .inject(catalog -> injectSchemas(catalog, messages)) - .build() - .build(); + .catalog() + .name(INLINE_CATALOG_NAME) + .inject(cataloged -> injectJsonSchemas(cataloged, asyncapi, messages, APPLICATION_JSON)) + .build() + .build(); } } return request; } - private CatalogedConfigBuilder injectSchemas( - CatalogedConfigBuilder catalog, - Map messages) - { - for (String name : messages.keySet()) - { - AsyncapiMessageView message = AsyncapiMessageView.of(asyncApi.components.messages, messages.get(name)); - String subject = message.refKey() != null ? message.refKey() : name; - catalog - .schema() - .subject(subject) - .build() - .build(); - } - return catalog; - } - private HttpRequestConfigBuilder injectPathParams( HttpRequestConfigBuilder request, Map parameters) @@ -202,9 +201,25 @@ private HttpRequestConfigBuilder injectPathParams( for (String name : parameters.keySet()) { AsyncapiParameter parameter = parameters.get(name); - if (parameter.schema != null && parameter.schema.type != null) + AsyncapiSchema schema = parameter.schema; + if (schema != null && schema.type != null) { - ModelConfig model = MODELS.get(parameter.schema.type); + String format = schema.format; + String type = schema.type; + ModelConfig model; + if (StringModel.NAME.equals(type)) + { + StringModelConfigBuilder builder = StringModelConfig.builder(); + if (format != null) + { + builder.pattern(StringPattern.of(format)); + } + model = builder.build(); + } + else + { + model = MODELS.get(format != null ? String.format("%s:%s", type, format) : type); + } if (model != null) { request diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiMqttProtocol.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiMqttProtocol.java index a362960990..970472f3d4 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiMqttProtocol.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiMqttProtocol.java @@ -16,6 +16,7 @@ import static io.aklivity.zilla.runtime.binding.asyncapi.internal.config.AsyncapiNamespaceGenerator.APPLICATION_JSON; +import java.util.List; import java.util.Map; import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig; @@ -46,12 +47,12 @@ public class AsyncapiMqttProtocol extends AsyncapiProtocol public AsyncapiMqttProtocol( String qname, - Asyncapi asyncApi, + List asyncapis, AsyncapiOptionsConfig options, String protocol, String namespace) { - super(qname, asyncApi, protocol, SCHEME); + super(qname, asyncapis, protocol, SCHEME); final MqttOptionsConfig mqttOptions = options.mqtt; this.guardName = mqttOptions != null ? String.format("%s:%s", namespace, mqttOptions.authorization.name) : null; this.authorization = mqttOptions != null ? @@ -83,23 +84,26 @@ private MqttOptionsConfigBuilder injectMqttAuthorization( private MqttOptionsConfigBuilder injectMqttTopicsOptions( MqttOptionsConfigBuilder options) { - for (Map.Entry channelEntry : asyncApi.channels.entrySet()) + for (Asyncapi asyncapi : asyncapis) { - String topic = channelEntry.getValue().address.replaceAll("\\{[^}]+\\}", "#"); - Map messages = channelEntry.getValue().messages; - if (hasJsonContentType()) + for (Map.Entry channelEntry : asyncapi.channels.entrySet()) { - options - .topic() - .name(topic) - .content(JsonModelConfig::builder) - .catalog() - .name(INLINE_CATALOG_NAME) - .inject(cataloged -> injectJsonSchemas(cataloged, messages, APPLICATION_JSON)) + String topic = channelEntry.getValue().address.replaceAll("\\{[^}]+\\}", "#"); + Map messages = channelEntry.getValue().messages; + if (hasJsonContentType(asyncapi)) + { + options + .topic() + .name(topic) + .content(JsonModelConfig::builder) + .catalog() + .name(INLINE_CATALOG_NAME) + .inject(cataloged -> injectJsonSchemas(cataloged, asyncapi, messages, APPLICATION_JSON)) + .build() .build() - .build() - .inject(t -> injectMqttUserPropertiesConfig(t, messages)) - .build(); + .inject(t -> injectMqttUserPropertiesConfig(t, asyncapi, messages)) + .build(); + } } } return options; @@ -107,24 +111,25 @@ private MqttOptionsConfigBuilder injectMqttTopicsOptions( private MqttTopicConfigBuilder injectMqttUserPropertiesConfig( MqttTopicConfigBuilder topic, + Asyncapi asyncapi, Map messages) { for (Map.Entry messageEntry : messages.entrySet()) { AsyncapiMessageView message = - AsyncapiMessageView.of(asyncApi.components.messages, messageEntry.getValue()); + AsyncapiMessageView.of(asyncapi.components.messages, messageEntry.getValue()); if (message.traits() != null) { for (AsyncapiTrait asyncapiTrait : message.traits()) { - AsyncapiTraitView trait = AsyncapiTraitView.of(asyncApi.components.messageTraits, asyncapiTrait); + AsyncapiTraitView trait = AsyncapiTraitView.of(asyncapi.components.messageTraits, asyncapiTrait); for (Map.Entry header : trait.commonHeaders().properties.entrySet()) { topic .userProperty() - .inject(u -> injectUserProperty(u, header.getKey())) + .inject(u -> injectUserProperty(u, INLINE_CATALOG_NAME, header.getKey())) .build(); } } @@ -136,13 +141,14 @@ private MqttTopicConfigBuilder injectMqttUserPropertiesConfig( private MqttUserPropertyConfigBuilder injectUserProperty( MqttUserPropertyConfigBuilder userProperty, + String catalogName, String subject) { userProperty .name(subject) .value(JsonModelConfig::builder) .catalog() - .name(INLINE_CATALOG_NAME) + .name(catalogName) .schema() .version(VERSION_LATEST) .subject(subject) @@ -156,23 +162,26 @@ private MqttUserPropertyConfigBuilder injectUserProperty( public BindingConfigBuilder injectProtocolServerRoutes( BindingConfigBuilder binding) { - for (Map.Entry entry : asyncApi.channels.entrySet()) + for (Asyncapi asyncapi : asyncapis) { - String topic = entry.getValue().address.replaceAll("\\{[^}]+\\}", "#"); - binding - .route() - .when(MqttConditionConfig::builder) - .publish() - .topic(topic) + for (Map.Entry entry : asyncapi.channels.entrySet()) + { + String topic = entry.getValue().address.replaceAll("\\{[^}]+\\}", "#"); + binding + .route() + .when(MqttConditionConfig::builder) + .publish() + .topic(topic) + .build() .build() - .build() - .when(MqttConditionConfig::builder) - .subscribe() - .topic(topic) + .when(MqttConditionConfig::builder) + .subscribe() + .topic(topic) + .build() .build() - .build() - .exit(qname) - .build(); + .exit(qname) + .build(); + } } return binding; } diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceConfig.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceConfig.java new file mode 100644 index 0000000000..e725677450 --- /dev/null +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.binding.asyncapi.internal.config; + +import java.util.ArrayList; +import java.util.List; + +import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiSchemaConfig; +import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi; +import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; + +class AsyncapiNamespaceConfig +{ + List asyncapiLabels; + List servers; + List asyncapis; + List configs; + + AsyncapiNamespaceConfig() + { + asyncapiLabels = new ArrayList<>(); + servers = new ArrayList<>(); + asyncapis = new ArrayList<>(); + configs = new ArrayList<>(); + } + + public void addSpecForNamespace( + List servers, + AsyncapiSchemaConfig config, + Asyncapi asyncapi) + { + this.asyncapiLabels.add(config.apiLabel); + this.servers.addAll(servers); + this.configs.add(config); + this.asyncapis.add(asyncapi); + } +} diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceGenerator.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceGenerator.java index 45dfa42ed5..ddf75ede2c 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceGenerator.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiNamespaceGenerator.java @@ -65,7 +65,6 @@ public abstract class AsyncapiNamespaceGenerator protected static final Pattern VARIABLE = Pattern.compile("\\{([^}]*.?)\\}"); protected final Matcher variable = VARIABLE.matcher(""); - protected Asyncapi asyncapi; protected Map asyncapis; protected boolean isTlsEnabled; protected AsyncapiProtocol protocol; @@ -74,9 +73,18 @@ public abstract class AsyncapiNamespaceGenerator protected String qvault; protected String vault; + public void init( + BindingConfig binding) + { + this.qname = binding.qname; + this.namespace = binding.namespace; + this.qvault = binding.qvault; + this.vault = binding.vault; + } + public NamespaceConfig generate( BindingConfig binding, - Asyncapi asyncapi) + AsyncapiNamespaceConfig namespaceConfig) { return null; } @@ -92,6 +100,7 @@ public NamespaceConfig generateProxy( protected AsyncapiProtocol resolveProtocol( String protocolName, AsyncapiOptionsConfig options, + List asyncapis, List servers) { Pattern pattern = Pattern.compile("(http|mqtt|kafka)"); @@ -102,14 +111,14 @@ protected AsyncapiProtocol resolveProtocol( switch (matcher.group()) { case "http": - protocol = new AsyncapiHttpProtocol(qname, asyncapi, options, protocolName); + protocol = new AsyncapiHttpProtocol(qname, asyncapis, options, protocolName); break; case "mqtt": - protocol = new AsyncapiMqttProtocol(qname, asyncapi, options, protocolName, namespace); + protocol = new AsyncapiMqttProtocol(qname, asyncapis, options, protocolName, namespace); break; case "kafka": case "kafka-secure": - protocol = new AyncapiKafkaProtocol(qname, asyncapi, servers, options, protocolName); + protocol = new AyncapiKafkaProtocol(qname, asyncapis, servers, options, protocolName); break; } } @@ -121,9 +130,10 @@ protected AsyncapiProtocol resolveProtocol( } protected List filterAsyncapiServers( - Map servers, + Asyncapi asyncapi, List serverConfigs) { + final Map servers = asyncapi.servers; List filtered; Map serverViews = servers.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, e -> AsyncapiServerView.of(e.getValue(), asyncapi.components.serverVariables))); @@ -178,9 +188,11 @@ public int[] resolvePorts( protected NamespaceConfigBuilder injectCatalog( NamespaceConfigBuilder namespace, - Asyncapi asyncapi) + List asyncapis) { - if (asyncapi.components != null && asyncapi.components.schemas != null && !asyncapi.components.schemas.isEmpty()) + final boolean injectCatalog = asyncapis.stream() + .anyMatch(a -> a.components != null && a.components.schemas != null && !a.components.schemas.isEmpty()); + if (injectCatalog) { namespace .catalog() @@ -188,7 +200,7 @@ protected NamespaceConfigBuilder injectCatalog( .type(INLINE_CATALOG_TYPE) .options(InlineOptionsConfig::builder) .subjects() - .inject(this::injectSubjects) + .inject(s -> injectSubjects(s, asyncapis)) .build() .build() .build(); @@ -197,41 +209,48 @@ protected NamespaceConfigBuilder injectCatalog( } protected InlineSchemaConfigBuilder injectSubjects( - InlineSchemaConfigBuilder subjects) + InlineSchemaConfigBuilder subjects, + List asyncapis) { - try (Jsonb jsonb = JsonbBuilder.create()) + for (Asyncapi asyncapi : asyncapis) { - YAMLMapper yaml = YAMLMapper.builder() - .disable(WRITE_DOC_START_MARKER) - .enable(MINIMIZE_QUOTES) - .build(); - for (Map.Entry entry : asyncapi.components.schemas.entrySet()) - { - AsyncapiSchemaView schema = AsyncapiSchemaView.of(asyncapi.components.schemas, entry.getValue()); - - subjects - .subject(entry.getKey()) - .version(VERSION_LATEST) - .schema(writeSchemaYaml(jsonb, yaml, schema)) - .build(); - } - if (asyncapi.components.messageTraits != null) + if (asyncapi.components != null && asyncapi.components.schemas != null && !asyncapi.components.schemas.isEmpty()) { - for (Map.Entry entry : asyncapi.components.messageTraits.entrySet()) + try (Jsonb jsonb = JsonbBuilder.create()) { - entry.getValue().headers.properties.forEach((k, v) -> + YAMLMapper yaml = YAMLMapper.builder() + .disable(WRITE_DOC_START_MARKER) + .enable(MINIMIZE_QUOTES) + .build(); + for (Map.Entry entry : asyncapi.components.schemas.entrySet()) + { + AsyncapiSchemaView schema = AsyncapiSchemaView.of(asyncapi.components.schemas, entry.getValue()); + subjects - .subject(k) + .subject(entry.getKey()) .version(VERSION_LATEST) - .schema(writeSchemaYaml(jsonb, yaml, v)) - .build()); + .schema(writeSchemaYaml(jsonb, yaml, schema)) + .build(); + } + if (asyncapi.components.messageTraits != null) + { + for (Map.Entry entry : asyncapi.components.messageTraits.entrySet()) + { + entry.getValue().headers.properties.forEach((k, v) -> + subjects + .subject(k) + .version(VERSION_LATEST) + .schema(writeSchemaYaml(jsonb, yaml, v)) + .build()); + } + } + } + catch (Exception ex) + { + rethrowUnchecked(ex); } } } - catch (Exception ex) - { - rethrowUnchecked(ex); - } return subjects; } diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProtocol.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProtocol.java index a28f22d3aa..4c9a60f1bb 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProtocol.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProtocol.java @@ -16,7 +16,6 @@ import static java.util.Objects.requireNonNull; -import java.net.URI; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,7 +27,6 @@ import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.AsyncapiMessage; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiMessageView; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiSchemaView; -import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; import io.aklivity.zilla.runtime.engine.config.BindingConfigBuilder; import io.aklivity.zilla.runtime.engine.config.CatalogedConfigBuilder; import io.aklivity.zilla.runtime.engine.config.MetricRefConfig; @@ -42,7 +40,7 @@ public abstract class AsyncapiProtocol protected static final String VERSION_LATEST = "latest"; protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher(""); - protected Asyncapi asyncApi; + protected final List asyncapis; protected String qname; protected Map securitySchemes; protected boolean isJwtEnabled; @@ -51,12 +49,12 @@ public abstract class AsyncapiProtocol protected AsyncapiProtocol( String qname, - Asyncapi asyncApi, + List asyncapis, String protocol, String scheme) { this.qname = qname; - this.asyncApi = asyncApi; + this.asyncapis = asyncapis; this.protocol = protocol; this.scheme = scheme; this.securitySchemes = resolveSecuritySchemes(); @@ -84,25 +82,25 @@ public BindingConfigBuilder injectProtocolClientOptions( protected CatalogedConfigBuilder injectJsonSchemas( CatalogedConfigBuilder cataloged, + Asyncapi asyncapi, Map messages, String contentType) { for (Map.Entry messageEntry : messages.entrySet()) { AsyncapiMessageView message = - AsyncapiMessageView.of(asyncApi.components.messages, messageEntry.getValue()); + AsyncapiMessageView.of(asyncapi.components.messages, messageEntry.getValue()); if (message.payload() != null) { - String schema = AsyncapiSchemaView.of(asyncApi.components.schemas, message.payload()).refKey(); + String schema = AsyncapiSchemaView.of(asyncapi.components.schemas, message.payload()).refKey(); if (message.contentType() != null && message.contentType().equals(contentType) || - jsonContentType.reset(asyncApi.defaultContentType).matches()) + jsonContentType.reset(asyncapi.defaultContentType).matches()) { cataloged .schema() - .version(VERSION_LATEST) - .subject(schema) - .build() - .build(); + .version(VERSION_LATEST) + .subject(schema) + .build(); } else { @@ -113,54 +111,41 @@ protected CatalogedConfigBuilder injectJsonSchemas( return cataloged; } - protected boolean hasJsonContentType() + protected boolean hasJsonContentType( + Asyncapi asyncapi) { String contentType = null; - if (asyncApi.components != null && asyncApi.components.messages != null && - !asyncApi.components.messages.isEmpty()) + if (asyncapi.components != null && asyncapi.components.messages != null && + !asyncapi.components.messages.isEmpty()) { - AsyncapiMessage firstAsyncapiMessage = asyncApi.components.messages.entrySet().stream() + AsyncapiMessage firstAsyncapiMessage = asyncapi.components.messages.entrySet().stream() .findFirst().get().getValue(); - contentType = AsyncapiMessageView.of(asyncApi.components.messages, firstAsyncapiMessage).contentType(); + contentType = AsyncapiMessageView.of(asyncapi.components.messages, firstAsyncapiMessage).contentType(); } - return contentType != null && jsonContentType.reset(contentType).matches() || asyncApi.defaultContentType != null && - jsonContentType.reset(asyncApi.defaultContentType).matches(); + return contentType != null && jsonContentType.reset(contentType).matches() || asyncapi.defaultContentType != null && + jsonContentType.reset(asyncapi.defaultContentType).matches(); } protected abstract boolean isSecure(); protected Map resolveSecuritySchemes() { - requireNonNull(asyncApi); + requireNonNull(asyncapis); Map result = new HashMap<>(); - if (asyncApi.components != null && asyncApi.components.securitySchemes != null) + for (Asyncapi asyncapi : asyncapis) { - for (String securitySchemeName : asyncApi.components.securitySchemes.keySet()) + if (asyncapi.components != null && asyncapi.components.securitySchemes != null) { - String guardType = asyncApi.components.securitySchemes.get(securitySchemeName).bearerFormat; - //TODO: change when jwt support added for mqtt in asyncapi - //if ("jwt".equals(guardType)) - //{ - // result.put(securitySchemeName, guardType); - //} - result.put(securitySchemeName, guardType); - } - } - return result; - } - - protected URI findFirstServerUrlWithScheme( - String scheme) - { - requireNonNull(scheme); - URI result = null; - for (String key : asyncApi.servers.keySet()) - { - AsyncapiServerView server = AsyncapiServerView.of(asyncApi.servers.get(key)); - if (scheme.equals(server.url().getScheme())) - { - result = server.url(); - break; + for (String securitySchemeName : asyncapi.components.securitySchemes.keySet()) + { + String guardType = asyncapi.components.securitySchemes.get(securitySchemeName).bearerFormat; + //TODO: change when jwt support added for mqtt in asyncapi + //if ("jwt".equals(guardType)) + //{ + // result.put(securitySchemeName, guardType); + //} + result.put(securitySchemeName, guardType); + } } } return result; diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProxyNamespaceGenerator.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProxyNamespaceGenerator.java index 67d2a8518c..79cb502d77 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProxyNamespaceGenerator.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiProxyNamespaceGenerator.java @@ -54,7 +54,7 @@ public NamespaceConfig generateProxy( .map(r -> new AsyncapiRouteConfig(r, resolveApiId)) .collect(Collectors.toList()); this.asyncapis = asyncapis; - this.qname = binding.qname; + final List metricRefs = binding.telemetryRef != null ? binding.telemetryRef.metricRefs : emptyList(); @@ -130,14 +130,15 @@ public BindingConfigBuilder injectMqttKafkaRoutes( final AsyncapiChannelView channel = AsyncapiChannelView.of(mqttAsyncapi.channels, whenOperation.channel); final MqttKafkaConditionKind kind = whenOperation.action.equals(ASYNCAPI_SEND_ACTION_NAME) ? MqttKafkaConditionKind.PUBLISH : MqttKafkaConditionKind.SUBSCRIBE; - final String topic = channel.address().replaceAll("\\{[^}]+\\}", "+"); + String topic = channel.address(); + routeBuilder .when(MqttKafkaConditionConfig::builder) .topic(topic) .kind(kind) .build() .with(MqttKafkaWithConfig::builder) - .messages(messages) + .messages(messages.replaceAll("\\{([^{}]*)\\}", "\\${params.$1}")) .build() .exit(qname); } diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiServerNamespaceGenerator.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiServerNamespaceGenerator.java index b8cf008d2c..c58961015a 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiServerNamespaceGenerator.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AsyncapiServerNamespaceGenerator.java @@ -18,10 +18,8 @@ import static java.util.Collections.emptyList; import java.util.List; -import java.util.stream.Collectors; import io.aklivity.zilla.runtime.binding.asyncapi.config.AsyncapiOptionsConfig; -import io.aklivity.zilla.runtime.binding.asyncapi.internal.model.Asyncapi; import io.aklivity.zilla.runtime.binding.asyncapi.internal.view.AsyncapiServerView; import io.aklivity.zilla.runtime.binding.tcp.config.TcpConditionConfig; import io.aklivity.zilla.runtime.binding.tcp.config.TcpOptionsConfig; @@ -36,31 +34,22 @@ public class AsyncapiServerNamespaceGenerator extends AsyncapiNamespaceGenerator { public NamespaceConfig generate( BindingConfig binding, - Asyncapi asyncapi) + AsyncapiNamespaceConfig namespaceConfig) { + List servers = namespaceConfig.servers; AsyncapiOptionsConfig options = binding.options != null ? (AsyncapiOptionsConfig) binding.options : EMPTY_OPTION; final List metricRefs = binding.telemetryRef != null ? binding.telemetryRef.metricRefs : emptyList(); - this.asyncapi = asyncapi; - this.qname = binding.qname; - this.qvault = binding.qvault; - this.namespace = binding.namespace; - - final List servers = - filterAsyncapiServers(asyncapi.servers, options.asyncapis.stream() - .flatMap(a -> a.servers.stream()) - .collect(Collectors.toList())); - servers.forEach(s -> s.setAsyncapiProtocol(resolveProtocol(s.protocol(), options, servers))); - //TODO: keep it until we support different protocols on the same composite binding AsyncapiServerView serverView = servers.get(0); this.protocol = serverView.getAsyncapiProtocol(); + final String namespace = String.join("+", namespaceConfig.asyncapiLabels); return NamespaceConfig.builder() - .name(String.format("%s/%s", qname, protocol.scheme)) + .name(String.format("%s/%s", qname, namespace)) .inject(n -> this.injectNamespaceMetric(n, !metricRefs.isEmpty())) - .inject(n -> this.injectCatalog(n, asyncapi)) + .inject(n -> this.injectCatalog(n, namespaceConfig.asyncapis)) .inject(n -> injectTcpServer(n, servers, options, metricRefs)) .inject(n -> injectTlsServer(n, options)) .binding() @@ -68,8 +57,8 @@ public NamespaceConfig generate( .type(protocol.scheme) .inject(b -> this.injectMetrics(b, metricRefs, protocol.scheme)) .kind(SERVER) - .inject(protocol::injectProtocolServerOptions) - .inject(protocol::injectProtocolServerRoutes) + .inject(b -> protocol.injectProtocolServerOptions(b)) + .inject(b -> protocol.injectProtocolServerRoutes(b)) .build() .build(); } diff --git a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AyncapiKafkaProtocol.java b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AyncapiKafkaProtocol.java index 7929d58b1b..dbe6cd174b 100644 --- a/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AyncapiKafkaProtocol.java +++ b/runtime/binding-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/config/AyncapiKafkaProtocol.java @@ -14,6 +14,7 @@ */ package io.aklivity.zilla.runtime.binding.asyncapi.internal.config; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Pattern; @@ -50,12 +51,12 @@ public class AyncapiKafkaProtocol extends AsyncapiProtocol public AyncapiKafkaProtocol( String qname, - Asyncapi asyncApi, + List asyncapis, List servers, AsyncapiOptionsConfig options, String protocol) { - super(qname, asyncApi, protocol, SCHEME); + super(qname, asyncapis, protocol, SCHEME); this.servers = servers; this.sasl = options.kafka != null ? options.kafka.sasl : null; } @@ -145,21 +146,24 @@ private KafkaOptionsConfigBuilder injectKafkaServerOptions( private KafkaOptionsConfigBuilder injectKafkaTopicOptions( KafkaOptionsConfigBuilder options) { - for (String name : asyncApi.operations.keySet()) + for (Asyncapi asyncapi : asyncapis) { - AsyncapiOperation operation = asyncApi.operations.get(name); - AsyncapiChannelView channel = AsyncapiChannelView.of(asyncApi.channels, operation.channel); - String topic = channel.address(); - - if (channel.messages() != null && !channel.messages().isEmpty() || - channel.parameters() != null && !channel.parameters().isEmpty()) + for (String name : asyncapi.operations.keySet()) { - options - .topic(KafkaTopicConfig::builder) - .name(topic) - .inject(topicConfig -> injectValue(topicConfig, channel.messages())) - .build() - .build(); + AsyncapiOperation operation = asyncapi.operations.get(name); + AsyncapiChannelView channel = AsyncapiChannelView.of(asyncapi.channels, operation.channel); + String topic = channel.address(); + + if (channel.messages() != null && !channel.messages().isEmpty() || + channel.parameters() != null && !channel.parameters().isEmpty()) + { + options + .topic(KafkaTopicConfig::builder) + .name(topic) + .inject(topicConfig -> injectValue(topicConfig, asyncapi, channel.messages())) + .build() + .build(); + } } } return options; @@ -168,24 +172,30 @@ private KafkaOptionsConfigBuilder injectKafkaTopicOptions( private KafkaOptionsConfigBuilder injectKafkaBootstrapOptions( KafkaOptionsConfigBuilder options) { - return options.bootstrap(asyncApi.channels.values().stream() - .filter(c -> !PARAMETERIZED_TOPIC_PATTERN.matcher(c.address).find()) - .map(c -> AsyncapiChannelView.of(asyncApi.channels, c).address()).collect(Collectors.toList())); + List bootstrap = new ArrayList<>(); + for (Asyncapi asyncapi : asyncapis) + { + bootstrap.addAll(asyncapi.channels.values().stream() + .filter(c -> !PARAMETERIZED_TOPIC_PATTERN.matcher(c.address).find()) + .map(c -> AsyncapiChannelView.of(asyncapi.channels, c).address()).collect(Collectors.toList())); + } + return options.bootstrap(bootstrap); } private KafkaTopicConfigBuilder injectValue( KafkaTopicConfigBuilder topic, + Asyncapi asyncapi, Map messages) { if (messages != null) { - if (hasJsonContentType()) + if (hasJsonContentType(asyncapi)) { topic .value(JsonModelConfig::builder) .catalog() .name(INLINE_CATALOG_NAME) - .inject(catalog -> injectSchemas(catalog, messages)) + .inject(catalog -> injectSchemas(catalog, asyncapi, messages)) .build() .build(); } @@ -195,12 +205,13 @@ private KafkaTopicConfigBuilder injectValue( private CatalogedConfigBuilder injectSchemas( CatalogedConfigBuilder catalog, + Asyncapi asyncapi, Map messages) { for (String name : messages.keySet()) { - AsyncapiMessageView message = AsyncapiMessageView.of(asyncApi.components.messages, messages.get(name)); - AsyncapiSchemaView payload = AsyncapiSchemaView.of(asyncApi.components.schemas, message.payload()); + AsyncapiMessageView message = AsyncapiMessageView.of(asyncapi.components.messages, messages.get(name)); + AsyncapiSchemaView payload = AsyncapiSchemaView.of(asyncapi.components.schemas, message.payload()); String subject = payload.refKey() != null ? payload.refKey() : name; catalog .schema() diff --git a/runtime/binding-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/server/AsyncapiIT.java b/runtime/binding-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/server/AsyncapiIT.java index 9fb0d52045..6aedafa05e 100644 --- a/runtime/binding-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/server/AsyncapiIT.java +++ b/runtime/binding-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/asyncapi/internal/stream/server/AsyncapiIT.java @@ -70,4 +70,26 @@ public void shouldCreatePet() throws Exception { k3po.finish(); } + + @Test + @Configuration("server.multi.protocol.yaml") + @Specification({ + "${mqtt}/publish.and.subscribe/client", + "${asyncapi}/mqtt/publish.and.subscribe/server" + }) + public void shouldPublishAndSubscribeMultipleSpec() throws Exception + { + k3po.finish(); + } + + @Test + @Configuration("server.multi.protocol.yaml") + @Specification({ + "${http}/create.pet/client", + "${asyncapi}/http/create.pet/server" + }) + public void shouldCreatePetMultipleSpec() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/binding-echo/NOTICE b/runtime/binding-echo/NOTICE index 08323b88fb..b894dd7e66 100644 --- a/runtime/binding-echo/NOTICE +++ b/runtime/binding-echo/NOTICE @@ -12,6 +12,18 @@ specific language governing permissions and limitations under the License. This project includes: + agrona under The Apache License, Version 2.0 + ICU4J under Unicode/ICU License + Jackson-annotations under The Apache Software License, Version 2.0 + Jackson-core under The Apache Software License, Version 2.0 + jackson-databind under The Apache Software License, Version 2.0 + Jackson-dataformat-YAML under The Apache Software License, Version 2.0 + Jakarta JSON Processing API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception + JSON-B API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception + org.leadpony.justify under The Apache Software License, Version 2.0 + SnakeYAML under Apache License, Version 2.0 + zilla::runtime::common under The Apache Software License, Version 2.0 + zilla::runtime::engine under The Apache Software License, Version 2.0 This project also includes code under copyright of the following entities: diff --git a/runtime/binding-echo/pom.xml b/runtime/binding-echo/pom.xml index 59a307226e..30029f82e6 100644 --- a/runtime/binding-echo/pom.xml +++ b/runtime/binding-echo/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -41,7 +41,6 @@ ${project.groupId} engine ${project.version} - provided ${project.groupId} @@ -158,6 +157,11 @@ test-jar + + + **/*IT.class + + @@ -216,6 +220,7 @@ org.agrona:agrona io.aklivity.zilla:engine + io.aklivity.zilla:common org.openjdk.jmh:jmh-core net.sf.jopt-simple:jopt-simple org.apache.commons:commons-math3 diff --git a/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoHandshakeBM.java b/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoHandshakeBM.java new file mode 100644 index 0000000000..522a9210f2 --- /dev/null +++ b/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoHandshakeBM.java @@ -0,0 +1,152 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.echo.internal.bench; + +import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.io.IOException; + +import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.UnsafeBuffer; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Control; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import io.aklivity.zilla.runtime.binding.echo.internal.types.stream.BeginFW; +import io.aklivity.zilla.runtime.binding.echo.internal.types.stream.WindowFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.binding.BindingContext; +import io.aklivity.zilla.runtime.engine.binding.BindingFactory; +import io.aklivity.zilla.runtime.engine.binding.BindingHandler; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.config.BindingConfig; +import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@Fork(3) +@Warmup(iterations = 10, time = 1, timeUnit = SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = SECONDS) +@OutputTimeUnit(SECONDS) +public class EchoHandshakeBM +{ + private static final int BUFFER_SIZE = 1024 * 8; + + private final BeginFW.Builder beginRW = new BeginFW.Builder(); + private final WindowFW.Builder windowRW = new WindowFW.Builder(); + private final MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[BUFFER_SIZE]); + + private BindingHandler handler; + private Runnable detacher; + + @Setup(Level.Trial) + public void init() throws IOException + { + BindingFactory bindings = BindingFactory.instantiate(); + BindingContext context = bindings.create("echo", new Configuration()) + .supply(new EchoWorker()); + + NamespaceConfig namespace = NamespaceConfig.builder() + .name("echo") + .binding() + .name("echo_server0") + .type("echo") + .kind(SERVER) + .build() + .build(); + + BindingConfig binding = namespace.bindings.stream() + .filter(b -> "echo_server0".equals(b.name)) + .findFirst() + .get(); + + this.handler = context.attach(binding); + this.detacher = () -> context.detach(binding); + } + + @TearDown(Level.Trial) + public void destroy() + { + detacher.run(); + } + + @Setup(Level.Iteration) + public void reset() + { + } + + @Benchmark + public void handshake( + final Control control) throws Exception + { + final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) + .routedId(0L) + .streamId(0L) + .sequence(0L) + .acknowledge(0L) + .maximum(BUFFER_SIZE) + .traceId(0L) + .authorization(0L) + .affinity(0L) + .build(); + + MessageConsumer sender = MessageConsumer.NOOP; + MessageConsumer receiver = handler.newStream(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof(), sender); + + receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof()); + + final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) + .routedId(0L) + .streamId(0L) + .sequence(0L) + .acknowledge(0L) + .maximum(BUFFER_SIZE) + .traceId(0L) + .budgetId(0L) + .padding(0) + .build(); + + receiver.accept(window.typeId(), window.buffer(), window.offset(), window.sizeof()); + } + + public static void main( + String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(EchoHandshakeBM.class.getSimpleName()) + .forks(0) + .build(); + + new Runner(opt).run(); + } +} diff --git a/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoWorker.java b/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoWorker.java new file mode 100644 index 0000000000..175b20f3cf --- /dev/null +++ b/runtime/binding-echo/src/test/java/io/aklivity/zilla/runtime/binding/echo/internal/bench/EchoWorker.java @@ -0,0 +1,359 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.echo.internal.bench; + +import java.net.InetAddress; +import java.net.URL; +import java.nio.channels.SelectableChannel; +import java.time.Clock; +import java.util.function.LongSupplier; + +import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.UnsafeBuffer; + +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.binding.BindingHandler; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.binding.function.MessageReader; +import io.aklivity.zilla.runtime.engine.budget.BudgetCreditor; +import io.aklivity.zilla.runtime.engine.budget.BudgetDebitor; +import io.aklivity.zilla.runtime.engine.buffer.BufferPool; +import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; +import io.aklivity.zilla.runtime.engine.concurrent.Signaler; +import io.aklivity.zilla.runtime.engine.config.BindingConfig; +import io.aklivity.zilla.runtime.engine.config.ModelConfig; +import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; +import io.aklivity.zilla.runtime.engine.guard.GuardHandler; +import io.aklivity.zilla.runtime.engine.metrics.Metric; +import io.aklivity.zilla.runtime.engine.model.ConverterHandler; +import io.aklivity.zilla.runtime.engine.model.ValidatorHandler; +import io.aklivity.zilla.runtime.engine.poller.PollerKey; +import io.aklivity.zilla.runtime.engine.vault.VaultHandler; + +public class EchoWorker implements EngineContext +{ + private static final int BUFFER_SIZE = 1024 * 8; + private final MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[BUFFER_SIZE]); + + @Override + public int index() + { + return 0; + } + + @Override + public Signaler signaler() + { + return null; + } + + @Override + public int supplyTypeId( + String name) + { + return 0; + } + + @Override + public long supplyInitialId( + long bindingId) + { + return 0; + } + + @Override + public long supplyReplyId( + long initialId) + { + return 0; + } + + @Override + public long supplyPromiseId( + long initialId) + { + return 0; + } + + @Override + public long supplyAuthorizedId() + { + return 0; + } + + @Override + public long supplyBudgetId() + { + return 0; + } + + @Override + public long supplyTraceId() + { + return 0; + } + + @Override + public MessageConsumer supplySender( + long streamId) + { + return null; + } + + @Override + public MessageConsumer supplyReceiver( + long streamId) + { + return null; + } + + @Override + public EventFormatter supplyEventFormatter() + { + return null; + } + + @Override + public void attachComposite(NamespaceConfig composite) + { + + } + + @Override + public void detachComposite( + NamespaceConfig composite) + { + + } + + @Override + public void detachSender(long replyId) + { + + } + + @Override + public void detachStreams(long bindingId) + { + + } + + @Override + public BudgetCreditor creditor() + { + return null; + } + + @Override + public BudgetDebitor supplyDebitor(long budgetId) + { + return null; + } + + @Override + public MutableDirectBuffer writeBuffer() + { + return writeBuffer; + } + + @Override + public BufferPool bufferPool() + { + return null; + } + + @Override + public LongSupplier supplyCounter( + long bindingId, + long metricId) + { + return null; + } + + @Override + public LongSupplier supplyGauge( + long bindingId, + long metricId) + { + return null; + } + + @Override + public LongSupplier[] supplyHistogram( + long bindingId, + long metricId) + { + return new LongSupplier[0]; + } + + @Override + public MessageConsumer droppedFrameHandler() + { + return null; + } + + @Override + public int supplyClientIndex( + long streamId) + { + return 0; + } + + @Override + public InetAddress[] resolveHost( + String host) + { + return new InetAddress[0]; + } + + @Override + public PollerKey supplyPollerKey( + SelectableChannel channel) + { + return null; + } + + @Override + public long supplyBindingId( + NamespaceConfig namespace, + BindingConfig binding) + { + return 0; + } + + @Override + public String supplyNamespace( + long namespacedId) + { + return ""; + } + + @Override + public String supplyLocalName( + long namespacedId) + { + return ""; + } + + @Override + public String supplyQName( + long namespacedId) + { + return ""; + } + + @Override + public int supplyEventId( + String name) + { + return 0; + } + + @Override + public BindingHandler streamFactory() + { + return null; + } + + @Override + public GuardHandler supplyGuard( + long guardId) + { + return null; + } + + @Override + public VaultHandler supplyVault( + long vaultId) + { + return null; + } + + @Override + public CatalogHandler supplyCatalog( + long catalogId) + { + return null; + } + + @Override + public ValidatorHandler supplyValidator( + ModelConfig config) + { + return null; + } + + @Override + public ConverterHandler supplyReadConverter( + ModelConfig config) + { + return null; + } + + @Override + public ConverterHandler supplyWriteConverter( + ModelConfig config) + { + return null; + } + + @Override + public URL resolvePath( + String path) + { + return null; + } + + @Override + public Metric resolveMetric( + String name) + { + return null; + } + + @Override + public void onExporterAttached( + long exporterId) + { + + } + + @Override + public void onExporterDetached( + long exporterId) + { + + } + + @Override + public MessageConsumer supplyEventWriter() + { + return null; + } + + @Override + public MessageReader supplyEventReader() + { + return null; + } + + @Override + public Clock clock() + { + return null; + } +} diff --git a/runtime/binding-fan/pom.xml b/runtime/binding-fan/pom.xml index 146b79f7a7..472f920a5d 100644 --- a/runtime/binding-fan/pom.xml +++ b/runtime/binding-fan/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-filesystem/pom.xml b/runtime/binding-filesystem/pom.xml index 4325d6eb50..928388bef1 100644 --- a/runtime/binding-filesystem/pom.xml +++ b/runtime/binding-filesystem/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java b/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java index f1da190ac8..b92aad3bee 100644 --- a/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java +++ b/runtime/binding-filesystem/src/main/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerFactory.java @@ -36,6 +36,7 @@ import java.util.function.LongUnaryOperator; import java.util.function.Supplier; +import org.agrona.BitUtil; import org.agrona.DirectBuffer; import org.agrona.MutableDirectBuffer; import org.agrona.collections.Long2ObjectHashMap; @@ -385,9 +386,7 @@ private String calculateTag() { final byte[] readArray = readBuffer.byteArray(); int bytesRead = input.read(readArray, 0, readArray.length); - byte[] content = new byte[bytesRead]; - readBuffer.getBytes(0, content, 0, bytesRead); - newTag = calculateHash(content); + newTag = calculateHash(readArray, 0, Math.max(bytesRead, 0)); } } catch (IOException ex) @@ -412,16 +411,14 @@ private InputStream getInputStream() } private String calculateHash( - byte[] content) + byte[] input, + int offset, + int length) { - - byte[] hash = md5.digest(content); - StringBuilder sb = new StringBuilder(hash.length * 2); - for (byte b: hash) - { - sb.append(String.format("%02x", b)); - } - return sb.toString(); + md5.reset(); + md5.update(input, offset, length); + byte[] hash = md5.digest(); + return BitUtil.toHex(hash); } private void onAppEnd( @@ -631,12 +628,13 @@ private void flushAppData( if (replyWin > 0) { InputStream input = getInputStream(); - boolean replyClosable = input == null; - if (input != null) + try { - try + int available = input != null ? input.available() : 0; + + if (available > 0) { - int reserved = Math.min(replyWin, input.available() + replyPad); + int reserved = Math.min(replyWin, available + replyPad); int length = Math.max(reserved - replyPad, 0); if (length > 0 && replyDebIndex != NO_DEBITOR_INDEX && replyDeb != null) @@ -657,25 +655,25 @@ private void flushAppData( doAppData(traceId, reserved, payload); replyBytes += bytesRead; - replyClosable = replyBytes == attributes.size(); + + if (replyBytes == attributes.size()) + { + input.close(); + input = null; + } } } - if (replyClosable) - { - input.close(); - doAppEnd(traceId); - } } - catch (IOException ex) + + if (available <= 0 || input == null) { - doAppAbort(traceId); + doAppEnd(traceId); } } - else + catch (IOException ex) { - doAppEnd(traceId); + doAppAbort(traceId); } - } } } diff --git a/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java b/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java index f4e4ce46ff..8462fb0975 100644 --- a/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java +++ b/runtime/binding-filesystem/src/test/java/io/aklivity/zilla/runtime/binding/filesystem/internal/stream/FileSystemServerIT.java @@ -72,6 +72,16 @@ public void shouldReadFileExtensionDefault() throws Exception k3po.finish(); } + @Test + @Configuration("server.yaml") + @Specification({ + "${app}/read.file.payload.empty/client", + }) + public void shouldReadFilePayloadEmpty() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.yaml") @Specification({ diff --git a/runtime/binding-grpc-kafka/pom.xml b/runtime/binding-grpc-kafka/pom.xml index f953e4fa1b..3668cf3650 100644 --- a/runtime/binding-grpc-kafka/pom.xml +++ b/runtime/binding-grpc-kafka/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-grpc/pom.xml b/runtime/binding-grpc/pom.xml index 74ada33109..6264b5cbf4 100644 --- a/runtime/binding-grpc/pom.xml +++ b/runtime/binding-grpc/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-http-filesystem/pom.xml b/runtime/binding-http-filesystem/pom.xml index 73c97743f2..07fc55f5a1 100644 --- a/runtime/binding-http-filesystem/pom.xml +++ b/runtime/binding-http-filesystem/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-http-kafka/pom.xml b/runtime/binding-http-kafka/pom.xml index 42ca77af4c..f0b1d07e6c 100644 --- a/runtime/binding-http-kafka/pom.xml +++ b/runtime/binding-http-kafka/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-http/pom.xml b/runtime/binding-http/pom.xml index fb4f00e238..168347bf9c 100644 --- a/runtime/binding-http/pom.xml +++ b/runtime/binding-http/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java index 06e97df87b..18c735874f 100644 --- a/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java +++ b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7230/server/EventIT.java @@ -19,7 +19,6 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; @@ -51,7 +50,6 @@ public class EventIT public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Ignore @Configuration("server.event.yaml") @Specification({ "${net}/request.with.headers/client", diff --git a/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java index 8bf5686dbf..a61817a2ee 100644 --- a/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java +++ b/runtime/binding-http/src/test/java/io/aklivity/zilla/runtime/binding/http/internal/streams/rfc7540/server/EventIT.java @@ -19,7 +19,6 @@ import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.rules.RuleChain.outerRule; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.DisableOnDebug; @@ -51,7 +50,6 @@ public class EventIT public final TestRule chain = outerRule(engine).around(k3po).around(timeout); @Test - @Ignore @Configuration("server.event.yaml") @Specification({ "${net}/connection.headers/client", diff --git a/runtime/binding-kafka-grpc/pom.xml b/runtime/binding-kafka-grpc/pom.xml index d5999cd0f4..d6a274923e 100644 --- a/runtime/binding-kafka-grpc/pom.xml +++ b/runtime/binding-kafka-grpc/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-kafka/pom.xml b/runtime/binding-kafka/pom.xml index 1264e1ac87..898df66436 100644 --- a/runtime/binding-kafka/pom.xml +++ b/runtime/binding-kafka/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaConfiguration.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaConfiguration.java index 6786f38ffc..d8d9bdbb1d 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaConfiguration.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/KafkaConfiguration.java @@ -37,6 +37,7 @@ public class KafkaConfiguration extends Configuration { public static final boolean DEBUG = Boolean.getBoolean("zilla.binding.kafka.debug"); public static final boolean DEBUG_PRODUCE = DEBUG || Boolean.getBoolean("zilla.binding.kafka.debug.produce"); + public static final boolean DEBUG_CONSUMER = DEBUG || Boolean.getBoolean("zilla.binding.kafka.debug.consumer"); public static final String KAFKA_CLIENT_ID_DEFAULT = "zilla"; diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaCacheServerConsumerFactory.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaCacheServerConsumerFactory.java index 516e5a4363..bb720677b1 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaCacheServerConsumerFactory.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaCacheServerConsumerFactory.java @@ -17,7 +17,9 @@ import java.util.ArrayDeque; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.LongFunction; import java.util.function.LongUnaryOperator; @@ -26,6 +28,7 @@ import org.agrona.MutableDirectBuffer; import org.agrona.collections.IntHashSet; import org.agrona.collections.Object2ObjectHashMap; +import org.agrona.collections.ObjectHashSet; import org.agrona.concurrent.UnsafeBuffer; import io.aklivity.zilla.runtime.binding.kafka.internal.KafkaBinding; @@ -533,7 +536,8 @@ final class KafkaCacheServerConsumerFanout private final long routedId; private final long authorization; private final ArrayList streams; - private final Object2ObjectHashMap members; + private final Map members; + private final ObjectHashSet memberIds; private final Object2ObjectHashMap partitionsByTopic; private final Object2ObjectHashMap> consumers; private final Object2ObjectHashMap assignments; @@ -578,7 +582,8 @@ private KafkaCacheServerConsumerFanout( this.groupId = groupId; this.timeout = timeout; this.streams = new ArrayList<>(); - this.members = new Object2ObjectHashMap<>(); + this.memberIds = new ObjectHashSet<>(); + this.members = new LinkedHashMap<>(); this.partitionsByTopic = new Object2ObjectHashMap<>(); this.consumers = new Object2ObjectHashMap<>(); this.assignments = new Object2ObjectHashMap<>(); @@ -590,8 +595,6 @@ private void onConsumerFanoutStreamOpening( { streams.add(stream); - assert !streams.isEmpty(); - doConsumerInitialBegin(traceId, stream); if (KafkaState.initialOpened(state)) @@ -886,7 +889,7 @@ private void onConsumerReplyFlush( memberId = kafkaGroupFlushEx.memberId().asString(); partitionsByTopic.clear(); - members.clear(); + memberIds.clear(); kafkaGroupFlushEx.members().forEach(m -> { @@ -896,7 +899,8 @@ private void onConsumerReplyFlush( final String consumerId = kafkaGroupMemberMetadataRO.consumerId().asString(); final String mId = m.id().asString(); - members.put(mId, consumerId); + members.putIfAbsent(mId, consumerId); + memberIds.add(mId); groupMetadata.topics().forEach(mt -> { @@ -907,6 +911,8 @@ private void onConsumerReplyFlush( }); } + members.entrySet().removeIf(m -> !memberIds.contains(m.getKey())); + doPartitionAssignment(traceId, authorization); } @@ -941,6 +947,12 @@ private void onConsumerReplyData( IntHashSet partitions = new IntHashSet(); List topicConsumers = new ArrayList<>(); + if (KafkaConfiguration.DEBUG_CONSUMER) + { + System.out.printf("Subscription: MemberId - %s\n", memberId); + ta.partitions().forEach(np -> System.out.printf("%s\n", np)); + } + stream.doConsumerReplyData(traceId, flags, replyPad, EMPTY_OCTETS, ex -> ex.set((b, o, l) -> kafkaDataExRW.wrap(b, o, l) .typeId(kafkaTypeId) @@ -1089,7 +1101,6 @@ private void doMemberAssigment( .wrap(writeBuffer, DataFW.FIELD_OFFSET_PAYLOAD, writeBuffer.capacity()); this.consumers.forEach((k, v) -> - { assignmentBuilder.item(ma -> ma .memberId(k) .assignments(ta -> v.forEach(tp -> ta.item(i -> i @@ -1101,12 +1112,19 @@ private void doMemberAssigment( u.item(ud -> ud .consumerId(at.consumerId) .partitions(pt -> at.partitions.forEach(up -> - pt.item(pi -> pi.partitionId(up)))))))) - )))); - }); + pt.item(pi -> pi.partitionId(up))))))))))))); Array32FW assignment = assignmentBuilder.build(); + if (KafkaConfiguration.DEBUG_CONSUMER) + { + assignment.forEach(c -> + { + System.out.printf("Assignment: MemberId - %s\n", c.memberId()); + c.assignments().forEach(a -> a.partitions().forEach(System.out::println)); + }); + } + doConsumerInitialData(traceId, authorization, initialBud, assignment.sizeof(), 3, assignment.buffer(), assignment.offset(), assignment.sizeof(), EMPTY_OCTETS); } diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientOffsetFetchFactory.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientOffsetFetchFactory.java index d5897f2cc2..f68c1fa26d 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientOffsetFetchFactory.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientOffsetFetchFactory.java @@ -57,6 +57,7 @@ import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.KafkaBeginExFW; import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.KafkaDataExFW; import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.KafkaOffsetFetchBeginExFW; +import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.KafkaOffsetFetchDataExFW; import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.KafkaResetExFW; import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.ProxyBeginExFW; import io.aklivity.zilla.runtime.binding.kafka.internal.types.stream.ResetFW; @@ -711,6 +712,8 @@ private int decodeOffsetFetchError( client.decodeableResponseBytes -= error.sizeof(); assert client.decodeableResponseBytes >= 0; + client.onDecodeEmptyOffsetFetchResponse(traceId); + client.decoder = decodeOffsetFetchResponse; client.nextResponseId++; } @@ -1729,6 +1732,20 @@ private void onDecodeOffsetFetchResponse( } } + private void onDecodeEmptyOffsetFetchResponse( + long traceId) + { + if (topicPartitions.isEmpty()) + { + final KafkaDataExFW kafkaDataEx = kafkaDataExRW.wrap(extBuffer, 0, extBuffer.capacity()) + .typeId(kafkaTypeId) + .offsetFetch(KafkaOffsetFetchDataExFW.Builder::build) + .build(); + + delegate.doApplicationData(traceId, authorization, kafkaDataEx); + } + } + public void onDecodeTopic( long traceId) { diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientProduceFactory.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientProduceFactory.java index 385209cc6d..70c89311fc 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientProduceFactory.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaClientProduceFactory.java @@ -159,7 +159,7 @@ public final class KafkaClientProduceFactory extends KafkaClientSaslHandshaker i private final KafkaProduceClientFlusher flushRecord = this::flushRecord; private final KafkaProduceClientFlusher flushRecordInit = this::flushRecordInit; - private final KafkaProduceClientFlusher frameProduceRecordContFin = this::flushRecordContFin; + private final KafkaProduceClientFlusher flushRecordContFin = this::flushRecordContFin; private final KafkaProduceClientFlusher flushRecordIgnoreAll = this::flushRecordIgnoreAll; private final KafkaProduceClientDecoder decodeSaslHandshakeResponse = this::decodeSaslHandshakeResponse; @@ -546,10 +546,9 @@ private int flushRecordInit( final KafkaAckMode ackMode = kafkaProduceDataEx.ackMode().get(); final KafkaKeyFW key = kafkaProduceDataEx.key(); final Array32FW headers = kafkaProduceDataEx.headers(); - client.encodeableRecordBytesDeferred = kafkaProduceDataEx.deferred(); - client.valueChecksum = kafkaProduceDataEx.crc32c(); + final int deferred = kafkaProduceDataEx.deferred(); final int valueSize = payload != null ? payload.sizeof() : 0; - client.valueCompleteSize = valueSize + client.encodeableRecordBytesDeferred; + final int valueCompleteSize = valueSize + deferred; final int maxEncodeableBytes = client.encodeSlotLimit + client.valueCompleteSize + produceRecordFramingSize; @@ -562,6 +561,10 @@ private int flushRecordInit( client.doEncodeRequestIfNecessary(traceId, budgetId); } + client.valueChecksum = kafkaProduceDataEx.crc32c(); + client.encodeableRecordBytesDeferred = deferred; + client.valueCompleteSize = valueCompleteSize; + if (client.producerId == RECORD_BATCH_PRODUCER_ID_NONE) { client.baseSequence = sequence; @@ -574,8 +577,7 @@ private int flushRecordInit( client.doEncodeRecordInit(traceId, timestamp, ackMode, key, payload, headers); if (client.encodeSlot != NO_SLOT) { - client.flusher = frameProduceRecordContFin; - client.flushFlags = FLAGS_INIT; + client.flusher = flushRecordContFin; } else { @@ -610,6 +612,7 @@ private int flushRecordContFin( assert progress == limit; client.flusher = flushRecord; client.flushFlags = FLAGS_FIN; + client.encodeableRecordBytesDeferred = 0; } return progress; @@ -1967,7 +1970,7 @@ private void doEncodeProduceRequest( final ByteBuffer encodeSlotByteBuffer = encodePool.byteBuffer(encodeSlot); final int encodeSlotBytePosition = encodeSlotByteBuffer.position(); - final int partialValueSize = flushFlags != FLAGS_FIN ? encodeableRecordValueBytes : 0; + final int partialValueSize = encodeableRecordBytesDeferred > 0 ? encodeableRecordValueBytes : 0; encodeSlotByteBuffer.limit(encodeSlotBytePosition + encodeSlotLimit - partialValueSize); encodeSlotByteBuffer.position(encodeSlotBytePosition + encodeSlotOffset + crcLimit); @@ -1976,7 +1979,7 @@ private void doEncodeProduceRequest( crc.update(encodeSlotByteBuffer); long checksum = crc.getValue(); - if (flushFlags != FLAGS_FIN) + if (encodeableRecordBytesDeferred > 0) { checksum = computeChecksum(encodeBuffer, encodeLimit, encodeProgress, encodeSlotBuffer, checksum); } diff --git a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaMergedFactory.java b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaMergedFactory.java index 54b8a7892b..9280cfef77 100644 --- a/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaMergedFactory.java +++ b/runtime/binding-kafka/src/main/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/KafkaMergedFactory.java @@ -1341,7 +1341,7 @@ private void onMergedInitialAbort( describeStream.doDescribeInitialAbortIfNecessary(traceId); metaStream.doMetaInitialAbortIfNecessary(traceId); fetchStreams.forEach(f -> f.onMergedInitialAbort(traceId)); - produceStreams.forEach(f -> f.doProduceInitialEndIfNecessary(traceId)); + produceStreams.forEach(f -> f.doProduceInitialAbortIfNecessary(traceId)); if (consumerStream != null) { @@ -2010,6 +2010,8 @@ private void onTopicOffsetFetchDataChanged( long traceId, Array32FW partitions) { + offsetsByPartitionId.clear(); + partitions.forEach(p -> offsetsByPartitionId.put(p.partitionId(), new KafkaPartitionOffset( topic, @@ -2020,6 +2022,17 @@ private void onTopicOffsetFetchDataChanged( p.metadata().asString()))); doFetchPartitionsIfNecessary(traceId); + + fetchStreams.removeIf(f -> + { + boolean missing = !leadersByAssignedId.containsKey(f.partitionId); + if (missing) + { + f.doFetchInitialEndIfNecessary(traceId); + f.doFetchReplyResetIfNecessary(traceId); + } + return missing; + }); } private void doFetchPartitionOffsets( @@ -2027,6 +2040,7 @@ private void doFetchPartitionOffsets( { if (hasFetchCapability(capabilities)) { + offsetFetchStream.resetStreamIfNecessary(traceId); offsetFetchStream.doOffsetFetchInitialBeginIfNecessary(traceId); } } @@ -3190,7 +3204,7 @@ private KafkaUnmergedOffsetFetchStream( private void doOffsetFetchInitialBeginIfNecessary( long traceId) { - if (!KafkaState.initialOpening(state)) + if (!KafkaState.initialOpening(state) || KafkaState.closed(state)) { doOffsetFetchInitialBegin(traceId); } @@ -3199,6 +3213,11 @@ private void doOffsetFetchInitialBeginIfNecessary( private void doOffsetFetchInitialBegin( long traceId) { + if (KafkaState.closed(state)) + { + state = 0; + } + assert state == 0; state = KafkaState.openingInitial(state); @@ -3332,7 +3351,8 @@ private void onOffsetFetchReplyData( final Array32FW partitions = kafkaOffsetFetchDataEx.partitions(); merged.onTopicOffsetFetchDataChanged(traceId, partitions); - doOffsetFetchReplyWindow(traceId, 0, replyMax); + doOffsetFetchInitialEndIfNecessary(traceId); + doOffsetFetchReplyResetIfNecessary(traceId); } } @@ -3424,6 +3444,16 @@ private void doOffsetFetchReplyReset( doReset(receiver, merged.routedId, merged.resolvedId, replyId, replySeq, replyAck, replyMax, traceId, merged.authorization, EMPTY_EXTENSION); } + + private void resetStreamIfNecessary( + long traceId) + { + if (KafkaState.initialOpening(state)) + { + doOffsetFetchInitialAbortIfNecessary(traceId); + doOffsetFetchReplyResetIfNecessary(traceId); + } + } } private final class KafkaUnmergedFetchStream diff --git a/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/cache/KafkaCachePartitionTest.java b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/cache/KafkaCachePartitionTest.java index 0347028b1c..9c7cf45248 100644 --- a/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/cache/KafkaCachePartitionTest.java +++ b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/cache/KafkaCachePartitionTest.java @@ -236,8 +236,6 @@ public void shouldCleanSegment() throws Exception partition.writeEntry(null, 1L, 1L, 12L, entryMark, valueMark, 0L, -1L, key, headers, value, ancestor, 0x00, KafkaDeltaType.NONE, ConverterHandler.NONE, ConverterHandler.NONE, false); - partition.writeEntry(null, 1L, 1L, 12L, entryMark, valueMark, 0L, -1L, - key, headers, value, ancestor, 0x00, KafkaDeltaType.NONE, null, null, false); Node head15 = partition.append(15L); KafkaCacheSegment head15s = head15.segment(); diff --git a/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/CacheMergedIT.java b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/CacheMergedIT.java index 008850670d..05fda6b413 100644 --- a/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/CacheMergedIT.java +++ b/runtime/binding-kafka/src/test/java/io/aklivity/zilla/runtime/binding/kafka/internal/stream/CacheMergedIT.java @@ -713,4 +713,24 @@ public void shouldAckMessageOffset() throws Exception { k3po.finish(); } + + @Test + @Configuration("cache.options.merged.yaml") + @Specification({ + "${app}/merged.fetch.unsubscribe/client", + "${app}/unmerged.group.fetch.unsubscribe/server"}) + public void shouldUnsubscribeOnPartitionReassignment() throws Exception + { + k3po.finish(); + } + + @Test + @Configuration("cache.options.merged.yaml") + @Specification({ + "${app}/merged.fetch.unsubscribe/client", + "${app}unmerged.group.fetch.assignment.incomplete/server"}) + public void shouldCancelPreviousIncompleteOffsetFetchRequest() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/binding-mqtt-kafka/pom.xml b/runtime/binding-mqtt-kafka/pom.xml index f6e06bedae..bec6d7d5f7 100644 --- a/runtime/binding-mqtt-kafka/pom.xml +++ b/runtime/binding-mqtt-kafka/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/config/MqttKafkaRouteConfig.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/config/MqttKafkaRouteConfig.java index ed1d8ada79..99151c0580 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/config/MqttKafkaRouteConfig.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/config/MqttKafkaRouteConfig.java @@ -27,14 +27,14 @@ public class MqttKafkaRouteConfig { - private final Optional with; + + public final MqttKafkaWithResolver with; private final List when; private final LongPredicate authorized; public final long id; public final long order; - public final String16FW messages; public final String16FW retained; public MqttKafkaRouteConfig( @@ -45,12 +45,13 @@ public MqttKafkaRouteConfig( this.order = route.order; this.with = Optional.ofNullable(route.with) .map(MqttKafkaWithConfig.class::cast) - .map(c -> new MqttKafkaWithResolver(options, c)); - this.messages = with.isPresent() ? with.get().messages() : options.topics.messages; + .map(c -> new MqttKafkaWithResolver(options, c)) + .orElse(new MqttKafkaWithResolver(options, null)); this.retained = options.topics.retained; this.when = route.when.stream() .map(MqttKafkaConditionConfig.class::cast) .map(MqttKafkaConditionMatcher::new) + .peek(m -> m.observe(with::onConditionMatched)) .collect(toList()); this.authorized = route.authorized; } diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfiguration.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfiguration.java index 945170aded..2b88be4f92 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfiguration.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfiguration.java @@ -25,6 +25,7 @@ import org.agrona.LangUtil; +import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttQoS; import io.aklivity.zilla.runtime.engine.Configuration; public class MqttKafkaConfiguration extends Configuration @@ -39,6 +40,7 @@ public class MqttKafkaConfiguration extends Configuration public static final IntPropertyDef WILL_STREAM_RECONNECT_DELAY; public static final BooleanPropertyDef BOOTSTRAP_AVAILABLE; public static final IntPropertyDef BOOTSTRAP_STREAM_RECONNECT_DELAY; + public static final IntPropertyDef PUBLISH_QOS_MAX; static { @@ -57,6 +59,7 @@ public class MqttKafkaConfiguration extends Configuration WILL_STREAM_RECONNECT_DELAY = config.property("will.stream.reconnect", 2); BOOTSTRAP_AVAILABLE = config.property("bootstrap.available", true); BOOTSTRAP_STREAM_RECONNECT_DELAY = config.property("bootstrap.stream.reconnect", 2); + PUBLISH_QOS_MAX = config.property("publish.qos.max", 2); MQTT_KAFKA_CONFIG = config; } @@ -116,6 +119,11 @@ public int bootstrapStreamReconnectDelay() return BOOTSTRAP_STREAM_RECONNECT_DELAY.getAsInt(this); } + public MqttQoS publishQosMax() + { + return MqttQoS.valueOf(PUBLISH_QOS_MAX.getAsInt(this)); + } + private static StringSupplier decodeStringSupplier( String fullyQualifiedMethodName) diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaBindingConfig.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaBindingConfig.java index a152f8f2d0..855ee3fdd1 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaBindingConfig.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaBindingConfig.java @@ -29,6 +29,7 @@ import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaRouteConfig; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.stream.MqttKafkaSessionFactory; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.Array32FW; +import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttQoS; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttTopicFilterFW; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.String16FW; import io.aklivity.zilla.runtime.engine.config.BindingConfig; @@ -95,6 +96,12 @@ public List resolveAll( .collect(Collectors.toList()); } + public MqttQoS publishQosMax() + { + return routes.stream().noneMatch(r -> r.with != null && r.with.containsParams()) ? + MqttQoS.EXACTLY_ONCE : MqttQoS.AT_LEAST_ONCE; + } + public String16FW messagesTopic() { return options.topics.messages; diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaConditionMatcher.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaConditionMatcher.java index 866ebdc322..7d1af3446c 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaConditionMatcher.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaConditionMatcher.java @@ -16,6 +16,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -24,34 +25,45 @@ public class MqttKafkaConditionMatcher { - private final List matchers; + private final Matcher matcher; public final MqttKafkaConditionKind kind; + private Consumer observer; public MqttKafkaConditionMatcher( MqttKafkaConditionConfig condition) { - this.matchers = asTopicMatchers(condition.topics); + this.matcher = asTopicMatcher(condition.topics); this.kind = condition.kind; } public boolean matches( String topic) { - boolean match = false; - if (matchers != null) + return this.matcher == null || + this.matcher.reset(topic).matches() && observeMatched(); + } + + public String parameter( + String name) + { + return matcher.group(name); + } + + public void observe( + Consumer observer) + { + this.observer = observer; + } + + private boolean observeMatched() + { + if (observer != null) { - for (Matcher matcher : matchers) - { - if (matcher.reset(topic).matches()) - { - match = true; - break; - } - } + observer.accept(this); } - return match; - } + return true; + } private static List asTopicMatchers( List wildcards) @@ -62,11 +74,37 @@ private static List asTopicMatchers( String patternBegin = wildcard.startsWith("/") ? "(" : "^(?!\\/)("; String fixedPattern = patternBegin + asRegexPattern(wildcard, 0, true) + ")?\\/?\\#?"; String nonFixedPattern = patternBegin + asRegexPattern(wildcard, 0, false) + ")?\\/?\\#"; + fixedPattern = fixedPattern.replaceAll("\\{([a-zA-Z_]+)\\}", "(?<$1>.+)"); + nonFixedPattern = nonFixedPattern.replaceAll("\\{([a-zA-Z_]+)\\}", ""); matchers.add(Pattern.compile(nonFixedPattern + "|" + fixedPattern).matcher("")); } return matchers; } + private static Matcher asTopicMatcher( + List wildcards) + { + StringBuilder combinedRegex = new StringBuilder(); + + for (String wildcard : wildcards) + { + String patternBegin = wildcard.startsWith("/") ? "(" : "^(?!\\/)("; + String fixedPattern = patternBegin + asRegexPattern(wildcard, 0, true) + ")?\\/?\\#?"; + String nonFixedPattern = patternBegin + asRegexPattern(wildcard, 0, false) + ")?\\/?\\#"; + fixedPattern = fixedPattern.replaceAll("\\{([a-zA-Z_]+)\\}", "(?<$1>.+)"); + nonFixedPattern = nonFixedPattern.replaceAll("\\{([a-zA-Z_]+)\\}", ""); + + combinedRegex.append(nonFixedPattern).append("|").append(fixedPattern).append("|"); + } + + if (combinedRegex.length() > 0) + { + combinedRegex.deleteCharAt(combinedRegex.length() - 1); + } + + return Pattern.compile(combinedRegex.toString()).matcher(""); + } + private static String asRegexPattern( String wildcard, int level, @@ -93,6 +131,7 @@ private static String asRegexPattern( .replace(".", "\\.") .replace("$", "\\$") .replace("+", "[^/]*") + .replace("\\{[^}]+\\}", "[^/]*") .replace("#", ".*"); pattern = (level > 0) ? "(\\/\\+|\\/" + currentPart + ")" : "(\\+|" + currentPart + ")"; } diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithResolver.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithResolver.java index d0ca895a2c..69c4fe4863 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithResolver.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/config/MqttKafkaWithResolver.java @@ -14,6 +14,10 @@ */ package io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.config; +import java.util.function.Function; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaOptionsConfig; import io.aklivity.zilla.runtime.binding.mqtt.kafka.config.MqttKafkaWithConfig; @@ -21,17 +25,51 @@ public class MqttKafkaWithResolver { - private final String16FW messages; + private static final Pattern PARAMS_PATTERN = Pattern.compile("\\$\\{params\\.([a-zA-Z_]+)\\}"); + + private final Matcher paramsMatcher; + private final MqttKafkaWithConfig with; + private final MqttKafkaOptionsConfig options; + + private Function replacer = r -> null; public MqttKafkaWithResolver( MqttKafkaOptionsConfig options, MqttKafkaWithConfig with) { - this.messages = with.messages == null ? options.topics.messages : new String16FW(with.messages); + this.paramsMatcher = PARAMS_PATTERN.matcher(""); + this.with = with; + this.options = options; + } + + public void onConditionMatched( + MqttKafkaConditionMatcher condition) + { + this.replacer = r -> condition.parameter(r.group(1)); } - public String16FW messages() + public boolean containsParams() { - return messages; + return with != null && paramsMatcher.reset(with.messages).find(); + } + + public String16FW resolveMessages() + { + String topic = null; + if (with != null) + { + topic = with.messages; + Matcher topicMatcher = paramsMatcher.reset(topic); + StringBuilder result = new StringBuilder(); + while (topicMatcher.find()) + { + String replacement = replacer.apply(paramsMatcher.toMatchResult()); + topicMatcher.appendReplacement(result, replacement); + } + topicMatcher.appendTail(result); + + topic = result.toString(); + } + return topic == null ? options.topics.messages : new String16FW(topic); } } diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishFactory.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishFactory.java index 2554a12fe6..0ef4c014a0 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishFactory.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishFactory.java @@ -207,11 +207,17 @@ public MessageConsumer newStream( binding.resolve(authorization, mqttPublishBeginEx.topic().asString()) : null; MessageConsumer newStream = null; - if (resolved != null) + final int qos = mqttPublishBeginEx.qos(); + final int qosMax = binding.publishQosMax().value(); + + if (mqttPublishBeginEx.qos() > qosMax) + { + return null; + } + else if (resolved != null) { final long resolvedId = resolved.id; - final String16FW messagesTopic = resolved.messages; - final int qos = mqttPublishBeginEx.qos(); + final String16FW messagesTopic = resolved.with.resolveMessages(); final MqttPublishProxy proxy = new MqttPublishProxy(mqtt, originId, routedId, initialId, resolvedId, affinity, binding, messagesTopic, binding.retainedTopic(), qos, binding.clients); newStream = proxy::onMqttMessage; diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishMetadata.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishMetadata.java index 30bd6d28ef..da188b6d2d 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishMetadata.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishMetadata.java @@ -93,12 +93,14 @@ public static final class KafkaOffsetMetadata public final IntArrayList packetIds; public long sequence; + public String topic; KafkaOffsetMetadata( + String topic, long producerId, short producerEpoch) { - this(producerId, producerEpoch, new IntArrayList()); + this(topic, producerId, producerEpoch, new IntArrayList()); } KafkaOffsetMetadata( @@ -111,6 +113,19 @@ public static final class KafkaOffsetMetadata this.producerEpoch = producerEpoch; this.packetIds = packetIds; } + + KafkaOffsetMetadata( + String topic, + long producerId, + short producerEpoch, + IntArrayList packetIds) + { + this.sequence = 1; + this.topic = topic.intern(); + this.producerId = producerId; + this.producerEpoch = producerEpoch; + this.packetIds = packetIds; + } } public static final class KafkaOffsetMetadataHelper diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSessionFactory.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSessionFactory.java index 04d48c1d68..ee699398fc 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSessionFactory.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSessionFactory.java @@ -72,6 +72,7 @@ import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttPayloadFormat; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttPayloadFormatFW; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttPublishFlags; +import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttQoS; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttSessionFlags; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttSessionSignalFW; import io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.types.MqttSessionStateFW; @@ -262,6 +263,7 @@ public class MqttKafkaSessionFactory implements MqttKafkaStreamFactory private final Int2ObjectHashMap qosLevels; private final Long2ObjectHashMap clientMetadata; private final KafkaOffsetMetadataHelper offsetMetadataHelper; + private final MqttQoS publishQosMax; private String serverRef; private int reconnectAttempt; @@ -303,6 +305,7 @@ public MqttKafkaSessionFactory( this.sessionExpiryIds = new Object2LongHashMap<>(-1); this.instanceId = instanceId; this.reconnectDelay = config.willStreamReconnectDelay(); + this.publishQosMax = config.publishQosMax(); this.qosLevels = new Int2ObjectHashMap<>(); this.qosLevels.put(0, new String16FW("0")); this.qosLevels.put(1, new String16FW("1")); @@ -336,8 +339,10 @@ public MessageConsumer newStream( { final long resolvedId = resolved.id; final String16FW sessionTopic = binding.sessionsTopic(); + + final MqttQoS publishQosMax = MqttQoS.valueOf(Math.min(binding.publishQosMax().value(), this.publishQosMax.value())); final MqttSessionProxy proxy = new MqttSessionProxy(mqtt, originId, routedId, initialId, resolvedId, - binding.id, sessionTopic); + binding.id, sessionTopic, publishQosMax); newStream = proxy::onMqttMessage; } @@ -391,8 +396,8 @@ private final class MqttSessionProxy private final List offsetFetches; private final List initializablePartitions; private final Long2LongHashMap leaderEpochs; - private final IntArrayQueue unackedPacketIds; + private IntArrayQueue unackedPacketIds; private String lifetimeId; private KafkaSessionStream session; private KafkaGroupStream group; @@ -424,11 +429,12 @@ private final class MqttSessionProxy private String willId; private int delay; private boolean redirect; - private int publishQosMax; + private int publishQosMax = -1; private int unfetchedKafkaTopics; private MqttKafkaPublishMetadata metadata; - private final Set messagesTopics; private final String16FW retainedTopic; + + private Set messagesTopics; private long producerId; private short producerEpoch; @@ -439,7 +445,8 @@ private MqttSessionProxy( long initialId, long resolvedId, long bindingId, - String16FW sessionsTopic) + String16FW sessionsTopic, + MqttQoS publishQosMax) { this.mqtt = mqtt; this.originId = originId; @@ -457,10 +464,14 @@ private MqttSessionProxy( final MqttKafkaBindingConfig binding = supplyBinding.apply(bindingId); final String16FW messagesTopic = binding.messagesTopic(); this.retainedTopic = binding.retainedTopic(); - this.messagesTopics = binding.routes.stream().map(r -> r.messages).collect(Collectors.toSet()); - this.messagesTopics.add(messagesTopic); - this.unfetchedKafkaTopics = messagesTopics.size() + 1; - this.unackedPacketIds = new IntArrayQueue(); + this.publishQosMax = publishQosMax.value(); + if (publishQosMax == MqttQoS.EXACTLY_ONCE) + { + this.messagesTopics = binding.routes.stream().map(r -> r.with.resolveMessages()).collect(Collectors.toSet()); + this.messagesTopics.add(messagesTopic); + this.unfetchedKafkaTopics = messagesTopics.size() + 1; + this.unackedPacketIds = new IntArrayQueue(); + } } private void onMqttMessage( @@ -534,7 +545,7 @@ private void onMqttBegin( sessionExpiryMillis = (int) SECONDS.toMillis(mqttSessionBeginEx.expiry()); sessionFlags = mqttSessionBeginEx.flags(); redirect = hasRedirectCapability(mqttSessionBeginEx.capabilities()); - publishQosMax = mqttSessionBeginEx.publishQosMax(); + publishQosMax = publishQosMax == -1 ? mqttSessionBeginEx.publishQosMax() : publishQosMax; if (!isSetWillFlag(sessionFlags) || isSetCleanStart(sessionFlags)) { @@ -1137,6 +1148,7 @@ private void onSessionBegin( .flags(sessionFlags) .expiry((int) TimeUnit.MILLISECONDS.toSeconds(sessionExpiryMillis)) .subscribeQosMax(MQTT_KAFKA_MAX_QOS) + .publishQosMax(publishQosMax) .capabilities(MQTT_KAFKA_CAPABILITIES) .clientId(clientId)) .build(); @@ -1199,7 +1211,7 @@ private void onOffsetFetched( Array32FW partitions, KafkaOffsetFetchStream kafkaOffsetFetchStream) { - boolean initProducer = !partitions.anyMatch(p -> p.metadata().length() > 0); + boolean initProducer = isSetCleanStart(sessionFlags) || !partitions.anyMatch(p -> p.metadata().length() > 0); partitions.forEach(partition -> { @@ -1290,7 +1302,7 @@ private void onOffsetCommitOpened( initializablePartitions.forEach(kp -> { final long partitionKey = partitionKey(kp.topic, kp.partitionId); - final KafkaOffsetMetadata metadata = new KafkaOffsetMetadata(producerId, producerEpoch); + final KafkaOffsetMetadata metadata = new KafkaOffsetMetadata(kp.topic, producerId, producerEpoch); this.metadata.offsets.put(partitionKey, metadata); Flyweight initialOffsetCommit = kafkaDataExRW .wrap(extBuffer, 0, extBuffer.capacity()) @@ -1431,7 +1443,7 @@ private void doCreateSessionStream( .flags(sessionFlags) .expiry((int) TimeUnit.MILLISECONDS.toSeconds(sessionExpiryMillis)) .subscribeQosMax(MQTT_KAFKA_MAX_QOS) - .publishQosMax(MQTT_KAFKA_MAX_QOS) + .publishQosMax(publishQosMax) .capabilities(MQTT_KAFKA_CAPABILITIES) .clientId(clientId); @@ -2914,6 +2926,7 @@ private void onKafkaBegin( .flags(delegate.sessionFlags) .expiry((int) TimeUnit.MILLISECONDS.toSeconds(delegate.sessionExpiryMillis)) .subscribeQosMax(MQTT_KAFKA_MAX_QOS) + .publishQosMax(delegate.publishQosMax) .capabilities(MQTT_KAFKA_CAPABILITIES) .clientId(delegate.clientId)) .build(); diff --git a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeFactory.java b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeFactory.java index 852a720d26..ebbfc1d362 100644 --- a/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeFactory.java +++ b/runtime/binding-mqtt-kafka/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeFactory.java @@ -855,7 +855,7 @@ private KafkaMessagesBootstrap( { this.originId = originId; this.routedId = route.id; - this.topic = route.messages; + this.topic = route.with.resolveMessages(); this.serverRef = serverRef; this.initialId = supplyInitialId.applyAsLong(routedId); this.replyId = supplyReplyId.applyAsLong(initialId); @@ -1118,7 +1118,7 @@ private KafkaMessagesProxy( { this.originId = originId; this.routedId = route.id; - this.topic = route.messages; + this.topic = route.with.resolveMessages(); this.topicKey = System.identityHashCode(topic.asString().intern()); this.routeConfig = route; this.mqtt = mqtt; @@ -2072,7 +2072,7 @@ private void onKafkaData( if (((filters >> i) & 1) == 1) { long subscriptionId = mqtt.retainedSubscriptionIds.get(i); - if (mqtt.retainAsPublished.getOrDefault(subscriptionId, false)) + if (mqtt.retainAsPublished.getOrDefault(subscriptionId, Boolean.FALSE)) { flag |= RETAIN_FLAG; } diff --git a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfigurationTest.java b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfigurationTest.java index fccc240c61..fc272acd19 100644 --- a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfigurationTest.java +++ b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/MqttKafkaConfigurationTest.java @@ -19,6 +19,7 @@ import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.BOOTSTRAP_STREAM_RECONNECT_DELAY; import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.INSTANCE_ID; import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.LIFETIME_ID; +import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.PUBLISH_QOS_MAX; import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.SESSION_ID; import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.TIME; import static io.aklivity.zilla.runtime.binding.mqtt.kafka.internal.MqttKafkaConfiguration.WILL_AVAILABLE; @@ -35,7 +36,7 @@ public class MqttKafkaConfigurationTest public static final String WILL_STREAM_RECONNECT_DELAY_NAME = "zilla.binding.mqtt.kafka.will.stream.reconnect"; public static final String BOOTSTRAP_AVAILABLE_NAME = "zilla.binding.mqtt.kafka.bootstrap.available"; public static final String BOOTSTRAP_STREAM_RECONNECT_DELAY_NAME = "zilla.binding.mqtt.kafka.bootstrap.stream.reconnect"; - public static final String PUBLISH_MAX_QOS_NAME = "zilla.binding.mqtt.kafka.publish.max.qos"; + public static final String PUBLISH_MAX_QOS_NAME = "zilla.binding.mqtt.kafka.publish.qos.max"; public static final String SESSION_ID_NAME = "zilla.binding.mqtt.kafka.session.id"; public static final String WILL_ID_NAME = "zilla.binding.mqtt.kafka.will.id"; public static final String LIFETIME_ID_NAME = "zilla.binding.mqtt.kafka.lifetime.id"; @@ -53,5 +54,6 @@ public void shouldVerifyConstants() assertEquals(WILL_ID.name(), WILL_ID_NAME); assertEquals(LIFETIME_ID.name(), LIFETIME_ID_NAME); assertEquals(INSTANCE_ID.name(), INSTANCE_ID_NAME); + assertEquals(PUBLISH_QOS_MAX.name(), PUBLISH_MAX_QOS_NAME); } } diff --git a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishProxyIT.java b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishProxyIT.java index 6e169835a7..d7e6a61c2a 100644 --- a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishProxyIT.java +++ b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaPublishProxyIT.java @@ -168,6 +168,17 @@ public void shouldSendOneMessageWithChangedTopicName() throws Exception k3po.finish(); } + @Test + @Configuration("proxy.when.publish.topic.with.messages.params.yaml") + @Configure(name = WILL_AVAILABLE_NAME, value = "false") + @Specification({ + "${mqtt}/publish.one.message/client", + "${kafka}/publish.one.message.resolve.topic.params/server"}) + public void shouldSendOneMessageWithResolvingParams() throws Exception + { + k3po.finish(); + } + @Test @Configuration("proxy.when.publish.topic.with.messages.yaml") @Configure(name = WILL_AVAILABLE_NAME, value = "false") @@ -179,6 +190,28 @@ public void shouldSendUsingTopicSpace() throws Exception k3po.finish(); } + @Test + @Configuration("proxy.when.publish.topic.with.messages.params.yaml") + @Configure(name = WILL_AVAILABLE_NAME, value = "false") + @Specification({ + "${mqtt}/publish.topic.space.with.params/client", + "${kafka}/publish.topic.space.with.params/server"}) + public void shouldSendUsingTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + + @Test + @Configuration("proxy.when.publish.topic.with.messages.params.yaml") + @Configure(name = WILL_AVAILABLE_NAME, value = "false") + @Specification({ + "${mqtt}/publish.reject.qos2/client", + "${kafka}/publish.reject.qos2/server"}) + public void shouldRejectPublishWhenTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + @Test @Configuration("proxy.when.client.topic.space.yaml") @Configure(name = WILL_AVAILABLE_NAME, value = "false") diff --git a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeProxyIT.java b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeProxyIT.java index 62e2ac00fc..e109973413 100644 --- a/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeProxyIT.java +++ b/runtime/binding-mqtt-kafka/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/kafka/internal/stream/MqttKafkaSubscribeProxyIT.java @@ -174,6 +174,17 @@ public void shouldReceiveOneMessageWithChangedTopicName() throws Exception k3po.finish(); } + @Test + @Configuration("proxy.when.subscribe.topic.with.messages.params.yaml") + @Configure(name = WILL_AVAILABLE_NAME, value = "false") + @Specification({ + "${mqtt}/subscribe.one.message/client", + "${kafka}/subscribe.one.message.resolve.topic.params/server"}) + public void shouldReceiveOneMessageWithResolvingParams() throws Exception + { + k3po.finish(); + } + @Test @Configuration("proxy.when.subscribe.topic.with.messages.yaml") @Configure(name = WILL_AVAILABLE_NAME, value = "false") diff --git a/runtime/binding-mqtt/pom.xml b/runtime/binding-mqtt/pom.xml index f0e80fa1d0..7d83a51e93 100644 --- a/runtime/binding-mqtt/pom.xml +++ b/runtime/binding-mqtt/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -26,7 +26,7 @@ 11 11 - 0.69 + 0.88 3 diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventContext.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventContext.java new file mode 100644 index 0000000000..89ad74c645 --- /dev/null +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventContext.java @@ -0,0 +1,80 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.mqtt.internal; + +import static io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.MqttEventType.CLIENT_CONNECTED; + +import java.nio.ByteBuffer; +import java.time.Clock; + +import org.agrona.concurrent.AtomicBuffer; +import org.agrona.concurrent.UnsafeBuffer; + +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.MqttEventExFW; +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.guard.GuardHandler; + +public class MqttEventContext +{ + private static final int EVENT_BUFFER_CAPACITY = 2048; + + private final AtomicBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final AtomicBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); + private final EventFW.Builder eventRW = new EventFW.Builder(); + private final MqttEventExFW.Builder mqttEventExRW = new MqttEventExFW.Builder(); + private final int mqttTypeId; + private final int clientConnectedEventId; + private final MessageConsumer eventWriter; + private final Clock clock; + + public MqttEventContext( + EngineContext context) + { + this.mqttTypeId = context.supplyTypeId(MqttBinding.NAME); + this.clientConnectedEventId = context.supplyEventId("binding.mqtt.client.connected"); + this.eventWriter = context.supplyEventWriter(); + this.clock = context.clock(); + } + + public void onClientConnected( + long traceId, + long bindingId, + GuardHandler guard, + long authorization, + String clientId) + { + String identity = guard == null ? null : guard.identity(authorization); + MqttEventExFW extension = mqttEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .clientConnected(e -> e + .typeId(CLIENT_CONNECTED.value()) + .identity(identity) + .clientId(clientId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(clientConnectedEventId) + .timestamp(clock.millis()) + .traceId(traceId) + .namespacedId(bindingId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(mqttTypeId, event.buffer(), event.offset(), event.limit()); + } +} diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatter.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatter.java new file mode 100644 index 0000000000..ba102af34c --- /dev/null +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatter.java @@ -0,0 +1,73 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.mqtt.internal; + +import org.agrona.DirectBuffer; + +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.StringFW; +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.EventFW; +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.MqttClientConnectedExFW; +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.event.MqttEventExFW; +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; + +public final class MqttEventFormatter implements EventFormatterSpi +{ + private static final String CLIENT_CONNECTED_FORMAT = "CLIENT_CONNECTED %s %s"; + + private final EventFW eventRO = new EventFW(); + private final MqttEventExFW mqttEventExRO = new MqttEventExFW(); + + MqttEventFormatter( + Configuration config) + { + } + + public String format( + DirectBuffer buffer, + int index, + int length) + { + final EventFW event = eventRO.wrap(buffer, index, index + length); + final MqttEventExFW extension = mqttEventExRO + .wrap(event.extension().buffer(), event.extension().offset(), event.extension().limit()); + String result = null; + switch (extension.kind()) + { + case CLIENT_CONNECTED: + { + MqttClientConnectedExFW ex = extension.clientConnected(); + result = String.format(CLIENT_CONNECTED_FORMAT, identity(ex.identity()), asString(ex.clientId())); + break; + } + } + return result; + } + + private static String asString( + StringFW stringFW) + { + String s = stringFW.asString(); + return s == null ? "" : s; + } + + private static String identity( + StringFW identity) + { + int length = identity.length(); + return length <= 0 ? "-" : identity.asString(); + } +} diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatterFactory.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatterFactory.java new file mode 100644 index 0000000000..beab5092cc --- /dev/null +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/MqttEventFormatterFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.mqtt.internal; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi; + +public final class MqttEventFormatterFactory implements EventFormatterFactorySpi +{ + @Override + public MqttEventFormatter create( + Configuration config) + { + return new MqttEventFormatter(config); + } + + @Override + public String type() + { + return MqttBinding.NAME; + } +} diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/config/MqttBindingConfig.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/config/MqttBindingConfig.java index d97dce6ade..c20584064b 100644 --- a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/config/MqttBindingConfig.java +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/config/MqttBindingConfig.java @@ -51,7 +51,8 @@ public final class MqttBindingConfig public final KindConfig kind; public final MqttOptionsConfig options; public final List routes; - public final Function credentials; + public final Function resolveCredentials; + public final Function injectCredentials; public final Map topics; public final List versions; public final ToLongFunction resolveId; @@ -67,8 +68,10 @@ public MqttBindingConfig( this.routes = binding.routes.stream().map(MqttRouteConfig::new).collect(toList()); this.options = (MqttOptionsConfig) binding.options; this.resolveId = binding.resolveId; - this.credentials = options != null && options.authorization != null ? + this.resolveCredentials = options != null && options.authorization != null ? asAccessor(options.authorization.credentials) : DEFAULT_CREDENTIALS; + this.injectCredentials = options != null && options.authorization != null ? + asInjector(options.authorization.credentials) : DEFAULT_CREDENTIALS; this.topics = new HashMap<>(); if (options != null && options.topics != null) { @@ -175,9 +178,14 @@ public ModelConfig supplyUserPropertyModelConfig( return config; } - public Function credentials() + public Function resolveCredentials() { - return credentials; + return resolveCredentials; + } + + public Function injectCredentials() + { + return injectCredentials; } public MqttConnectProperty authField() @@ -215,7 +223,7 @@ private Function asAccessor( Pattern.compile(config.pattern.replace("{credentials}", "(?[^\\s]+)")) .matcher(""); - accessor = orElseIfNull(accessor, connect -> + accessor = connect -> { String result = null; if (connect != null && connectMatch.reset(connect).matches()) @@ -223,21 +231,34 @@ private Function asAccessor( result = connectMatch.group("credentials"); } return result; - }); + }; } return accessor; } - private static Function orElseIfNull( - Function first, - Function second) + private Function asInjector( + MqttCredentialsConfig credentials) { - return x -> + Function injector = DEFAULT_CREDENTIALS; + List connectPatterns = credentials.connect; + + if (connectPatterns != null && !connectPatterns.isEmpty()) { - String result = first.apply(x); - return result != null ? result : second.apply(x); - }; + MqttPatternConfig config = connectPatterns.get(0); + + injector = connect -> + { + String result = null; + if (connect != null) + { + result = config.pattern.replace("{credentials}", connect); + } + return result; + }; + } + + return injector; } private static class TopicValidator diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttClientFactory.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttClientFactory.java index 69e6367e3c..d979b67d0b 100644 --- a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttClientFactory.java +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttClientFactory.java @@ -77,6 +77,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.LongFunction; import java.util.function.LongSupplier; import java.util.function.LongUnaryOperator; @@ -90,6 +91,7 @@ import org.agrona.collections.ObjectHashSet; import org.agrona.concurrent.UnsafeBuffer; +import io.aklivity.zilla.runtime.binding.mqtt.config.MqttPatternConfig.MqttConnectProperty; import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttBinding; import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttConfiguration; import io.aklivity.zilla.runtime.binding.mqtt.internal.config.MqttBindingConfig; @@ -107,6 +109,7 @@ import io.aklivity.zilla.runtime.binding.mqtt.internal.types.OctetsFW; import io.aklivity.zilla.runtime.binding.mqtt.internal.types.String16FW; import io.aklivity.zilla.runtime.binding.mqtt.internal.types.Varuint32FW; +import io.aklivity.zilla.runtime.binding.mqtt.internal.types.codec.BinaryFW; import io.aklivity.zilla.runtime.binding.mqtt.internal.types.codec.MqttConnackV5FW; import io.aklivity.zilla.runtime.binding.mqtt.internal.types.codec.MqttConnectFW; import io.aklivity.zilla.runtime.binding.mqtt.internal.types.codec.MqttConnectV5FW; @@ -156,6 +159,7 @@ import io.aklivity.zilla.runtime.engine.buffer.BufferPool; import io.aklivity.zilla.runtime.engine.concurrent.Signaler; import io.aklivity.zilla.runtime.engine.config.BindingConfig; +import io.aklivity.zilla.runtime.engine.guard.GuardHandler; public final class MqttClientFactory implements MqttStreamFactory { @@ -177,6 +181,9 @@ public final class MqttClientFactory implements MqttStreamFactory private static final int RETAIN_AS_PUBLISHED_MASK = 0b0000_1000; private static final int RETAIN_HANDLING_MASK = 0b0011_0000; + private static final int USERNAME_MASK = 0b1000_0000; + private static final int PASSWORD_MASK = 0b0100_0000; + private static final int WILL_FLAG_MASK = 0b0000_0100; private static final int WILL_QOS_MASK = 0b0001_1000; private static final int WILL_RETAIN_MASK = 0b0010_0000; @@ -287,6 +294,8 @@ public final class MqttClientFactory implements MqttStreamFactory new Array32FW.Builder<>(new MqttUserPropertyFW.Builder(), new MqttUserPropertyFW()); private final Array32FW.Builder subscriptionIdsRW = new Array32FW.Builder<>(new Varuint32FW.Builder(), new Varuint32FW()); + private final BinaryFW.Builder passwordRW = new BinaryFW.Builder(); + private final MqttClientDecoder decodeInitialType = this::decodeInitialType; private final MqttClientDecoder decodePacketType = this::decodePacketType; private final MqttClientDecoder decodeConnack = this::decodeConnack; @@ -327,7 +336,8 @@ public final class MqttClientFactory implements MqttStreamFactory private final MutableDirectBuffer propertyBuffer; private final MutableDirectBuffer userPropertiesBuffer; private final MutableDirectBuffer subscriptionIdsBuffer; - private final MutableDirectBuffer willMessageBuffer; + private final MutableDirectBuffer connectPayloadBuffer; + private final MutableDirectBuffer passwordBuffer; private final MutableDirectBuffer willPropertyBuffer; private final ByteBuffer charsetBuffer; @@ -347,9 +357,10 @@ public final class MqttClientFactory implements MqttStreamFactory private final long publishTimeoutMillis; private final long connackTimeoutMillis; private final int encodeBudgetMax; - private final CharsetDecoder utf8Decoder; + private final EngineContext context; + public MqttClientFactory( MqttConfiguration config, EngineContext context) @@ -363,11 +374,13 @@ public MqttClientFactory( this.subscriptionIdsBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); this.payloadBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); this.charsetBuffer = ByteBuffer.wrap(new byte[writeBuffer.capacity()]); - this.willMessageBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); + this.connectPayloadBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); + this.passwordBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); this.willPropertyBuffer = new UnsafeBuffer(new byte[writeBuffer.capacity()]); this.bufferPool = context.bufferPool(); this.creditor = context.creditor(); this.signaler = context.signaler(); + this.context = context; this.droppedHandler = context.droppedFrameHandler(); this.streamFactory = context.streamFactory(); this.supplyDebitor = context::supplyDebitor; @@ -389,7 +402,7 @@ public MqttClientFactory( public void attach( BindingConfig binding) { - MqttBindingConfig mqttBinding = new MqttBindingConfig(binding, null); + MqttBindingConfig mqttBinding = new MqttBindingConfig(binding, context); bindings.put(binding.id, mqttBinding); } @@ -434,7 +447,8 @@ public MessageConsumer newStream( final MqttBeginExFW mqttBeginEx = extension.get(mqttBeginExRO::tryWrap); final int kind = mqttBeginEx.kind(); - MqttClient client = resolveClient(routedId, resolvedId, supplyInitialId.applyAsLong(resolvedId), affinity, kind); + MqttClient client = resolveClient(routedId, resolvedId, supplyInitialId.applyAsLong(resolvedId), affinity, kind, + binding.guard, binding.injectCredentials(), binding.authField()); switch (kind) { case MqttBeginExFW.KIND_SESSION: @@ -460,10 +474,14 @@ private MqttClient resolveClient( long resolvedId, long initialId, long affinity, - int kind) + int kind, + GuardHandler guard, + Function credentials, + MqttConnectProperty authField) { return kind == MqttBeginExFW.KIND_SESSION ? clients.computeIfAbsent(affinity, - s -> new MqttClient(routedId, resolvedId, initialId, maximumPacketSize)) : clients.get(affinity); + s -> new MqttClient(routedId, resolvedId, initialId, maximumPacketSize, guard, credentials, authField)) : + clients.get(affinity); } private MessageConsumer newStream( @@ -1199,6 +1217,9 @@ private final class MqttClient private final Int2ObjectHashMap subscribeStreams; private final Int2ObjectHashMap topicAliases; private final long encodeBudgetId; + private final GuardHandler guard; + private final Function credentials; + private final MqttConnectProperty authField; private long budgetId; private int state; @@ -1262,7 +1283,10 @@ private MqttClient( long originId, long routedId, long initialId, - int maximumPacketSize) + int maximumPacketSize, + GuardHandler guard, + Function credentials, + MqttConnectProperty authField) { this.originId = originId; this.routedId = routedId; @@ -1275,6 +1299,9 @@ private MqttClient( this.topicAliases = new Int2ObjectHashMap<>(); this.maximumPacketSize = maximumPacketSize; this.packetIdCounter = new AtomicInteger(); + this.guard = guard; + this.credentials = credentials; + this.authField = authField; } private void onNetwork( @@ -2248,6 +2275,7 @@ private void doEncodeConnect( propertiesSize = mqttProperty.limit(); } MqttWillV5FW will = null; + int connectPayloadProgress = 0; if (willMessage != null) { final int expiryInterval = willMessage.expiryInterval(); @@ -2307,14 +2335,38 @@ private void doEncodeConnect( willPropertiesSize.set(mqttWillPropertyRW.limit()); }); - will = willMessageRW.wrap(willMessageBuffer, 0, willMessageBuffer.capacity()) + will = willMessageRW.wrap(connectPayloadBuffer, 0, connectPayloadBuffer.capacity()) .properties(p -> p.length(willPropertiesSize.get()) .value(willPropertyBuffer, 0, willPropertiesSize.get())) .topic(willMessage.topic()) .payloadSize(willMessage.payloadSize()) .build(); - willMessageBuffer.putBytes(will.limit(), willPayload.buffer(), willPayload.offset(), willPayload.limit()); + connectPayloadBuffer.putBytes(will.limit(), willPayload.buffer(), willPayload.offset(), willPayload.limit()); + connectPayloadProgress = willPayload.limit(); + } + + int credentialsSize = 0; + if (guard != null) + { + Flyweight credentials = EMPTY_OCTETS; + String credentials0 = this.credentials.apply(guard.credentials(authorization)); + if (this.authField.equals(MqttConnectProperty.USERNAME)) + { + flags |= USERNAME_MASK; + credentials = new String16FW(credentials0, BIG_ENDIAN); + credentialsSize = credentials.sizeof(); + } + else if (this.authField.equals(MqttConnectProperty.PASSWORD)) + { + flags |= PASSWORD_MASK; + credentials = passwordRW.wrap(passwordBuffer, 0, passwordBuffer.capacity()) + .bytes(b -> b.set(credentials0.getBytes(StandardCharsets.UTF_8))).build(); + credentialsSize = credentials.sizeof(); + } + + connectPayloadBuffer + .putBytes(connectPayloadProgress, credentials.buffer(), credentials.offset(), credentials.limit()); } final int propertiesSize0 = propertiesSize; @@ -2324,7 +2376,7 @@ private void doEncodeConnect( final MqttConnectV5FW connect = mqttConnectV5RW.wrap(writeBuffer, FIELD_OFFSET_PAYLOAD, writeBuffer.capacity()) .typeAndFlags(0x10) - .remainingLength(11 + propertiesSize0 + clientId.length() + 2 + willSize) + .remainingLength(11 + propertiesSize0 + clientId.length() + 2 + willSize + credentialsSize) .protocolName(MQTT_PROTOCOL_NAME) .protocolVersion(MQTT_PROTOCOL_VERSION) .flags(flags) @@ -2335,9 +2387,9 @@ private void doEncodeConnect( .build(); doNetworkData(traceId, authorization, 0L, connect); - if (will != null) + if (will != null || guard != null) { - doNetworkData(traceId, authorization, 0L, willMessageBuffer, 0, willSize); + doNetworkData(traceId, authorization, 0L, connectPayloadBuffer, 0, willSize + credentialsSize); } } diff --git a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttServerFactory.java b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttServerFactory.java index ff18bfa0d4..c2fe91c9a2 100644 --- a/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttServerFactory.java +++ b/runtime/binding-mqtt/src/main/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/MqttServerFactory.java @@ -112,6 +112,7 @@ import io.aklivity.zilla.runtime.binding.mqtt.config.MqttPatternConfig.MqttConnectProperty; import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttBinding; import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttConfiguration; +import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttEventContext; import io.aklivity.zilla.runtime.binding.mqtt.internal.MqttValidator; import io.aklivity.zilla.runtime.binding.mqtt.internal.config.MqttBindingConfig; import io.aklivity.zilla.runtime.binding.mqtt.internal.config.MqttRouteConfig; @@ -204,7 +205,7 @@ public final class MqttServerFactory implements MqttStreamFactory private static final String16FW MQTT_PROTOCOL_NAME = new String16FW("MQTT", BIG_ENDIAN); public static final int MQTT_PROTOCOL_VERSION_5 = 5; public static final int MQTT_PROTOCOL_VERSION_4 = 4; - private static final int MAXIMUM_CLIENT_ID_LENGTH = 36; + private static final int MAXIMUM_CLIENT_ID_LENGTH = 256; private static final int CONNECT_FIXED_HEADER = 0b0001_0000; private static final int SUBSCRIBE_FIXED_HEADER = 0b1000_0010; private static final int UNSUBSCRIBE_FIXED_HEADER = 0b1010_0010; @@ -406,7 +407,6 @@ public final class MqttServerFactory implements MqttStreamFactory private final Map decodersByPacketTypeV4; private final Map decodersByPacketTypeV5; private final IntSupplier supplySubscriptionId; - private final MqttQoS publishQosMax; private final EngineContext context; private int maximumPacketSize = Integer.MAX_VALUE; @@ -481,6 +481,9 @@ public final class MqttServerFactory implements MqttStreamFactory private final MqttValidator validator; private final CharsetDecoder utf8Decoder; private final Function supplyValidator; + private final MqttEventContext events; + + private MqttQoS publishQosMax; public MqttServerFactory( MqttConfiguration config, @@ -528,6 +531,7 @@ public MqttServerFactory( this.decodePacketTypeByVersion.put(MQTT_PROTOCOL_VERSION_4, this::decodePacketTypeV4); this.decodePacketTypeByVersion.put(MQTT_PROTOCOL_VERSION_5, this::decodePacketTypeV5); this.supplyValidator = context::supplyValidator; + this.events = new MqttEventContext(context); } @Override @@ -574,7 +578,7 @@ public MessageConsumer newStream( affinity, binding.versions, binding.guard, - binding.credentials(), + binding.resolveCredentials(), binding.authField())::onNetwork; } return newStream; @@ -972,7 +976,7 @@ private int decodePacketTypeV5( server.onDecodeError(traceId, authorization, PACKET_TOO_LARGE); server.decoder = decodeIgnoreAll; } - else if (length >= 0) + else if (limit - packet.limit() >= length || server.decodeBudget() == 0) { server.decodeablePacketBytes = packet.sizeof() + length; server.decoder = decoder; @@ -1251,6 +1255,13 @@ private int decodePublishV4( String16FW topicName; int publishLimit; int packetId = 0; + + if (qos > publishQosMax.value()) + { + reasonCode = QOS_NOT_SUPPORTED; + break decode; + } + if (qos > 0) { final MqttPublishQosV4FW publish = @@ -1355,6 +1366,13 @@ private int decodePublishV5( MqttPropertiesFW properties; int publishLimit; int packetId = 0; + + if (qos > publishQosMax.value()) + { + reasonCode = QOS_NOT_SUPPORTED; + break decode; + } + if (qos > 0) { final MqttPublishQosV5FW publish = @@ -3175,11 +3193,7 @@ private void onDecodePublish( { int reasonCode = SUCCESS; - if (qos > subscribeQosMax) - { - reasonCode = QOS_NOT_SUPPORTED; - } - else if (retained && !retainAvailable(capabilities)) + if (retained && !retainAvailable(capabilities)) { reasonCode = RETAIN_NOT_SUPPORTED; } @@ -4436,6 +4450,10 @@ private void doEncodeConnack( String16FW reason, int version) { + if (reasonCode == SUCCESS) + { + events.onClientConnected(traceId, routedId, guard, authorization, clientId.asString()); + } switch (version) { @@ -4975,6 +4993,11 @@ private boolean validContent( payload.sizeof(), ValueConsumer.NOP); } + private int decodeBudget() + { + return decodeMax - (int) (decodeSeq - decodeAck); + } + private final class Subscription { private int id = 0; @@ -5212,6 +5235,7 @@ private void onSessionBegin( sessionExpiry = mqttSessionBeginEx.expiry(); capabilities = mqttSessionBeginEx.capabilities(); subscribeQosMax = mqttSessionBeginEx.subscribeQosMax(); + publishQosMax = MqttQoS.valueOf(mqttSessionBeginEx.publishQosMax()); if (packetIds != null) { packetIds.forEachRemaining((IntConsumer) p -> unreleasedPacketIds.add(p)); diff --git a/runtime/binding-mqtt/src/main/moditect/module-info.java b/runtime/binding-mqtt/src/main/moditect/module-info.java index 4cf09438f0..06d1e06d0b 100644 --- a/runtime/binding-mqtt/src/main/moditect/module-info.java +++ b/runtime/binding-mqtt/src/main/moditect/module-info.java @@ -27,4 +27,7 @@ provides io.aklivity.zilla.runtime.engine.config.ConditionConfigAdapterSpi with io.aklivity.zilla.runtime.binding.mqtt.internal.config.MqttConditionConfigAdapter; + + provides io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi + with io.aklivity.zilla.runtime.binding.mqtt.internal.MqttEventFormatterFactory; } diff --git a/runtime/binding-mqtt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi b/runtime/binding-mqtt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi new file mode 100644 index 0000000000..574bd0dd80 --- /dev/null +++ b/runtime/binding-mqtt/src/main/resources/META-INF/services/io.aklivity.zilla.runtime.engine.event.EventFormatterFactorySpi @@ -0,0 +1 @@ +io.aklivity.zilla.runtime.binding.mqtt.internal.MqttEventFormatterFactory diff --git a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/client/v5/ConnectionIT.java b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/client/v5/ConnectionIT.java index 93a333e7b0..cf0fec79b1 100644 --- a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/client/v5/ConnectionIT.java +++ b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/client/v5/ConnectionIT.java @@ -61,6 +61,26 @@ public void shouldReceiveClientSentAbort() throws Exception k3po.finish(); } + @Test + @Configuration("client.credentials.username.yaml") + @Specification({ + "${net}/connect.username.authentication.successful/server", + "${app}/session.connect.authorization/client"}) + public void shouldAuthenticateUsernameAndConnect() throws Exception + { + k3po.finish(); + } + + @Test + @Configuration("client.credentials.password.yaml") + @Specification({ + "${net}/connect.password.authentication.successful/server", + "${app}/session.connect.authorization/client"}) + public void shouldAuthenticatePasswordAndConnect() throws Exception + { + k3po.finish(); + } + @Test @Configuration("client.yaml") @Specification({ diff --git a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v4/ConnectionIT.java b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v4/ConnectionIT.java index 7beb8dbe69..3fc6db15b0 100644 --- a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v4/ConnectionIT.java +++ b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v4/ConnectionIT.java @@ -68,6 +68,16 @@ public void shouldConnect() throws Exception k3po.finish(); } + @Test + @Configuration("server.log.event.yaml") + @Specification({ + "${net}/connect.successful/client", + "${app}/session.connect/server"}) + public void shouldConnectAndLog() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.credentials.username.yaml") @Specification({ @@ -126,6 +136,15 @@ public void shouldRejectMissingClientId() throws Exception k3po.finish(); } + @Test + @Configuration("server.yaml") + @Specification({ + "${net}/connect.reject.exceeding.max.client.id/client"}) + public void shouldRejectExceedingClientIdMax() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.yaml") @Specification({ diff --git a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v5/ConnectionIT.java b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v5/ConnectionIT.java index 09d0a4965e..7d22e40ed3 100644 --- a/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v5/ConnectionIT.java +++ b/runtime/binding-mqtt/src/test/java/io/aklivity/zilla/runtime/binding/mqtt/internal/stream/server/v5/ConnectionIT.java @@ -66,6 +66,16 @@ public void shouldConnect() throws Exception k3po.finish(); } + @Test + @Configuration("server.log.event.yaml") + @Specification({ + "${net}/connect.successful/client", + "${app}/session.connect/server"}) + public void shouldConnectAndLog() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.credentials.username.yaml") @Specification({ @@ -124,6 +134,15 @@ public void shouldRejectMissingClientId() throws Exception k3po.finish(); } + @Test + @Configuration("server.yaml") + @Specification({ + "${net}/connect.reject.exceeding.max.client.id/client"}) + public void shouldRejectExceedingClientIdMax() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.yaml") @Specification({ diff --git a/runtime/binding-openapi-asyncapi/pom.xml b/runtime/binding-openapi-asyncapi/pom.xml index 21fd07e4e8..9951cd1944 100644 --- a/runtime/binding-openapi-asyncapi/pom.xml +++ b/runtime/binding-openapi-asyncapi/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-openapi-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/config/OpenapiAsyncNamespaceGenerator.java b/runtime/binding-openapi-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/config/OpenapiAsyncNamespaceGenerator.java index b72459bc66..dbd0a02ec3 100644 --- a/runtime/binding-openapi-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/config/OpenapiAsyncNamespaceGenerator.java +++ b/runtime/binding-openapi-asyncapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/config/OpenapiAsyncNamespaceGenerator.java @@ -145,24 +145,102 @@ private void computeRoutes( condition.operationId : path.methods().get(method).operationId; final OpenapiOperation openapiOperation = path.methods().get(method); - final Optional asyncapiOperation = asyncapi.operations.entrySet().stream() - .filter(f -> f.getKey().equals(operationId)) - .map(Map.Entry::getValue) - .findFirst(); - final List paramNames = findParams(item); - - asyncapiOperation.ifPresent(operation -> binding - .route() - .exit(qname) - .when(HttpKafkaConditionConfig::builder) - .method(method) - .path(item) - .build() - .inject(r -> injectHttpKafkaRouteWith(r, openapi, asyncapi, openapiOperation, - operation, paramNames)) - .build()); + final Optional asyncapiOperation = findAsyncOperation( + item, openapi, asyncapi, openapiOperation, operationId); + + asyncapiOperation.ifPresent(operation -> + { + final List paramNames = findParams(item); + + binding + .route() + .exit(qname) + .when(HttpKafkaConditionConfig::builder) + .method(method) + .path(item) + .build() + .inject(r -> injectHttpKafkaRouteWith(r, openapi, asyncapi, openapiOperation, + operation, paramNames)) + .build(); + }); + } + } + } + + private Optional findAsyncOperation( + String path, + Openapi openapi, + Asyncapi asyncapi, + OpenapiOperation openapiOperation, + String operationId) + { + Optional operation = findAsyncOperationByOperationId(asyncapi.operations, operationId); + + if (operation.isEmpty() && isOpenapiOperationAsync(openapiOperation)) + { + Optional correlatedOperationId = findOpenapiOperationIdByFormat(path, openapi); + if (correlatedOperationId.isPresent()) + { + operation = findAsyncOperationByOperationId(asyncapi.operations, correlatedOperationId.get()); + } + } + return operation; + } + + private Optional findAsyncOperationByOperationId( + Map operations, + String operationId) + { + return operations.entrySet().stream() + .filter(f -> f.getKey().equals(operationId)) + .map(Map.Entry::getValue) + .findFirst(); + } + + private Optional findOpenapiOperationIdByFormat( + String format, + Openapi openapi) + { + String operationId = null; + correlated: + for (String item : openapi.paths.keySet()) + { + if (!item.equals(format)) + { + OpenapiPathView path = OpenapiPathView.of(openapi.paths.get(item)); + for (String method : path.methods().keySet()) + { + final OpenapiOperation openapiOperation = path.methods().get(method); + boolean formatMatched = openapiOperation.responses.entrySet().stream() + .anyMatch(o -> + { + OpenapiResponseByContentType content = o.getValue(); + return "202".equals(o.getKey()) && content.headers.entrySet().stream() + .anyMatch(c -> matchFormat(format, c.getValue())); + }); + + if (formatMatched) + { + operationId = path.methods().get(method).operationId; + break correlated; + } + } } } + + return Optional.ofNullable(operationId); + } + + private boolean isOpenapiOperationAsync( + OpenapiOperation openapiOperation) + { + return openapiOperation.responses.entrySet().stream() + .anyMatch(o -> + { + OpenapiResponseByContentType content = o.getValue(); + return "202".equals(o.getKey()) && content.headers.entrySet().stream() + .anyMatch(c -> hasCorrelationId(c.getValue())); + }); } private List findParams( @@ -304,6 +382,21 @@ private boolean hasCorrelationId( return hasCorrelationId; } + private boolean matchFormat( + String format, + OpenapiHeader header) + { + boolean matched = false; + OpenapiSchema schema = header.schema; + if (schema != null && + schema.format != null) + { + matched = schema.format.equals(format); + } + + return matched; + } + private NamespaceConfigBuilder injectNamespaceMetric( NamespaceConfigBuilder namespace, boolean hasMetrics) diff --git a/runtime/binding-openapi-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/streams/OpenapiAsyncapiIT.java b/runtime/binding-openapi-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/streams/OpenapiAsyncapiIT.java index 2c28776b51..70d72e6ca3 100644 --- a/runtime/binding-openapi-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/streams/OpenapiAsyncapiIT.java +++ b/runtime/binding-openapi-asyncapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/asyncapi/internal/streams/OpenapiAsyncapiIT.java @@ -56,4 +56,15 @@ public void shouldCreatePet() throws Exception { k3po.finish(); } + + @Test + @Configuration("proxy-async.yaml") + @Specification({ + "${openapi}/async.verify.customer/client", + "${asyncapi}/async.verify.customer/server" + }) + public void shouldVerifyCustomerAsync() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/binding-openapi/pom.xml b/runtime/binding-openapi/pom.xml index 23c63cc997..dd224e1c0a 100644 --- a/runtime/binding-openapi/pom.xml +++ b/runtime/binding-openapi/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiBindingConfig.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiBindingConfig.java index 1b020b55a1..27f91d386f 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiBindingConfig.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiBindingConfig.java @@ -28,6 +28,7 @@ import java.util.function.ToLongFunction; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.agrona.AsciiSequenceView; import org.agrona.DirectBuffer; @@ -47,6 +48,7 @@ import io.aklivity.zilla.runtime.binding.openapi.internal.types.String16FW; import io.aklivity.zilla.runtime.binding.openapi.internal.types.String8FW; import io.aklivity.zilla.runtime.binding.openapi.internal.types.stream.HttpBeginExFW; +import io.aklivity.zilla.runtime.binding.openapi.internal.view.OpenapiServerView; import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.config.BindingConfig; import io.aklivity.zilla.runtime.engine.config.KindConfig; @@ -119,29 +121,44 @@ public void attach( BindingConfig binding) { List configs = convertToOpenapi(options.openapis); - configs.forEach(c -> + + final Map namespaceConfigs = new HashMap<>(); + for (OpenapiSchemaConfig config : configs) + { + Openapi openapi = config.openapi; + final List servers = + namespaceGenerator.filterOpenapiServers(openapi.servers, options.openapis.stream() + .flatMap(o -> o.servers.stream()) + .collect(Collectors.toList())); + + servers.stream().collect(Collectors.groupingBy(OpenapiServerView::getPort)).forEach((k, v) -> + namespaceConfigs.computeIfAbsent(k, s -> new OpenapiNamespaceConfig()).addSpecForNamespace(v, config, openapi)); + } + + for (OpenapiNamespaceConfig namespaceConfig : namespaceConfigs.values()) { - Openapi openapi = c.openapi; - final NamespaceConfig composite = namespaceGenerator.generate(binding, openapi); + final NamespaceConfig composite = namespaceGenerator.generate(binding, namespaceConfig); composite.readURL = binding.readURL; attach.accept(composite); - composites.put(c.schemaId, composite); - openapi.paths.forEach((k, v) -> + namespaceConfig.configs.forEach(c -> { - String regex = k.replaceAll("\\{[^/]+}", "[^/]+"); - regex = "^" + regex + "$"; - Pattern pattern = Pattern.compile(regex); - paths.put(pattern.matcher(""), v); + composites.put(c.schemaId, composite); + namespaceConfig.openapis.forEach(o -> + o.paths.forEach((k, v) -> + { + String regex = k.replaceAll("\\{[^/]+}", "[^/]+"); + regex = "^" + regex + "$"; + Pattern pattern = Pattern.compile(regex); + paths.put(pattern.matcher(""), v); + }) + ); }); - }); + } composites.forEach((k, v) -> { List http = v.bindings.stream().filter(b -> b.type.equals("http")).collect(toList()); - http.stream() - .map(b -> b.routes) - .flatMap(List::stream) - .forEach(r -> resolvedIds.put(k, r.id)); + http.forEach(b -> resolvedIds.put(k, b.id)); http.stream() .map(b -> NamespacedId.namespaceId(b.id)) .forEach(n -> diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiClientNamespaceGenerator.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiClientNamespaceGenerator.java index af7c0344b2..04a2c043a1 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiClientNamespaceGenerator.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiClientNamespaceGenerator.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfig; import io.aklivity.zilla.runtime.binding.http.config.HttpOptionsConfigBuilder; @@ -44,6 +43,10 @@ import io.aklivity.zilla.runtime.engine.config.ModelConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.StringModelConfig; +import io.aklivity.zilla.runtime.model.core.config.StringModelConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.StringPattern; +import io.aklivity.zilla.runtime.model.core.internal.StringModel; import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; public final class OpenapiClientNamespaceGenerator extends OpenapiNamespaceGenerator @@ -51,19 +54,15 @@ public final class OpenapiClientNamespaceGenerator extends OpenapiNamespaceGener @Override public NamespaceConfig generate( BindingConfig binding, - Openapi openapi) + OpenapiNamespaceConfig namespaceConfig) { final OpenapiOptionsConfig options = (OpenapiOptionsConfig) binding.options; final List metricRefs = binding.telemetryRef != null ? binding.telemetryRef.metricRefs : emptyList(); - final List servers = - filterOpenapiServers( - openapi.servers, options.openapis.stream() - .flatMap(o -> o.servers.stream()) - .collect(Collectors.toList())); + List servers = namespaceConfig.servers; final int[] httpsPorts = resolvePortsForScheme("https", servers); - final boolean secure = httpsPorts != null; + final boolean secure = httpsPorts.length != 0; return NamespaceConfig.builder() .name(String.format(binding.qname, "$composite")) @@ -72,7 +71,7 @@ public NamespaceConfig generate( .name("http_client0") .type("http") .kind(CLIENT) - .inject(b -> this.injectHttpClientOptions(b, openapi)) + .inject(b -> this.injectHttpClientOptions(b, namespaceConfig.openapis)) .inject(b -> this.injectMetrics(b, metricRefs, "http")) .exit(secure ? "tls_client0" : "tcp_client0") .build() @@ -89,15 +88,18 @@ public NamespaceConfig generate( private BindingConfigBuilder injectHttpClientOptions( BindingConfigBuilder binding, - Openapi openApi) + List openApis) { - OpenapiOperationsView operations = OpenapiOperationsView.of(openApi.paths); - if (operations.hasResponses()) + for (Openapi openApi : openApis) { - binding. - options(HttpOptionsConfig::builder) - .inject(options -> injectHttpClientRequests(operations, options, openApi)) - .build(); + OpenapiOperationsView operations = OpenapiOperationsView.of(openApi.paths); + if (operations.hasResponses()) + { + binding. + options(HttpOptionsConfig::builder) + .inject(options -> injectHttpClientRequests(operations, options, openApi)) + .build(); + } } return binding; } @@ -175,16 +177,33 @@ private HttpResponseConfigBuilder injectResponseHeaders( { String name = header.getKey(); OpenapiSchema schema = header.getValue().schema; - String modelName = schema.format != null ? String.format("%s:%s", schema.type, schema.format) : - schema.type; - ModelConfig model = models.get(modelName); - if (model != null) + if (schema != null) { - response - .header() + String format = schema.format; + String type = schema.type; + ModelConfig model; + if (StringModel.NAME.equals(type)) + { + StringModelConfigBuilder builder = StringModelConfig.builder(); + if (format != null) + { + builder.pattern(StringPattern.of(format)); + } + model = builder.build(); + } + else + { + model = MODELS.get(format != null ? String.format("%s:%s", type, format) : type); + } + + if (model != null) + { + response + .header() .name(name) .model(model) .build(); + } } } } diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceConfig.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceConfig.java new file mode 100644 index 0000000000..eb2515997f --- /dev/null +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.binding.openapi.internal.config; + +import java.util.ArrayList; +import java.util.List; + +import io.aklivity.zilla.runtime.binding.openapi.config.OpenapiSchemaConfig; +import io.aklivity.zilla.runtime.binding.openapi.internal.model.Openapi; +import io.aklivity.zilla.runtime.binding.openapi.internal.view.OpenapiServerView; + +public class OpenapiNamespaceConfig +{ + List openapiLabels; + List servers; + List openapis; + List configs; + + public OpenapiNamespaceConfig() + { + openapiLabels = new ArrayList<>(); + servers = new ArrayList<>(); + openapis = new ArrayList<>(); + configs = new ArrayList<>(); + } + + public void addSpecForNamespace( + List servers, + OpenapiSchemaConfig config, + Openapi openapi) + { + this.openapiLabels.add(config.apiLabel); + this.servers.addAll(servers); + this.configs.add(config); + this.openapis.add(openapi); + } +} diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceGenerator.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceGenerator.java index 9ed52ad14f..bb3dca77c1 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceGenerator.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiNamespaceGenerator.java @@ -28,7 +28,6 @@ import io.aklivity.zilla.runtime.binding.openapi.config.OpenapiOptionsConfig; import io.aklivity.zilla.runtime.binding.openapi.config.OpenapiServerConfig; -import io.aklivity.zilla.runtime.binding.openapi.internal.model.Openapi; import io.aklivity.zilla.runtime.binding.openapi.internal.model.OpenapiServer; import io.aklivity.zilla.runtime.binding.openapi.internal.view.OpenapiServerView; import io.aklivity.zilla.runtime.engine.config.BindingConfig; @@ -38,9 +37,10 @@ import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; import io.aklivity.zilla.runtime.engine.config.TelemetryRefConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.DoubleModelConfig; +import io.aklivity.zilla.runtime.model.core.config.FloatModelConfig; import io.aklivity.zilla.runtime.model.core.config.Int32ModelConfig; import io.aklivity.zilla.runtime.model.core.config.Int64ModelConfig; -import io.aklivity.zilla.runtime.model.core.config.StringModelConfig; public abstract class OpenapiNamespaceGenerator { @@ -49,18 +49,20 @@ public abstract class OpenapiNamespaceGenerator protected static final String VERSION_LATEST = "latest"; protected static final Pattern JSON_CONTENT_TYPE = Pattern.compile("^application/(?:.+\\+)?json$"); protected static final OpenapiOptionsConfig EMPTY_OPTIONS = OpenapiOptionsConfig.builder().build(); - - protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher(""); - protected final Map models = Map.of( - "string", StringModelConfig.builder().build(), + protected static final Map MODELS = Map.of( "integer", Int32ModelConfig.builder().build(), "integer:int32", Int32ModelConfig.builder().build(), - "integer:int64", Int64ModelConfig.builder().build() + "integer:int64", Int64ModelConfig.builder().build(), + "number", FloatModelConfig.builder().build(), + "number:float", FloatModelConfig.builder().build(), + "number:double", DoubleModelConfig.builder().build() ); + protected final Matcher jsonContentType = JSON_CONTENT_TYPE.matcher(""); + public abstract NamespaceConfig generate( BindingConfig binding, - Openapi openapi); + OpenapiNamespaceConfig namespaceConfig); protected NamespaceConfigBuilder injectNamespaceMetric( NamespaceConfigBuilder namespace, diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiServerNamespaceGenerator.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiServerNamespaceGenerator.java index 4da97ae662..dea107b949 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiServerNamespaceGenerator.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/config/OpenapiServerNamespaceGenerator.java @@ -23,7 +23,6 @@ import java.net.URI; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import jakarta.json.bind.Jsonb; import jakarta.json.bind.JsonbBuilder; @@ -58,6 +57,10 @@ import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; import io.aklivity.zilla.runtime.engine.config.NamespaceConfigBuilder; import io.aklivity.zilla.runtime.engine.config.RouteConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.StringModelConfig; +import io.aklivity.zilla.runtime.model.core.config.StringModelConfigBuilder; +import io.aklivity.zilla.runtime.model.core.config.StringPattern; +import io.aklivity.zilla.runtime.model.core.internal.StringModel; import io.aklivity.zilla.runtime.model.json.config.JsonModelConfig; public final class OpenapiServerNamespaceGenerator extends OpenapiNamespaceGenerator @@ -67,26 +70,23 @@ public final class OpenapiServerNamespaceGenerator extends OpenapiNamespaceGener @Override public NamespaceConfig generate( BindingConfig binding, - Openapi openapi) + OpenapiNamespaceConfig namespaceConfig) { final OpenapiOptionsConfig options = binding.options != null ? (OpenapiOptionsConfig) binding.options : EMPTY_OPTIONS; final List metricRefs = binding.telemetryRef != null ? binding.telemetryRef.metricRefs : emptyList(); - final List servers = - filterOpenapiServers( - openapi.servers, options.openapis.stream() - .flatMap(o -> o.servers.stream()) - .collect(Collectors.toList())); + final List servers = namespaceConfig.servers; final String qvault = String.format("%s:%s", binding.namespace, binding.vault); + final String namespace = String.join("+", namespaceConfig.openapiLabels); return NamespaceConfig.builder() - .name(String.format("%s/http", binding.qname)) - .inject(namespace -> injectNamespaceMetric(namespace, !metricRefs.isEmpty())) - .inject(n -> injectCatalog(n, openapi)) + .name(String.format("%s/%s", binding.qname, namespace)) + .inject(n -> injectNamespaceMetric(n, !metricRefs.isEmpty())) + .inject(n -> injectCatalog(n, namespaceConfig.openapis)) .inject(n -> injectTcpServer(n, servers, options, metricRefs)) .inject(n -> injectTlsServer(n, qvault, servers, options, metricRefs)) - .inject(n -> injectHttpServer(n, binding.qname, openapi, servers, options, metricRefs)) + .inject(n -> injectHttpServer(n, binding.qname, namespaceConfig.openapis, servers, options, metricRefs)) .build(); } @@ -166,25 +166,28 @@ private HttpOptionsConfigBuilder injectHttpServerOptions( private HttpOptionsConfigBuilder injectHttpServerRequests( HttpOptionsConfigBuilder options, - Openapi openapi) + List openapis) { - for (String pathName : openapi.paths.keySet()) + for (Openapi openapi : openapis) { - OpenapiPathView path = OpenapiPathView.of(openapi.paths.get(pathName)); - for (String methodName : path.methods().keySet()) + for (String pathName : openapi.paths.keySet()) { - final OpenapiOperation operation = path.methods().get(methodName); - if (operation.requestBody != null || - operation.parameters != null && - !operation.parameters.isEmpty()) + OpenapiPathView path = OpenapiPathView.of(openapi.paths.get(pathName)); + for (String methodName : path.methods().keySet()) { - options - .request() - .path(pathName) - .method(HttpRequestConfig.Method.valueOf(methodName)) - .inject(request -> injectContent(request, operation, openapi)) - .inject(request -> injectParams(request, operation)) - .build(); + final OpenapiOperation operation = path.methods().get(methodName); + if (operation.requestBody != null || + operation.parameters != null && + !operation.parameters.isEmpty()) + { + options + .request() + .path(pathName) + .method(HttpRequestConfig.Method.valueOf(methodName)) + .inject(request -> injectContent(request, operation, openapi)) + .inject(request -> injectParams(request, operation)) + .build(); + } } } } @@ -226,12 +229,25 @@ private HttpRequestConfigBuilder injectParams( { for (OpenapiParameter parameter : operation.parameters) { - if (parameter.schema != null && parameter.schema.type != null) + OpenapiSchema schema = parameter.schema; + if (schema != null && schema.type != null) { - OpenapiSchema schema = parameter.schema; - String modelName = schema.format != null ? String.format("%s:%s", schema.type, schema.format) : - schema.type; - ModelConfig model = models.get(modelName); + String format = schema.format; + String type = schema.type; + ModelConfig model; + if (StringModel.NAME.equals(type)) + { + StringModelConfigBuilder builder = StringModelConfig.builder(); + if (format != null) + { + builder.pattern(StringPattern.of(format)); + } + model = builder.build(); + } + else + { + model = MODELS.get(format != null ? String.format("%s:%s", type, format) : type); + } if (model != null) { switch (parameter.in) @@ -267,25 +283,28 @@ private HttpRequestConfigBuilder injectParams( private BindingConfigBuilder injectHttpServerRoutes( BindingConfigBuilder binding, - Openapi openApi, + List openApis, String qname, String guardName, Map securitySchemes) { - for (String item : openApi.paths.keySet()) + for (Openapi openApi : openApis) { - OpenapiPathView path = OpenapiPathView.of(openApi.paths.get(item)); - for (String method : path.methods().keySet()) + for (String item : openApi.paths.keySet()) { - binding - .route() - .exit(qname) - .when(HttpConditionConfig::builder) - .header(":path", item.replaceAll("\\{[^}]+\\}", "*")) - .header(":method", method) - .build() - .inject(route -> injectHttpServerRouteGuarded(route, path, method, guardName, securitySchemes)) - .build(); + OpenapiPathView path = OpenapiPathView.of(openApi.paths.get(item)); + for (String method : path.methods().keySet()) + { + binding + .route() + .exit(qname) + .when(HttpConditionConfig::builder) + .header(":path", item.replaceAll("\\{[^}]+\\}", "*")) + .header(":method", method) + .build() + .inject(route -> injectHttpServerRouteGuarded(route, path, method, guardName, securitySchemes)) + .build(); + } } } @@ -335,11 +354,11 @@ private GuardedConfigBuilder injectGuardedRoles( private NamespaceConfigBuilder injectCatalog( NamespaceConfigBuilder namespace, - Openapi openapi) + List openapis) { - if (openapi.components != null && - openapi.components.schemas != null && - !openapi.components.schemas.isEmpty()) + final boolean injectCatalog = openapis.stream() + .anyMatch(a -> a.components != null && a.components.schemas != null && !a.components.schemas.isEmpty()); + if (injectCatalog) { namespace .catalog() @@ -347,7 +366,7 @@ private NamespaceConfigBuilder injectCatalog( .type(INLINE_CATALOG_TYPE) .options(InlineOptionsConfig::builder) .subjects() - .inject(s -> this.injectSubjects(s, openapi)) + .inject(s -> this.injectSubjects(s, openapis)) .build() .build() .build(); @@ -390,12 +409,12 @@ private NamespaceConfigBuilder injectTcpServer( private NamespaceConfigBuilder injectHttpServer( NamespaceConfigBuilder namespace, String qname, - Openapi openapi, + List openapis, List servers, OpenapiOptionsConfig options, List metricRefs) { - final Map securitySchemes = resolveSecuritySchemes(openapi); + final Map securitySchemes = resolveSecuritySchemes(openapis); final boolean hasJwt = !securitySchemes.isEmpty(); final HttpOptionsConfig httpOptions = options.http; final String guardName = httpOptions != null ? httpOptions.authorization.name : null; @@ -412,9 +431,9 @@ private NamespaceConfigBuilder injectHttpServer( .policy(CROSS_ORIGIN) .build() .inject(o -> this.injectHttpServerOptions(o, authorization, hasJwt)) - .inject(r -> this.injectHttpServerRequests(r, openapi)) + .inject(r -> this.injectHttpServerRequests(r, openapis)) .build() - .inject(b -> this.injectHttpServerRoutes(b, openapi, qname, guardName, securitySchemes)) + .inject(b -> this.injectHttpServerRoutes(b, openapis, qname, guardName, securitySchemes)) .inject(b -> this.injectMetrics(b, metricRefs, "http")) .build(); @@ -423,25 +442,28 @@ private NamespaceConfigBuilder injectHttpServer( private InlineSchemaConfigBuilder injectSubjects( InlineSchemaConfigBuilder subjects, - Openapi openApi) + List openApis) { - try (Jsonb jsonb = JsonbBuilder.create()) + for (Openapi openApi : openApis) { - for (Map.Entry entry : openApi.components.schemas.entrySet()) + try (Jsonb jsonb = JsonbBuilder.create()) { - OpenapiSchemaView schemaView = OpenapiSchemaView.of(openApi.components.schemas, entry.getValue()); - OpenapiSchema schema = schemaView.ref() != null ? schemaView.ref() : entry.getValue(); + for (Map.Entry entry : openApi.components.schemas.entrySet()) + { + OpenapiSchemaView schemaView = OpenapiSchemaView.of(openApi.components.schemas, entry.getValue()); + OpenapiSchema schema = schemaView.ref() != null ? schemaView.ref() : entry.getValue(); - subjects - .subject(entry.getKey()) - .schema(jsonb.toJson(schema)) - .version(VERSION_LATEST) - .build(); + subjects + .subject(entry.getKey()) + .schema(jsonb.toJson(schema)) + .version(VERSION_LATEST) + .build(); + } + } + catch (Exception ex) + { + rethrowUnchecked(ex); } - } - catch (Exception ex) - { - rethrowUnchecked(ex); } return subjects; } @@ -459,19 +481,22 @@ public int[] resolveAllPorts( } private Map resolveSecuritySchemes( - Openapi openApi) + List openApis) { - requireNonNull(openApi); + requireNonNull(openApis); Map result = new Object2ObjectHashMap<>(); - if (openApi.components != null && - openApi.components.securitySchemes != null) + for (Openapi openApi : openApis) { - for (String securitySchemeName : openApi.components.securitySchemes.keySet()) + if (openApi.components != null && + openApi.components.securitySchemes != null) { - String guardType = openApi.components.securitySchemes.get(securitySchemeName).bearerFormat; - if (JWT.equalsIgnoreCase(guardType)) + for (String securitySchemeName : openApi.components.securitySchemes.keySet()) { - result.put(securitySchemeName, guardType); + String guardType = openApi.components.securitySchemes.get(securitySchemeName).bearerFormat; + if (JWT.equalsIgnoreCase(guardType)) + { + result.put(securitySchemeName, guardType); + } } } } diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientFactory.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientFactory.java index c28f3272fb..c20529c828 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientFactory.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientFactory.java @@ -199,19 +199,6 @@ private final class OpenapiStream private int state; - private long replyBudgetId; - - private long initialSeq; - private long initialAck; - private int initialMax; - - private long replySeq; - private long replyAck; - private int replyMax; - private int replyPad; - private long replyBud; - private int replyCap; - private OpenapiStream( MessageConsumer sender, long originId, @@ -279,21 +266,16 @@ private void onOpenapiBegin( { final long sequence = begin.sequence(); final long acknowledge = begin.acknowledge(); + final int maximum = begin.maximum(); final long traceId = begin.traceId(); final OctetsFW extension = begin.extension(); final OpenapiBeginExFW openapiBeginEx = extension.get(openapiBeginExRO::tryWrap); assert acknowledge <= sequence; - assert sequence >= initialSeq; - assert acknowledge >= initialAck; - initialSeq = sequence; - initialAck = acknowledge; state = OpenapiState.openingInitial(state); - assert initialAck <= initialSeq; - - http.doHttpBegin(traceId, openapiBeginEx.extension()); + http.doHttpBegin(sequence, acknowledge, maximum, traceId, affinity, openapiBeginEx.extension()); } private void onOpenapiData( @@ -301,6 +283,7 @@ private void onOpenapiData( { final long sequence = data.sequence(); final long acknowledge = data.acknowledge(); + final int maximum = data.maximum(); final long traceId = data.traceId(); final long authorization = data.authorization(); final long budgetId = data.budgetId(); @@ -310,13 +293,9 @@ private void onOpenapiData( final OctetsFW extension = data.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - - initialSeq = sequence + reserved; - - assert initialAck <= initialSeq; - http.doHttpData(traceId, authorization, budgetId, reserved, flags, payload, extension); + http.doHttpData(sequence, acknowledge, maximum, traceId, authorization, + budgetId, reserved, flags, payload, extension); } private void onOpenapiEnd( @@ -324,18 +303,15 @@ private void onOpenapiEnd( { final long sequence = end.sequence(); final long acknowledge = end.acknowledge(); + final int maximum = end.maximum(); final long traceId = end.traceId(); final OctetsFW extension = end.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - initialSeq = sequence; state = OpenapiState.closeInitial(state); - assert initialAck <= initialSeq; - - http.doHttpEnd(traceId, extension); + http.doHttpEnd(sequence, acknowledge, maximum, traceId, extension); } private void onOpenapiFlush( @@ -343,18 +319,15 @@ private void onOpenapiFlush( { final long sequence = flush.sequence(); final long acknowledge = flush.acknowledge(); + final int maximum = flush.maximum(); final long traceId = flush.traceId(); + final long budgetId = flush.budgetId(); final int reserved = flush.reserved(); final OctetsFW extension = flush.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - - initialSeq = sequence + reserved; - - assert initialAck <= initialSeq; - http.doHttpFlush(traceId, reserved, extension); + http.doHttpFlush(sequence, acknowledge, maximum, traceId, budgetId, reserved, extension); } private void onOpenapiAbort( @@ -362,18 +335,15 @@ private void onOpenapiAbort( { final long sequence = abort.sequence(); final long acknowledge = abort.acknowledge(); + final int maximum = abort.maximum(); final long traceId = abort.traceId(); final OctetsFW extension = abort.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - initialSeq = sequence; state = OpenapiState.closeInitial(state); - assert initialAck <= initialSeq; - - http.doHttpAbort(traceId, extension); + http.doHttpAbort(sequence, acknowledge, maximum, traceId, extension); } private void onOpenapiReset( @@ -385,17 +355,10 @@ private void onOpenapiReset( final long traceId = reset.traceId(); assert acknowledge <= sequence; - assert sequence <= replySeq; - assert acknowledge >= replyAck; - assert maximum >= replyMax; - replyAck = acknowledge; - replyMax = maximum; state = OpenapiState.closeReply(state); - assert replyAck <= replySeq; - - cleanup(traceId); + http.doHttpReset(sequence, acknowledge, maximum, traceId); } private void onOpenapiWindow( @@ -407,26 +370,18 @@ private void onOpenapiWindow( final long traceId = window.traceId(); final long budgetId = window.budgetId(); final int padding = window.padding(); - final int capabilities = window.capabilities(); assert acknowledge <= sequence; - assert sequence <= replySeq; - assert acknowledge >= replyAck; - assert maximum >= replyMax; - - replyAck = acknowledge; - replyMax = maximum; - replyBud = budgetId; - replyPad = padding; - replyCap = capabilities; - state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; + state = OpenapiState.closingReply(state); - http.doHttpWindow(traceId, acknowledge, budgetId, padding); + http.doHttpWindow(sequence, acknowledge, maximum, traceId, acknowledge, budgetId, padding); } private void doOpenapiBegin( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { @@ -439,41 +394,50 @@ private void doOpenapiBegin( .extension(extension) .build(); - doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doBegin(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, affinity, openBeginEx); } private void doOpenapiData( + long sequence, + long acknowledge, + int maximum, long traceId, + long replyBudgetId, int flag, int reserved, OctetsFW payload, Flyweight extension) { - doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, - traceId, authorization, replyBudgetId, flag, reserved, payload, extension); + doData(sender, originId, routedId, replyId, sequence, acknowledge, maximum, + traceId, authorization, replyBudgetId, flag, reserved, payload, extension); - replySeq += reserved; + sequence += reserved; } private void doOpenapiFlush( + long sequence, + long acknowledge, + int maximum, long traceId, + long replyBudgetId, int reserved, OctetsFW extension) { - doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doFlush(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, replyBudgetId, reserved, extension); - - replySeq += reserved; } private void doOpenapiEnd( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (OpenapiState.replyOpening(state) && !OpenapiState.replyClosed(state)) { - doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doEnd(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, extension); } @@ -481,11 +445,14 @@ private void doOpenapiEnd( } private void doOpenapiAbort( + long sequence, + long acknowledge, + int maximum, long traceId) { if (OpenapiState.replyOpening(state) && !OpenapiState.replyClosed(state)) { - doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doAbort(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); } @@ -493,38 +460,32 @@ private void doOpenapiAbort( } private void doOpenapiReset( + long sequence, + long acknowledge, + int maximum, long traceId) { if (!OpenapiState.initialClosed(state)) { state = OpenapiState.closeInitial(state); - doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doReset(sender, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); } } private void doOpenapiWindow( + long sequence, + long acknowledge, + int maximum, long authorization, long traceId, long budgetId, int padding) { - initialAck = http.initialAck; - initialMax = http.initialMax; - - doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doWindow(sender, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, budgetId, padding); } - - private void cleanup( - long traceId) - { - doOpenapiReset(traceId); - doOpenapiAbort(traceId); - - http.cleanup(traceId); - } } private final class HttpStream @@ -540,15 +501,6 @@ private final class HttpStream private MessageConsumer receiver; private int state; - private long initialSeq; - private long initialAck; - private int initialMax; - private long initialBud; - - private long replySeq; - private long replyAck; - private int replyMax; - private HttpStream( OpenapiStream delegate, long originId, @@ -608,12 +560,15 @@ private void onHttpMessage( private void onHttpBegin( BeginFW begin) { + final long sequence = begin.sequence(); + final long acknowledge = begin.acknowledge(); + final int maximum = begin.maximum(); final long traceId = begin.traceId(); final OctetsFW extension = begin.extension(); state = OpenapiState.openingReply(state); - delegate.doOpenapiBegin(traceId, extension); + delegate.doOpenapiBegin(sequence, acknowledge, maximum, traceId, extension); } private void onHttpData( @@ -621,21 +576,18 @@ private void onHttpData( { final long sequence = data.sequence(); final long acknowledge = data.acknowledge(); + final int maximum = data.maximum(); final long traceId = data.traceId(); + final long budgetId = data.budgetId(); final int flags = data.flags(); final int reserved = data.reserved(); final OctetsFW payload = data.payload(); final OctetsFW extension = data.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - - replySeq = sequence + reserved; - - assert replyAck <= replySeq; - assert replySeq <= replyAck + replyMax; - delegate.doOpenapiData(traceId, flags, reserved, payload, extension); + delegate.doOpenapiData(sequence, acknowledge, maximum, traceId, budgetId, + flags, reserved, payload, extension); } private void onHttpFlush( @@ -643,19 +595,15 @@ private void onHttpFlush( { final long sequence = flush.sequence(); final long acknowledge = flush.acknowledge(); + final int maximum = flush.maximum(); final long traceId = flush.traceId(); + final long budgetId = flush.budgetId(); final int reserved = flush.reserved(); final OctetsFW extension = flush.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence + reserved; - - assert replyAck <= replySeq; - assert replySeq <= replyAck + replyMax; - - delegate.doOpenapiFlush(traceId, reserved, extension); + delegate.doOpenapiFlush(sequence, acknowledge, maximum, traceId, budgetId, reserved, extension); } private void onHttpEnd( @@ -663,18 +611,15 @@ private void onHttpEnd( { final long sequence = end.sequence(); final long acknowledge = end.acknowledge(); + final int maximum = end.maximum(); final long traceId = end.traceId(); final OctetsFW extension = end.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence; state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; - - delegate.doOpenapiEnd(traceId, extension); + delegate.doOpenapiEnd(sequence, acknowledge, maximum, traceId, extension); } private void onHttpAbort( @@ -682,17 +627,14 @@ private void onHttpAbort( { final long sequence = abort.sequence(); final long acknowledge = abort.acknowledge(); + final int maximum = abort.maximum(); final long traceId = abort.traceId(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence; state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; - - delegate.doOpenapiAbort(traceId); + delegate.doOpenapiAbort(sequence, acknowledge, maximum, traceId); } private void onHttpReset( @@ -700,17 +642,14 @@ private void onHttpReset( { final long sequence = reset.sequence(); final long acknowledge = reset.acknowledge(); + final int maximum = reset.maximum(); final long traceId = reset.traceId(); assert acknowledge <= sequence; - assert acknowledge >= delegate.initialAck; - delegate.initialAck = acknowledge; state = OpenapiState.closeInitial(state); - assert delegate.initialAck <= delegate.initialSeq; - - delegate.doOpenapiReset(traceId); + delegate.doOpenapiReset(sequence, acknowledge, maximum, traceId); } private void onHttpWindow( @@ -725,34 +664,35 @@ private void onHttpWindow( final int padding = window.padding(); assert acknowledge <= sequence; - assert acknowledge >= delegate.initialAck; - assert maximum >= delegate.initialMax; - initialAck = acknowledge; - initialMax = maximum; - initialBud = budgetId; state = OpenapiState.openingInitial(state); - assert initialAck <= initialSeq; - - delegate.doOpenapiWindow(authorization, traceId, budgetId, padding); + delegate.doOpenapiWindow(sequence, acknowledge, maximum, + authorization, traceId, budgetId, padding); } private void doHttpBegin( + long sequence, + long acknowledge, + int maximum, long traceId, + long affinity, OctetsFW extension) { if (!OpenapiState.initialOpening(state)) { assert state == 0; - this.receiver = newStream(this::onHttpMessage, originId, routedId, initialId, initialSeq, - initialAck, initialMax, traceId, authorization, 0L, extension); + this.receiver = newStream(this::onHttpMessage, originId, routedId, initialId, sequence, + acknowledge, maximum, traceId, authorization, affinity, extension); state = OpenapiState.openingInitial(state); } } private void doHttpData( + long sequence, + long acknowledge, + int maximum, long traceId, long authorization, long budgetId, @@ -761,34 +701,37 @@ private void doHttpData( OctetsFW payload, Flyweight extension) { - doData(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doData(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, budgetId, flags, reserved, payload, extension); - - initialSeq += reserved; - - assert initialSeq <= initialAck + initialMax; } private void doHttpFlush( + long sequence, + long acknowledge, + int maximum, long traceId, + long initialBud, int reserved, OctetsFW extension) { - doFlush(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doFlush(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, initialBud, reserved, extension); - initialSeq += reserved; + sequence += reserved; - assert initialSeq <= initialAck + initialMax; + assert sequence <= acknowledge + maximum; } private void doHttpEnd( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (!OpenapiState.initialClosed(state)) { - doEnd(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doEnd(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, extension); state = OpenapiState.closeInitial(state); @@ -796,12 +739,15 @@ private void doHttpEnd( } private void doHttpAbort( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (!OpenapiState.initialClosed(state)) { - doAbort(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doAbort(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, extension); state = OpenapiState.closeInitial(state); @@ -809,11 +755,14 @@ private void doHttpAbort( } private void doHttpReset( + long sequence, + long acknowledge, + int maximum, long traceId) { if (!OpenapiState.replyClosed(state)) { - doReset(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax, + doReset(receiver, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); state = OpenapiState.closeReply(state); @@ -821,24 +770,17 @@ private void doHttpReset( } private void doHttpWindow( + long sequence, + long acknowledge, + int maximum, long traceId, long authorization, long budgetId, int padding) { - replyAck = Math.max(delegate.replyAck - padding, 0); - replyMax = delegate.replyMax; - - doWindow(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax, + doWindow(receiver, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, budgetId, padding); } - - private void cleanup( - long traceId) - { - doHttpAbort(traceId, EMPTY_OCTETS); - doHttpReset(traceId); - } } private MessageConsumer newStream( diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerFactory.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerFactory.java index 7f0cabcdee..59698a3461 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerFactory.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerFactory.java @@ -201,17 +201,6 @@ private final class HttpStream private int state; - private long replyBudgetId; - - private long initialSeq; - private long initialAck; - private int initialMax; - - private long replySeq; - private long replyAck; - private int replyMax; - private int replyPad; - private HttpStream( MessageConsumer sender, long originId, @@ -279,22 +268,16 @@ private void onHttpBegin( { final long sequence = begin.sequence(); final long acknowledge = begin.acknowledge(); + final int maximum = begin.maximum(); final long traceId = begin.traceId(); - final long authorization = begin.authorization(); final long affinity = begin.affinity(); final OctetsFW extension = begin.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - assert acknowledge >= initialAck; - initialSeq = sequence; - initialAck = acknowledge; state = OpenapiState.openingInitial(state); - assert initialAck <= initialSeq; - - openapi.doOpenapiBegin(traceId, extension); + openapi.doOpenapiBegin(sequence, acknowledge, maximum, traceId, affinity, extension); } private void onHttpData( @@ -302,6 +285,7 @@ private void onHttpData( { final long sequence = data.sequence(); final long acknowledge = data.acknowledge(); + final int maximum = data.maximum(); final long traceId = data.traceId(); final long authorization = data.authorization(); final long budgetId = data.budgetId(); @@ -311,13 +295,9 @@ private void onHttpData( final OctetsFW extension = data.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - - initialSeq = sequence + reserved; - - assert initialAck <= initialSeq; - openapi.doOpenapiData(traceId, authorization, budgetId, reserved, flags, payload, extension); + openapi.doOpenapiData(sequence, acknowledge, maximum, traceId, authorization, budgetId, + reserved, flags, payload, extension); } private void onHttpEnd( @@ -325,18 +305,15 @@ private void onHttpEnd( { final long sequence = end.sequence(); final long acknowledge = end.acknowledge(); + final int maximum = end.maximum(); final long traceId = end.traceId(); final OctetsFW extension = end.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - initialSeq = sequence; state = OpenapiState.closeInitial(state); - assert initialAck <= initialSeq; - - openapi.doOpenapiEnd(traceId, extension); + openapi.doOpenapiEnd(sequence, acknowledge, maximum, traceId, extension); } private void onHttpFlush( @@ -344,18 +321,15 @@ private void onHttpFlush( { final long sequence = flush.sequence(); final long acknowledge = flush.acknowledge(); + final int maximum = flush.maximum(); final long traceId = flush.traceId(); + final long budgetId = flush.budgetId(); final int reserved = flush.reserved(); final OctetsFW extension = flush.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - - initialSeq = sequence + reserved; - - assert initialAck <= initialSeq; - openapi.doOpenapiFlush(traceId, reserved, extension); + openapi.doOpenapiFlush(sequence, acknowledge, maximum, traceId, budgetId, reserved, extension); } private void onHttpAbort( @@ -363,18 +337,15 @@ private void onHttpAbort( { final long sequence = abort.sequence(); final long acknowledge = abort.acknowledge(); + final int maximum = abort.maximum(); final long traceId = abort.traceId(); final OctetsFW extension = abort.extension(); assert acknowledge <= sequence; - assert sequence >= initialSeq; - initialSeq = sequence; state = OpenapiState.closeInitial(state); - assert initialAck <= initialSeq; - - openapi.doOpenapiAbort(traceId, extension); + openapi.doOpenapiAbort(sequence, acknowledge, maximum, traceId, extension); } private void onHttpReset( @@ -386,17 +357,10 @@ private void onHttpReset( final long traceId = reset.traceId(); assert acknowledge <= sequence; - assert sequence <= replySeq; - assert acknowledge >= replyAck; - assert maximum >= replyMax; - replyAck = acknowledge; - replyMax = maximum; state = OpenapiState.closeReply(state); - assert replyAck <= replySeq; - - cleanup(traceId); + openapi.doOpenapiReset(sequence, acknowledge, maximum, traceId); } private void onHttpWindow( @@ -406,65 +370,68 @@ private void onHttpWindow( final long acknowledge = window.acknowledge(); final int maximum = window.maximum(); final long traceId = window.traceId(); + final long authorization = window.authorization(); final long budgetId = window.budgetId(); final int padding = window.padding(); assert acknowledge <= sequence; - assert sequence <= replySeq; - assert acknowledge >= replyAck; - assert maximum >= replyMax; - replyAck = acknowledge; - replyMax = maximum; - replyPad = padding; state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; - - openapi.doOpenapiWindow(traceId, acknowledge, budgetId, padding); + openapi.doOpenapiWindow(sequence, acknowledge, maximum, traceId, authorization, budgetId, padding); } private void doHttpBegin( long traceId, + long sequence, + long acknowledge, + int maximum, OctetsFW extension) { state = OpenapiState.openingReply(state); - doBegin(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doBegin(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, affinity, extension); } private void doHttpData( + long sequence, + long acknowledge, + int maximum, long traceId, int flag, int reserved, + long replyBudgetId, OctetsFW payload, Flyweight extension) { - doData(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doData(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, replyBudgetId, flag, reserved, payload, extension); - - replySeq += reserved; } private void doHttpFlush( long traceId, + long replyBudgetId, + long sequence, + long acknowledge, + int maximum, int reserved, OctetsFW extension) { - doFlush(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doFlush(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, replyBudgetId, reserved, extension); - - replySeq += reserved; } private void doHttpEnd( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (OpenapiState.replyOpening(state) && !OpenapiState.replyClosed(state)) { - doEnd(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doEnd(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, extension); } @@ -472,11 +439,14 @@ private void doHttpEnd( } private void doHttpAbort( + long sequence, + long acknowledge, + int maximum, long traceId) { if (OpenapiState.replyOpening(state) && !OpenapiState.replyClosed(state)) { - doAbort(sender, originId, routedId, replyId, replySeq, replyAck, replyMax, + doAbort(sender, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); } @@ -484,38 +454,32 @@ private void doHttpAbort( } private void doHttpReset( + long sequence, + long acknowledge, + int maximum, long traceId) { if (!OpenapiState.initialClosed(state)) { state = OpenapiState.closeInitial(state); - doReset(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doReset(sender, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); } } private void doHttpWindow( + long sequence, + long acknowledge, + int maximum, long authorization, long traceId, long budgetId, int padding) { - initialAck = openapi.initialAck; - initialMax = openapi.initialMax; - - doWindow(sender, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doWindow(sender, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, budgetId, padding); } - - private void cleanup( - long traceId) - { - doHttpReset(traceId); - doHttpAbort(traceId); - - openapi.cleanup(traceId); - } } private final class OpenapiStream @@ -533,16 +497,6 @@ private final class OpenapiStream private int state; - private long initialSeq; - private long initialAck; - private int initialMax; - private long initialBud; - - private long replySeq; - private long replyAck; - private int replyMax; - private int replyPad; - private OpenapiStream( HttpStream delegate, long originId, @@ -607,13 +561,16 @@ private void onOpenapiBegin( BeginFW begin) { final long traceId = begin.traceId(); + final long sequence = begin.sequence(); + final long acknowledge = begin.acknowledge(); + final int maximum = begin.maximum(); final OctetsFW extension = begin.extension(); state = OpenapiState.openingReply(state); final OpenapiBeginExFW openapiBeginEx = extension.get(openapiBeginExRO::tryWrap); - delegate.doHttpBegin(traceId, openapiBeginEx.extension()); + delegate.doHttpBegin(traceId, sequence, acknowledge, maximum, openapiBeginEx.extension()); } private void onOpenapiData( @@ -621,41 +578,33 @@ private void onOpenapiData( { final long sequence = data.sequence(); final long acknowledge = data.acknowledge(); + final int maximum = data.maximum(); final long traceId = data.traceId(); final int flags = data.flags(); + final long budgetId = data.budgetId(); final int reserved = data.reserved(); final OctetsFW payload = data.payload(); final OctetsFW extension = data.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - - replySeq = sequence + reserved; - - assert replyAck <= replySeq; - assert replySeq <= replyAck + replyMax; - delegate.doHttpData(traceId, flags, reserved, payload, extension); + delegate.doHttpData(sequence, acknowledge, maximum, traceId, flags, reserved, budgetId, payload, extension); } private void onOpenapiFlush( FlushFW flush) { + final long budgetId = flush.budgetId(); final long sequence = flush.sequence(); final long acknowledge = flush.acknowledge(); + final int maximum = flush.maximum(); final long traceId = flush.traceId(); final int reserved = flush.reserved(); final OctetsFW extension = flush.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence + reserved; - - assert replyAck <= replySeq; - assert replySeq <= replyAck + replyMax; - - delegate.doHttpFlush(traceId, reserved, extension); + delegate.doHttpFlush(traceId, budgetId, sequence, acknowledge, maximum, reserved, extension); } private void onOpenapiEnd( @@ -663,18 +612,15 @@ private void onOpenapiEnd( { final long sequence = end.sequence(); final long acknowledge = end.acknowledge(); + final int maximum = end.maximum(); final long traceId = end.traceId(); final OctetsFW extension = end.extension(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence; state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; - - delegate.doHttpEnd(traceId, extension); + delegate.doHttpEnd(sequence, acknowledge, maximum, traceId, extension); } private void onOpenapiAbort( @@ -682,17 +628,14 @@ private void onOpenapiAbort( { final long sequence = abort.sequence(); final long acknowledge = abort.acknowledge(); + final int maximum = abort.maximum(); final long traceId = abort.traceId(); assert acknowledge <= sequence; - assert sequence >= replySeq; - replySeq = sequence; state = OpenapiState.closingReply(state); - assert replyAck <= replySeq; - - delegate.doHttpAbort(traceId); + delegate.doHttpAbort(sequence, acknowledge, maximum, traceId); } private void onOpenapiReset( @@ -700,17 +643,14 @@ private void onOpenapiReset( { final long sequence = reset.sequence(); final long acknowledge = reset.acknowledge(); + final int maximum = reset.maximum(); final long traceId = reset.traceId(); assert acknowledge <= sequence; - assert acknowledge >= delegate.initialAck; - delegate.initialAck = acknowledge; state = OpenapiState.closeInitial(state); - assert delegate.initialAck <= delegate.initialSeq; - - delegate.doHttpReset(traceId); + delegate.doHttpReset(sequence, acknowledge, maximum, traceId); } @@ -726,21 +666,18 @@ private void onOpenapiWindow( final int padding = window.padding(); assert acknowledge <= sequence; - assert acknowledge >= delegate.initialAck; - assert maximum >= delegate.initialMax; - initialAck = acknowledge; - initialMax = maximum; - initialBud = budgetId; state = OpenapiState.openInitial(state); - assert initialAck <= initialSeq; - - delegate.doHttpWindow(authorization, traceId, budgetId, padding); + delegate.doHttpWindow(sequence, acknowledge, maximum, authorization, traceId, budgetId, padding); } private void doOpenapiBegin( + long sequence, + long acknowledge, + int maximum, long traceId, + long affinity, OctetsFW extension) { if (!OpenapiState.initialOpening(state)) @@ -755,13 +692,16 @@ private void doOpenapiBegin( .extension(extension) .build(); - this.receiver = newStream(this::onOpenapiMessage, originId, routedId, initialId, initialSeq, - initialAck, initialMax, traceId, authorization, 0L, openapiBeginEx); + this.receiver = newStream(this::onOpenapiMessage, originId, routedId, initialId, sequence, + acknowledge, maximum, traceId, authorization, affinity, openapiBeginEx); state = OpenapiState.openingInitial(state); } } private void doOpenapiData( + long sequence, + long acknowledge, + int maximum, long traceId, long authorization, long budgetId, @@ -770,34 +710,37 @@ private void doOpenapiData( OctetsFW payload, Flyweight extension) { - doData(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doData(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, budgetId, flags, reserved, payload, extension); - - initialSeq += reserved; - - assert initialSeq <= initialAck + initialMax; } private void doOpenapiFlush( + long sequence, + long acknowledge, + int maximum, long traceId, + long initialBud, int reserved, OctetsFW extension) { - doFlush(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doFlush(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, initialBud, reserved, extension); - initialSeq += reserved; + sequence += reserved; - assert initialSeq <= initialAck + initialMax; + assert sequence <= acknowledge + maximum; } private void doOpenapiEnd( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (!OpenapiState.initialClosed(state)) { - doEnd(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doEnd(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, extension); state = OpenapiState.closeInitial(state); @@ -805,12 +748,15 @@ private void doOpenapiEnd( } private void doOpenapiAbort( + long sequence, + long acknowledge, + int maximum, long traceId, OctetsFW extension) { if (!OpenapiState.initialClosed(state)) { - doAbort(receiver, originId, routedId, initialId, initialSeq, initialAck, initialMax, + doAbort(receiver, originId, routedId, initialId, sequence, acknowledge, maximum, traceId, authorization, extension); state = OpenapiState.closeInitial(state); @@ -818,11 +764,14 @@ private void doOpenapiAbort( } private void doOpenapiReset( + long sequence, + long acknowledge, + int maximum, long traceId) { if (!OpenapiState.replyClosed(state)) { - doReset(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax, + doReset(receiver, originId, routedId, replyId, sequence, acknowledge, maximum, traceId, authorization, EMPTY_OCTETS); state = OpenapiState.closeReply(state); @@ -830,23 +779,16 @@ private void doOpenapiReset( } private void doOpenapiWindow( + long sequence, + long acknowledge, + int maximum, long traceId, long authorization, long budgetId, int padding) { - replyAck = Math.max(delegate.replyAck - replyPad, 0); - replyMax = delegate.replyMax; - - doWindow(receiver, originId, routedId, replyId, replySeq, replyAck, replyMax, - traceId, authorization, budgetId, padding + replyPad); - } - - private void cleanup( - long traceId) - { - doOpenapiAbort(traceId, EMPTY_OCTETS); - doOpenapiReset(traceId); + doWindow(receiver, originId, routedId, replyId, sequence, acknowledge, maximum, + traceId, authorization, budgetId, padding); } } diff --git a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/view/OpenapiServerView.java b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/view/OpenapiServerView.java index 6d3d674e47..651cfd2b38 100644 --- a/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/view/OpenapiServerView.java +++ b/runtime/binding-openapi/src/main/java/io/aklivity/zilla/runtime/binding/openapi/internal/view/OpenapiServerView.java @@ -39,6 +39,11 @@ public URI url() return URI.create(server.url); } + public int getPort() + { + return URI.create(server.url).getPort(); + } + public void resolveURL( String url) { diff --git a/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientIT.java b/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientIT.java index db61283ebf..3a2ffd74da 100644 --- a/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientIT.java +++ b/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiClientIT.java @@ -62,4 +62,16 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Configuration("client.multiple.specs.yaml") + @Specification({ + "${openapi}/create.pet.and.item/client", + "${http}/create.pet.and.item/server" + }) + @ScriptProperty("serverAddress \"zilla://streams/http0\"") + @Configure(name = OPENAPI_TARGET_ROUTE_ID_NAME, value = "4294967298") + public void shouldCreatePetAndItem() throws Exception + { + k3po.finish(); + } } diff --git a/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerIT.java b/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerIT.java index 2e5193c8bf..4b22c9fdac 100644 --- a/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerIT.java +++ b/runtime/binding-openapi/src/test/java/io/aklivity/zilla/runtime/binding/openapi/internal/streams/OpenapiServerIT.java @@ -57,6 +57,17 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Configuration("server.multiple.specs.yaml") + @Specification({ + "${http}/create.pet.and.item/client", + "${openapi}/create.pet.and.item/server" + }) + public void shouldCreatePetAndItem() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server-secure.yaml") @Specification({ diff --git a/runtime/binding-proxy/pom.xml b/runtime/binding-proxy/pom.xml index cb79d828e5..2a43ec7ada 100644 --- a/runtime/binding-proxy/pom.xml +++ b/runtime/binding-proxy/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-sse-kafka/pom.xml b/runtime/binding-sse-kafka/pom.xml index ff2e94c7df..e10e0f1cbb 100644 --- a/runtime/binding-sse-kafka/pom.xml +++ b/runtime/binding-sse-kafka/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-sse/pom.xml b/runtime/binding-sse/pom.xml index 1e8ebfb0c1..6ce520ed4c 100644 --- a/runtime/binding-sse/pom.xml +++ b/runtime/binding-sse/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-sse/src/main/java/io/aklivity/zilla/runtime/binding/sse/internal/stream/SseServerFactory.java b/runtime/binding-sse/src/main/java/io/aklivity/zilla/runtime/binding/sse/internal/stream/SseServerFactory.java index ae4827c9ee..58534d31c3 100644 --- a/runtime/binding-sse/src/main/java/io/aklivity/zilla/runtime/binding/sse/internal/stream/SseServerFactory.java +++ b/runtime/binding-sse/src/main/java/io/aklivity/zilla/runtime/binding/sse/internal/stream/SseServerFactory.java @@ -478,9 +478,7 @@ private void onNetReset( final long authorization = reset.authorization(); assert acknowledge <= sequence; - assert sequence <= httpReplySeq; assert acknowledge >= httpReplyAck; - assert maximum >= httpReplyMax; httpReplyAck = acknowledge; httpReplyMax = maximum; diff --git a/runtime/binding-tcp/pom.xml b/runtime/binding-tcp/pom.xml index 9416520a76..257d543a7b 100644 --- a/runtime/binding-tcp/pom.xml +++ b/runtime/binding-tcp/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/SocketChannelHelper.java b/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/SocketChannelHelper.java index e90faadc27..8d45c4da61 100644 --- a/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/SocketChannelHelper.java +++ b/runtime/binding-tcp/src/test/java/io/aklivity/zilla/runtime/binding/tcp/internal/SocketChannelHelper.java @@ -104,7 +104,7 @@ public static void initialize(CountDownLatch latch) } - private static class Rule implements TestRule + private static final class Rule implements TestRule { @Override public Statement apply(Statement base, Description description) diff --git a/runtime/binding-tls/NOTICE b/runtime/binding-tls/NOTICE index 08323b88fb..b894dd7e66 100644 --- a/runtime/binding-tls/NOTICE +++ b/runtime/binding-tls/NOTICE @@ -12,6 +12,18 @@ specific language governing permissions and limitations under the License. This project includes: + agrona under The Apache License, Version 2.0 + ICU4J under Unicode/ICU License + Jackson-annotations under The Apache Software License, Version 2.0 + Jackson-core under The Apache Software License, Version 2.0 + jackson-databind under The Apache Software License, Version 2.0 + Jackson-dataformat-YAML under The Apache Software License, Version 2.0 + Jakarta JSON Processing API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception + JSON-B API under Eclipse Public License 2.0 or GNU General Public License, version 2 with the GNU Classpath Exception + org.leadpony.justify under The Apache Software License, Version 2.0 + SnakeYAML under Apache License, Version 2.0 + zilla::runtime::common under The Apache Software License, Version 2.0 + zilla::runtime::engine under The Apache Software License, Version 2.0 This project also includes code under copyright of the following entities: diff --git a/runtime/binding-tls/pom.xml b/runtime/binding-tls/pom.xml index 8a7fc639b2..15c33e4f21 100644 --- a/runtime/binding-tls/pom.xml +++ b/runtime/binding-tls/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -41,7 +41,6 @@ ${project.groupId} engine ${project.version} - provided ${project.groupId} @@ -56,6 +55,12 @@ ${project.version} test + + ${project.groupId} + binding-echo + ${project.version} + test + junit junit @@ -241,6 +246,8 @@ org.agrona:agrona io.aklivity.zilla:engine + io.aklivity.zilla:common + io.aklivity.zilla:binding-echo org.openjdk.jmh:jmh-core net.sf.jopt-simple:jopt-simple org.apache.commons:commons-math3 diff --git a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsHandshakeBM.java b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsHandshakeBM.java new file mode 100644 index 0000000000..a1bcf842db --- /dev/null +++ b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsHandshakeBM.java @@ -0,0 +1,196 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tls.internal.bench; + +import static io.aklivity.zilla.runtime.engine.EngineConfiguration.ENGINE_CONFIG_URL; +import static io.aklivity.zilla.runtime.engine.config.KindConfig.CLIENT; +import static io.aklivity.zilla.runtime.engine.config.KindConfig.SERVER; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.net.URL; +import java.util.List; +import java.util.Properties; + +import org.agrona.MutableDirectBuffer; +import org.agrona.concurrent.UnsafeBuffer; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Control; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import io.aklivity.zilla.runtime.binding.tls.config.TlsOptionsConfig; +import io.aklivity.zilla.runtime.binding.tls.internal.types.stream.BeginFW; +import io.aklivity.zilla.runtime.binding.tls.internal.types.stream.WindowFW; +import io.aklivity.zilla.runtime.engine.EngineConfiguration; +import io.aklivity.zilla.runtime.engine.binding.BindingHandler; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; +import io.aklivity.zilla.runtime.vault.filesystem.config.FileSystemOptionsConfig; + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.Throughput) +@Fork(3) +@Warmup(iterations = 10, time = 1, timeUnit = SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = SECONDS) +@OutputTimeUnit(SECONDS) +public class TlsHandshakeBM +{ + private static final int BUFFER_SIZE = 1024 * 8; + + private final BeginFW.Builder beginRW = new BeginFW.Builder(); + private final WindowFW.Builder windowRW = new WindowFW.Builder(); + private final MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[BUFFER_SIZE]); + + private BindingHandler streamFactory; + private TlsWorker worker; + + @Setup(Level.Trial) + public void init() + { + final Properties properties = new Properties(); + URL configURL = TlsHandshakeBM.class.getClassLoader().getResource("io/aklivity/zilla/specs/binding/tls/config"); + properties.setProperty(ENGINE_CONFIG_URL.name(), String.format("%s/zilla.yaml", configURL.toString())); + final EngineConfiguration config = new EngineConfiguration(properties); + this.worker = new TlsWorker(config); + + NamespaceConfig namespace = NamespaceConfig.builder() + .name("tls") + .vault() + .name("server") + .type("filesystem") + .options(FileSystemOptionsConfig.builder() + .keys() + .store("stores/server/keys") + .type("pkcs12") + .password("generated") + .build() + .trust() + .store("stores/client/trust") + .type("pkcs12") + .password("generated") + .build() + .build()) + .build() + .binding() + .name("tls_client0") + .type("tls") + .kind(CLIENT) + .vault("server") + .options(TlsOptionsConfig.builder() + .trust(List.of("serverca")) + .sni(List.of("localhost")) + .build()) + .exit("tls_server0") + .build() + .binding() + .name("tls_server0") + .type("tls") + .kind(SERVER) + .vault("server") + .options(TlsOptionsConfig.builder() + .keys(List.of("localhost")) + .version("tls") + .build()) + .exit("echo_server0") + .build() + .binding() + .name("echo_server0") + .type("echo") + .kind(SERVER) + .build() + .build(); + + worker.attach(namespace); + + streamFactory = worker.streamFactory(); + } + + @TearDown(Level.Trial) + public void destroy() + { + } + + @Setup(Level.Iteration) + public void reset() + { + } + + @Benchmark + public void handshake( + final Control control) throws Exception + { + final long initialId = worker.supplyInitialId(0L); + final long replyId = worker.supplyReplyId(initialId); + + final BeginFW begin = beginRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) + .routedId(4261135416L) + .streamId(initialId) + .sequence(0L) + .acknowledge(0L) + .maximum(BUFFER_SIZE) + .traceId(0L) + .authorization(0L) + .affinity(0L) + .build(); + + MessageConsumer sender = MessageConsumer.NOOP; + MessageConsumer receiver = streamFactory.newStream( + begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof(), sender); + + receiver.accept(begin.typeId(), begin.buffer(), begin.offset(), begin.sizeof()); + + final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) + .routedId(4261135416L) + .streamId(replyId) + .sequence(0L) + .acknowledge(0L) + .maximum(BUFFER_SIZE) + .traceId(0L) + .budgetId(0L) + .padding(0) + .build(); + + receiver.accept(window.typeId(), window.buffer(), window.offset(), window.sizeof()); + + worker.doWork(); + } + + public static void main( + String[] args) throws RunnerException + { + Options opt = new OptionsBuilder() + .include(TlsHandshakeBM.class.getSimpleName()) + .forks(0) + .build(); + + new Runner(opt).run(); + } +} diff --git a/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsWorker.java b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsWorker.java new file mode 100644 index 0000000000..8f0ad77e20 --- /dev/null +++ b/runtime/binding-tls/src/test/java/io/aklivity/zilla/runtime/binding/tls/internal/bench/TlsWorker.java @@ -0,0 +1,728 @@ +/* + * Copyright 2021-2023 Aklivity Inc. + * + * Aklivity licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.aklivity.zilla.runtime.binding.tls.internal.bench; + +import static io.aklivity.zilla.runtime.engine.internal.stream.StreamId.isInitial; +import static java.lang.ThreadLocal.withInitial; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.agrona.LangUtil.rethrowUnchecked; + +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.channels.SelectableChannel; +import java.time.Clock; +import java.util.function.IntConsumer; +import java.util.function.LongSupplier; +import java.util.zip.CRC32C; + +import org.agrona.DirectBuffer; +import org.agrona.MutableDirectBuffer; +import org.agrona.collections.Long2ObjectHashMap; +import org.agrona.collections.Object2ObjectHashMap; +import org.agrona.concurrent.UnsafeBuffer; +import org.agrona.concurrent.ringbuffer.OneToOneRingBuffer; +import org.agrona.concurrent.ringbuffer.RingBuffer; + +import io.aklivity.zilla.runtime.engine.Configuration; +import io.aklivity.zilla.runtime.engine.EngineConfiguration; +import io.aklivity.zilla.runtime.engine.EngineContext; +import io.aklivity.zilla.runtime.engine.binding.Binding; +import io.aklivity.zilla.runtime.engine.binding.BindingContext; +import io.aklivity.zilla.runtime.engine.binding.BindingFactory; +import io.aklivity.zilla.runtime.engine.binding.BindingHandler; +import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; +import io.aklivity.zilla.runtime.engine.binding.function.MessageReader; +import io.aklivity.zilla.runtime.engine.budget.BudgetCreditor; +import io.aklivity.zilla.runtime.engine.budget.BudgetDebitor; +import io.aklivity.zilla.runtime.engine.buffer.BufferPool; +import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; +import io.aklivity.zilla.runtime.engine.concurrent.Signaler; +import io.aklivity.zilla.runtime.engine.config.BindingConfig; +import io.aklivity.zilla.runtime.engine.config.ModelConfig; +import io.aklivity.zilla.runtime.engine.config.NamespaceConfig; +import io.aklivity.zilla.runtime.engine.event.EventFormatter; +import io.aklivity.zilla.runtime.engine.guard.GuardHandler; +import io.aklivity.zilla.runtime.engine.internal.layouts.BufferPoolLayout; +import io.aklivity.zilla.runtime.engine.internal.stream.StreamId; +import io.aklivity.zilla.runtime.engine.internal.types.stream.BeginFW; +import io.aklivity.zilla.runtime.engine.internal.types.stream.FrameFW; +import io.aklivity.zilla.runtime.engine.internal.types.stream.SignalFW; +import io.aklivity.zilla.runtime.engine.metrics.Metric; +import io.aklivity.zilla.runtime.engine.model.ConverterHandler; +import io.aklivity.zilla.runtime.engine.model.ValidatorHandler; +import io.aklivity.zilla.runtime.engine.poller.PollerKey; +import io.aklivity.zilla.runtime.engine.vault.Vault; +import io.aklivity.zilla.runtime.engine.vault.VaultContext; +import io.aklivity.zilla.runtime.engine.vault.VaultFactory; +import io.aklivity.zilla.runtime.engine.vault.VaultHandler; + +public class TlsWorker implements EngineContext +{ + private static final int BUFFER_SIZE = 1024 * 64; + private final MutableDirectBuffer writeBuffer = new UnsafeBuffer(new byte[BUFFER_SIZE]); + private final RingBuffer streamsBuffer = new OneToOneRingBuffer(new UnsafeBuffer(new byte[1024 * 1024 + 768])); + private final BufferPool bufferPool; + private final Long2ObjectHashMap handlers; + private final Object2ObjectHashMap bindings; + private final Long2ObjectHashMap vaultHandlers; + private final Object2ObjectHashMap vaults; + private final Long2ObjectHashMap streamsById; + private final Long2ObjectHashMap throtllesById; + private final BindingFactory factory; + private final VaultFactory vaultFactory; + private final Configuration config; + private final URL configURL; + + private final TlsSignaler signaler; + + private final FrameFW frameRO = new FrameFW(); + private final CRC32C crc32C = new CRC32C(); + + private int nextInitialId = 3; + + public TlsWorker( + EngineConfiguration config) + { + this.config = config; + this.bufferPool = new BufferPoolLayout.Builder() + .path(config.directory().resolve(String.format("buffers%d", 0))) + .slotCapacity(config.bufferSlotCapacity()) + .slotCount(config.bufferPoolCapacity() / config.bufferSlotCapacity()) + .readonly(false) + .build() + .bufferPool(); + this.configURL = config.configURL(); + + this.signaler = new TlsSignaler(); + + this.factory = BindingFactory.instantiate(); + this.vaultFactory = VaultFactory.instantiate(); + this.bindings = new Object2ObjectHashMap<>(); + this.handlers = new Long2ObjectHashMap<>(); + this.vaultHandlers = new Long2ObjectHashMap<>(); + this.vaults = new Object2ObjectHashMap<>(); + this.streamsById = new Long2ObjectHashMap<>(); + this.throtllesById = new Long2ObjectHashMap<>(); + } + + @Override + public int index() + { + return 0; + } + + @Override + public Signaler signaler() + { + return signaler; + } + + @Override + public int supplyTypeId( + String name) + { + return 0; + } + + @Override + public long supplyInitialId( + long bindingId) + { + return nextInitialId += 2; + } + + @Override + public long supplyReplyId( + long initialId) + { + assert isInitial(initialId); + return initialId & 0xffff_ffff_ffff_fffeL; + } + + @Override + public long supplyPromiseId( + long initialId) + { + return 0; + } + + @Override + public long supplyAuthorizedId() + { + return 0; + } + + @Override + public long supplyBudgetId() + { + return 0; + } + + @Override + public long supplyTraceId() + { + return 0; + } + + @Override + public MessageConsumer supplySender( + long streamId) + { + return null; + } + + @Override + public MessageConsumer supplyReceiver( + long streamId) + { + return null; + } + + @Override + public EventFormatter supplyEventFormatter() + { + return null; + } + + @Override + public void attachComposite( + NamespaceConfig composite) + { + } + + @Override + public void detachComposite( + NamespaceConfig composite) + { + } + + @Override + public void detachSender(long replyId) + { + } + + @Override + public void detachStreams(long bindingId) + { + } + + @Override + public BudgetCreditor creditor() + { + return null; + } + + @Override + public BudgetDebitor supplyDebitor(long budgetId) + { + return null; + } + + @Override + public MutableDirectBuffer writeBuffer() + { + return writeBuffer; + } + + @Override + public BufferPool bufferPool() + { + return bufferPool; + } + + @Override + public LongSupplier supplyCounter( + long bindingId, + long metricId) + { + return null; + } + + @Override + public LongSupplier supplyGauge( + long bindingId, + long metricId) + { + return null; + } + + @Override + public LongSupplier[] supplyHistogram( + long bindingId, + long metricId) + { + return new LongSupplier[0]; + } + + @Override + public MessageConsumer droppedFrameHandler() + { + return null; + } + + @Override + public int supplyClientIndex( + long streamId) + { + return 0; + } + + @Override + public InetAddress[] resolveHost( + String host) + { + return new InetAddress[0]; + } + + @Override + public PollerKey supplyPollerKey( + SelectableChannel channel) + { + return null; + } + + @Override + public long supplyBindingId( + NamespaceConfig namespace, + BindingConfig binding) + { + return 0; + } + + @Override + public String supplyNamespace( + long namespacedId) + { + return ""; + } + + @Override + public String supplyLocalName( + long namespacedId) + { + return ""; + } + + @Override + public String supplyQName( + long namespacedId) + { + return ""; + } + + @Override + public int supplyEventId( + String name) + { + return 0; + } + + @Override + public BindingHandler streamFactory() + { + return this::newStream; + } + + @Override + public GuardHandler supplyGuard( + long guardId) + { + return null; + } + + @Override + public VaultHandler supplyVault( + long vaultId) + { + return vaultHandlers.get(vaultId); + } + + @Override + public CatalogHandler supplyCatalog( + long catalogId) + { + return null; + } + + @Override + public ValidatorHandler supplyValidator( + ModelConfig config) + { + return null; + } + + @Override + public ConverterHandler supplyReadConverter( + ModelConfig config) + { + return null; + } + + @Override + public ConverterHandler supplyWriteConverter( + ModelConfig config) + { + return null; + } + + @Override + public URL resolvePath( + String path) + { + URL resolved = null; + try + { + resolved = new URL(configURL, path); + } + catch (MalformedURLException ex) + { + rethrowUnchecked(ex); + } + return resolved; + } + + @Override + public Metric resolveMetric( + String name) + { + return null; + } + + @Override + public void onExporterAttached( + long exporterId) + { + + } + + @Override + public void onExporterDetached( + long exporterId) + { + + } + + @Override + public MessageConsumer supplyEventWriter() + { + return MessageConsumer.NOOP; + } + + @Override + public MessageReader supplyEventReader() + { + return null; + } + + @Override + public Clock clock() + { + return Clock.systemUTC(); + } + + public void doWork() + { + streamsBuffer.read(this::handleRead, Integer.MAX_VALUE); + } + + public void attach( + NamespaceConfig namespace) + { + namespace.vaults.forEach(v -> + { + Vault vault = supplyVault(v.type); + VaultContext context = vault.supply(this); + VaultHandler handler = context.attach(v); + + vaultHandlers.put(crc32c(v.name), handler); + }); + + namespace.bindings.stream() + .peek(b -> b.id = crc32c(b.name)) + .map(b -> b.routes) + .forEach(rs -> rs.stream() + .peek(r -> r.id = crc32c(r.exit)) + .forEach(r -> r.authorized = session -> true)); + + namespace.bindings.forEach(b -> + { + Binding binding = supplyBinding(b.type); + BindingContext context = binding.supply(this); + b.vaultId = b.vault != null ? crc32c(b.vault) : 0L; + BindingHandler handler = context.attach(b); + + handlers.put(b.id, handler); + }); + } + + private void handleRead( + int msgTypeId, + MutableDirectBuffer buffer, + int index, + int length) + { + final FrameFW frame = frameRO.wrap(buffer, index, index + length); + final long streamId = frame.streamId(); + + final MessageConsumer stream = StreamId.isThrottle(msgTypeId) + ? throtllesById.get(streamId) + : streamsById.get(streamId); + + stream.accept(msgTypeId, buffer, index, length); + } + + private MessageConsumer newStream( + int msgTypeId, + DirectBuffer buffer, + int index, + int length, + MessageConsumer sender) + { + switch (msgTypeId) + { + case BeginFW.TYPE_ID: + final FrameFW frame = frameRO.wrap(buffer, index, index + length); + final long routedId = frame.routedId(); + final long streamId = frame.streamId(); + + if (StreamId.isInitial(streamId)) + { + final BindingHandler handler = handlers.get(routedId); + MessageConsumer stream = handler.newStream(msgTypeId, buffer, index, length, this::handleWrite); + streamsById.put(streamId, stream); + throtllesById.put(streamId, sender); + + long replyId = supplyReplyId(streamId); + throtllesById.put(replyId, stream); + streamsById.put(replyId, sender); + } + break; + } + + return this::handleWrite; + } + + private void handleWrite( + int msgTypeId, + DirectBuffer buffer, + int index, + int length) + { + streamsBuffer.write(msgTypeId, buffer, index, length); + } + + private Binding supplyBinding( + String type) + { + return bindings.computeIfAbsent(type, this::createBinding); + } + + private Vault supplyVault( + String type) + { + return vaults.computeIfAbsent(type, this::createVault); + } + + private Vault createVault( + String type) + { + return vaultFactory.create(type, config); + } + + private Binding createBinding( + String type) + { + return factory.create(type, config); + } + + private long crc32c( + String value) + { + crc32C.reset(); + crc32C.update(value.getBytes(UTF_8)); + + return crc32C.getValue(); + } + + private static SignalFW.Builder newSignalRW( + int capacity) + { + MutableDirectBuffer buffer = new UnsafeBuffer(new byte[capacity]); + return new SignalFW.Builder().wrap(buffer, 0, buffer.capacity()); + } + + private final class TlsSignaler implements Signaler + { + private final ThreadLocal signalRW; + + private TlsSignaler() + { + signalRW = withInitial(() -> newSignalRW(512)); + } + + @Override + public long signalAt( + long timeMillis, + int signalId, + IntConsumer handler) + { + handler.accept(signalId); + + return NO_CANCEL_ID; + } + + @Override + public long signalAt( + long timeMillis, + long originId, + long routedId, + long streamId, + long traceId, + int signalId, + int contextId) + { + signal(originId, routedId, streamId, 0L, 0L, + traceId, NO_CANCEL_ID, signalId, contextId); + return NO_CANCEL_ID; + } + + @Override + public long signalTask( + Runnable task, + long originId, + long routedId, + long streamId, + long traceId, + int signalId, + int contextId) + { + try + { + task.run(); + } + finally + { + final SignalFW signal = signalRW.get() + .rewrap() + .originId(originId) + .routedId(routedId) + .streamId(streamId) + .sequence(0L) + .acknowledge(0L) + .maximum(0) + .timestamp(0L) + .traceId(traceId) + .cancelId(NO_CANCEL_ID) + .signalId(signalId) + .contextId(contextId) + .build(); + + streamsBuffer.write(signal.typeId(), signal.buffer(), signal.offset(), signal.sizeof()); + } + + return NO_CANCEL_ID; + } + + @Override + public void signalNow( + long originId, + long routedId, + long streamId, + long traceId, + int signalId, + int contextId) + { + signal(originId, routedId, streamId, 0L, 0L, traceId, NO_CANCEL_ID, signalId, contextId); + } + + @Override + public void signalNow( + long originId, + long routedId, + long streamId, + long traceId, + int signalId, + int contextId, + DirectBuffer buffer, + int offset, + int length) + { + signal(originId, routedId, streamId, 0L, 0L, traceId, NO_CANCEL_ID, signalId, contextId, + buffer, offset, length); + } + + @Override + public boolean cancel( + long cancelId) + { + return true; + } + + private void signal( + long originId, + long routedId, + long streamId, + long sequence, + long acknowledge, + long traceId, + long cancelId, + int signalId, + int contextId) + { + //NOOP + } + + private void signal( + long originId, + long routedId, + long streamId, + long sequence, + long acknowledge, + long traceId, + long cancelId, + int signalId, + int contextId, + DirectBuffer buffer, + int offset, + int length) + { + //NOOP + } + + private void invokeAndSignal( + Runnable task, + long originId, + long routedId, + long streamId, + long sequence, + long acknowledge, + long traceId, + long cancelId, + int signalId, + int contextId) + { + try + { + task.run(); + } + finally + { + signal(originId, routedId, streamId, sequence, acknowledge, traceId, cancelId, signalId, contextId); + } + } + } +} diff --git a/runtime/binding-ws/pom.xml b/runtime/binding-ws/pom.xml index 819018cc67..187ed53c85 100644 --- a/runtime/binding-ws/pom.xml +++ b/runtime/binding-ws/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/catalog-apicurio/pom.xml b/runtime/catalog-apicurio/pom.xml index 8eb963425d..0280b0799f 100644 --- a/runtime/catalog-apicurio/pom.xml +++ b/runtime/catalog-apicurio/pom.xml @@ -6,7 +6,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -24,7 +24,7 @@ 11 11 - 0.80 + 0.94 0 diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/ZillaConfigCommandSpi.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCache.java similarity index 53% rename from incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/ZillaConfigCommandSpi.java rename to runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCache.java index eb2b22b544..ad11660c6a 100644 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/ZillaConfigCommandSpi.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCache.java @@ -12,21 +12,20 @@ * WARRANTIES OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ -package io.aklivity.zilla.runtime.command.generate.internal; +package io.aklivity.zilla.runtime.catalog.apicurio.internal; -import com.github.rvesse.airline.builder.CliBuilder; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; -import io.aklivity.zilla.runtime.command.ZillaCommandSpi; -import io.aklivity.zilla.runtime.command.generate.internal.airline.ZillaConfigCommand; -import io.aklivity.zilla.runtime.common.feature.Incubating; - -@Incubating -public class ZillaConfigCommandSpi implements ZillaCommandSpi +public class ApicurioCache { - @Override - public void mixin( - CliBuilder builder) + public final ConcurrentMap> artifacts; + public final ConcurrentMap> artifactIds; + + public ApicurioCache() { - builder.withCommand(ZillaConfigCommand.class); + this.artifacts = new ConcurrentHashMap<>(); + this.artifactIds = new ConcurrentHashMap<>(); } } diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalog.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalog.java index 6530f67b65..dab082a1e4 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalog.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalog.java @@ -15,6 +15,8 @@ package io.aklivity.zilla.runtime.catalog.apicurio.internal; import java.net.URL; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import io.aklivity.zilla.runtime.engine.Configuration; import io.aklivity.zilla.runtime.engine.EngineContext; @@ -25,9 +27,12 @@ public class ApicurioCatalog implements Catalog { public static final String NAME = "apicurio"; + private final ConcurrentMap cache; + public ApicurioCatalog( Configuration config) { + this.cache = new ConcurrentHashMap<>(); } @Override @@ -40,7 +45,7 @@ public String name() public CatalogContext supply( EngineContext context) { - return new ApicurioCatalogContext(context); + return new ApicurioCatalogContext(context, cache); } @Override diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogContext.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogContext.java index ccc1750841..c1abd8e01d 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogContext.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogContext.java @@ -14,6 +14,8 @@ */ package io.aklivity.zilla.runtime.catalog.apicurio.internal; +import java.util.concurrent.ConcurrentMap; + import io.aklivity.zilla.runtime.catalog.apicurio.internal.config.ApicurioOptionsConfig; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.catalog.CatalogContext; @@ -23,17 +25,22 @@ public class ApicurioCatalogContext implements CatalogContext { private final EngineContext context; + private final ConcurrentMap cachesById; public ApicurioCatalogContext( - EngineContext context) + EngineContext context, + ConcurrentMap cachesById) { this.context = context; + this.cachesById = cachesById; } @Override public CatalogHandler attach( CatalogConfig catalog) { - return new ApicurioCatalogHandler(ApicurioOptionsConfig.class.cast(catalog.options), context, catalog.id); + ApicurioCache cache = cachesById.computeIfAbsent(catalog.id, id -> new ApicurioCache()); + return new ApicurioCatalogHandler(ApicurioOptionsConfig.class.cast(catalog.options), context, + catalog.id, cache); } } diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogHandler.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogHandler.java index 745d8561c6..f73ac4bb3b 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogHandler.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogHandler.java @@ -14,6 +14,7 @@ */ package io.aklivity.zilla.runtime.catalog.apicurio.internal; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.CachedArtifactId.IN_PROGRESS; import static io.aklivity.zilla.runtime.catalog.apicurio.internal.config.ApicurioOptionsConfigBuilder.CONTENT_ID; import static io.aklivity.zilla.runtime.catalog.apicurio.internal.config.ApicurioOptionsConfigBuilder.LEGACY_ID_ENCODING; import static org.agrona.BitUtil.SIZE_OF_BYTE; @@ -27,6 +28,9 @@ import java.net.http.HttpResponse; import java.nio.ByteOrder; import java.text.MessageFormat; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CRC32C; import jakarta.json.Json; @@ -53,6 +57,8 @@ public class ApicurioCatalogHandler implements CatalogHandler private static final String VERSION_LATEST = "latest"; private static final int MAX_PADDING_LENGTH = SIZE_OF_BYTE + SIZE_OF_LONG; private static final byte MAGIC_BYTE = 0x0; + private static final long RESET_RETRY_DELAY_MS_DEFAULT = 0L; + private static final long RETRY_INITIAL_DELAY_MS_DEFAULT = 1000L; private final ApicurioPrefixFW.Builder prefixRW = new ApicurioPrefixFW.Builder() .wrap(new UnsafeBuffer(new byte[5]), 0, 5); @@ -61,7 +67,7 @@ public class ApicurioCatalogHandler implements CatalogHandler private final String baseUrl; private final CRC32C crc32c; private final Int2ObjectCache artifacts; - private final Int2ObjectCache schemaIds; + private final Int2ObjectCache artifactIds; private final long maxAgeMillis; private final ApicurioEventContext event; private final long catalogId; @@ -70,17 +76,28 @@ public class ApicurioCatalogHandler implements CatalogHandler private final IdEncoder encodeId; private final int idSize; private final String artifactPath; + private final ConcurrentMap> cachedArtifacts; + private final ConcurrentMap> cachedArtifactIds; + public ApicurioCatalogHandler( ApicurioOptionsConfig config, EngineContext context, long catalogId) + { + this(config, context, catalogId, new ApicurioCache()); + } + public ApicurioCatalogHandler( + ApicurioOptionsConfig config, + EngineContext context, + long catalogId, + ApicurioCache cache) { this.baseUrl = config.url; this.client = HttpClient.newHttpClient(); this.crc32c = new CRC32C(); this.artifacts = new Int2ObjectCache<>(1, 1024, i -> {}); - this.schemaIds = new Int2ObjectCache<>(1, 1024, i -> {}); + this.artifactIds = new Int2ObjectCache<>(1, 1024, i -> {}); this.maxAgeMillis = config.maxAge.toMillis(); this.groupId = config.groupId; this.useId = config.useId; @@ -89,23 +106,83 @@ public ApicurioCatalogHandler( this.artifactPath = useId.equals(CONTENT_ID) ? ARTIFACT_BY_CONTENT_ID_PATH : ARTIFACT_BY_GLOBAL_ID_PATH; this.event = new ApicurioEventContext(context); this.catalogId = catalogId; + this.cachedArtifacts = cache.artifacts; + this.cachedArtifactIds = cache.artifactIds; } @Override public String resolve( - int schemaId) + int artifactId) { - String artifact; - if (artifacts.containsKey(schemaId)) + String artifact = null; + if (artifactId != NO_SCHEMA_ID) { - artifact = artifacts.get(schemaId); - } - else - { - artifact = sendHttpRequest(MessageFormat.format(artifactPath, schemaId)); - if (artifact != null) + if (artifacts.containsKey(artifactId)) + { + artifact = artifacts.get(artifactId); + } + else { - artifacts.put(schemaId, artifact); + AtomicInteger retryAttempts = new AtomicInteger(); + CompletableFuture newFuture = new CompletableFuture<>(); + CompletableFuture existing = cachedArtifacts.get(artifactId); + if (existing != null && existing.isDone()) + { + try + { + CachedArtifact cachedArtifact = existing.get(); + if (cachedArtifact != null) + { + retryAttempts = cachedArtifact.retryAttempts; + } + } + catch (Throwable ex) + { + existing.completeExceptionally(ex); + } + } + CompletableFuture future = cachedArtifacts.merge(artifactId, newFuture, (v1, v2) -> + v1.getNow(CachedArtifact.IN_PROGRESS).artifact == null ? v2 : v1); + if (future == newFuture) + { + try + { + artifact = sendHttpRequest(MessageFormat.format(artifactPath, artifactId)); + if (artifact == null) + { + if (retryAttempts.getAndIncrement() == 0) + { + event.onUnretrievableArtifactId(catalogId, artifactId); + } + newFuture.complete(new CachedArtifact(null, retryAttempts)); + } + else + { + if (retryAttempts.getAndSet(0) > 0) + { + event.onRetrievableArtifactId(catalogId, artifactId); + } + newFuture.complete(new CachedArtifact(artifact, retryAttempts)); + } + } + catch (Throwable ex) + { + newFuture.completeExceptionally(ex); + } + } + assert future != null; + try + { + artifact = future.get().artifact; + if (artifact != null) + { + artifacts.put(artifactId, artifact); + } + } + catch (Throwable ex) + { + future.completeExceptionally(ex); + } } } return artifact; @@ -116,27 +193,105 @@ public int resolve( String artifact, String version) { - int schemaId; + int artifactId = NO_SCHEMA_ID; - int checkSum = generateCRC32C(artifact, version); - if (schemaIds.containsKey(checkSum) && - (System.currentTimeMillis() - schemaIds.get(checkSum).timestamp) < maxAgeMillis) + int artifactKey = generateCRC32C(artifact, version); + if (artifactIds.containsKey(artifactKey) && !artifactIds.get(artifactKey).expired(maxAgeMillis)) { - schemaId = schemaIds.get(checkSum).id; + artifactId = artifactIds.get(artifactKey).id; } else { - String path = VERSION_LATEST.equals(version) ? MessageFormat.format(ARTIFACT_META_PATH, groupId, artifact) : - MessageFormat.format(ARTIFACT_VERSION_PATH, groupId, artifact, version); + CachedArtifactId cachedArtifactId = null; + AtomicInteger retryAttempts = new AtomicInteger(); + long retryAfter = RESET_RETRY_DELAY_MS_DEFAULT; + CompletableFuture newFuture = new CompletableFuture<>(); + CompletableFuture existing = cachedArtifactIds.get(artifactKey); + if (existing != null && existing.isDone()) + { + try + { + cachedArtifactId = existing.get(); + if (cachedArtifactId != null) + { + retryAttempts = cachedArtifactId.retryAttempts; + } + } + catch (Throwable ex) + { + existing.completeExceptionally(ex); + } + } + CompletableFuture future = cachedArtifactIds.merge(artifactKey, newFuture, (v1, v2) -> + v1.getNow(IN_PROGRESS).retry() && + (v1.getNow(IN_PROGRESS).id == NO_SCHEMA_ID || v1.getNow(IN_PROGRESS).expired(maxAgeMillis)) ? v2 : v1); + if (future == newFuture) + { + try + { + String path = VERSION_LATEST.equals(version) ? MessageFormat.format(ARTIFACT_META_PATH, groupId, artifact) : + MessageFormat.format(ARTIFACT_VERSION_PATH, groupId, artifact, version); - String response = sendHttpRequest(path); - schemaId = response != null ? resolveId(response) : NO_SCHEMA_ID; - if (schemaId != NO_SCHEMA_ID) + String response = sendHttpRequest(path); + if (response == null) + { + if (retryAttempts.getAndIncrement() == 0) + { + retryAfter = RETRY_INITIAL_DELAY_MS_DEFAULT; + event.onUnretrievableArtifactSubjectVersion(catalogId, artifact, version); + if (cachedArtifactId != null && cachedArtifactId.id != NO_SCHEMA_ID) + { + event.onUnretrievableArtifactSubjectVersionStaleArtifact(catalogId, + artifact, version, cachedArtifactId.id); + } + } + + if (cachedArtifactId != null) + { + if (cachedArtifactId.retryAfter != RESET_RETRY_DELAY_MS_DEFAULT) + { + retryAfter = Math.min(cachedArtifactId.retryAfter << 1, maxAgeMillis); + } + newFuture.complete(new CachedArtifactId(cachedArtifactId.timestamp, cachedArtifactId.id, + retryAttempts, retryAfter)); + } + else + { + newFuture.complete(new CachedArtifactId(System.currentTimeMillis(), NO_SCHEMA_ID, + retryAttempts, retryAfter)); + } + } + else if (response != null) + { + if (retryAttempts.getAndSet(0) > 0) + { + event.onRetrievableArtifactSubjectVersion(catalogId, artifact, version); + } + newFuture.complete(new CachedArtifactId(System.currentTimeMillis(), resolveId(response), + retryAttempts, retryAfter)); + } + } + catch (Throwable ex) + { + newFuture.completeExceptionally(ex); + } + } + assert future != null; + try { - schemaIds.put(checkSum, new CachedArtifactId(System.currentTimeMillis(), schemaId)); + cachedArtifactId = future.get(); + artifactId = cachedArtifactId.id; + if (artifactId != NO_SCHEMA_ID) + { + artifactIds.put(artifactKey, cachedArtifactId); + } + } + catch (Throwable ex) + { + future.completeExceptionally(ex); } } - return schemaId; + return artifactId; } private String sendHttpRequest( @@ -148,22 +303,17 @@ private String sendHttpRequest( .build(); // TODO: introduce interrupt/timeout for request to apicurio + String responseBody; try { HttpResponse httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - boolean success = httpResponse.statusCode() == 200; - String responseBody = success ? httpResponse.body() : null; - if (!success) - { - event.remoteAccessRejected(catalogId, httpRequest, httpResponse.statusCode()); - } - return responseBody; + responseBody = httpResponse.statusCode() == 200 ? httpResponse.body() : null; } catch (Exception ex) { - event.remoteAccessRejected(catalogId, httpRequest, 0); + responseBody = null; } - return null; + return responseBody; } @Override diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventContext.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventContext.java index 8493ff4cec..85553059b8 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventContext.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventContext.java @@ -14,9 +14,12 @@ */ package io.aklivity.zilla.runtime.catalog.apicurio.internal; -import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.REMOTE_ACCESS_REJECTED; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.RETRIEVED_ARTIFACT_ID; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.RETRIEVED_ARTIFACT_SUBJECT_VERSION; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.UNRETRIEVABLE_ARTIFACT_ID; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION; +import static io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventType.UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT; -import java.net.http.HttpRequest; import java.nio.ByteBuffer; import java.time.Clock; @@ -35,9 +38,13 @@ public class ApicurioEventContext private final MutableDirectBuffer eventBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); private final MutableDirectBuffer extensionBuffer = new UnsafeBuffer(ByteBuffer.allocate(EVENT_BUFFER_CAPACITY)); private final EventFW.Builder eventRW = new EventFW.Builder(); - private final ApicurioEventExFW.Builder schemaRegistryEventExRW = new ApicurioEventExFW.Builder(); + private final ApicurioEventExFW.Builder apicurioEventExRW = new ApicurioEventExFW.Builder(); private final int apicurioTypeId; - private final int remoteAccessRejectedEventId; + private final int unretrievableArtifactSubjectVersionId; + private final int staleArtifactID; + private final int unretrievableArtifactId; + private final int retrievableArtifactSubjectVersionId; + private final int retrievableArtifactId; private final MessageConsumer eventWriter; private final Clock clock; @@ -45,28 +52,127 @@ public ApicurioEventContext( EngineContext context) { this.apicurioTypeId = context.supplyTypeId(ApicurioCatalog.NAME); - this.remoteAccessRejectedEventId = context.supplyEventId("catalog.apicurio.remote.access.rejected"); + this.unretrievableArtifactSubjectVersionId = context.supplyEventId( + "catalog.apicurio.unretrievable.artifact.subject.version"); + this.staleArtifactID = context.supplyEventId("catalog.apicurio.unretrievable.artifact.subject.version.stale.artifact"); + this.unretrievableArtifactId = context.supplyEventId("catalog.apicurio.unretrievable.artifact.id"); + this.retrievableArtifactSubjectVersionId = context.supplyEventId( + "catalog.apicurio.retrievable.artifact.subject.version"); + this.retrievableArtifactId = context.supplyEventId("catalog.apicurio.retrievable.artifact.id"); this.eventWriter = context.supplyEventWriter(); this.clock = context.clock(); } - public void remoteAccessRejected( + public void onUnretrievableArtifactSubjectVersion( long catalogId, - HttpRequest httpRequest, - int status) + String subject, + String version) { - ApicurioEventExFW extension = schemaRegistryEventExRW + ApicurioEventExFW extension = apicurioEventExRW .wrap(extensionBuffer, 0, extensionBuffer.capacity()) - .remoteAccessRejected(e -> e - .typeId(REMOTE_ACCESS_REJECTED.value()) - .method(httpRequest.method()) - .url(httpRequest.uri().toString()) - .status((short) status) + .unretrievableArtifactSubjectVersion(e -> e + .typeId(UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION.value()) + .subject(subject) + .version(version) ) .build(); EventFW event = eventRW .wrap(eventBuffer, 0, eventBuffer.capacity()) - .id(remoteAccessRejectedEventId) + .id(unretrievableArtifactSubjectVersionId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(apicurioTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onUnretrievableArtifactSubjectVersionStaleArtifact( + long catalogId, + String subject, + String version, + int artifactId) + { + ApicurioEventExFW extension = apicurioEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .unretrievableArtifactSubjectVersionStaleArtifact(e -> e + .typeId(UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT.value()) + .subject(subject) + .version(version) + .artifactId(artifactId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(staleArtifactID) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(apicurioTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onUnretrievableArtifactId( + long catalogId, + int artifactId) + { + ApicurioEventExFW extension = apicurioEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .unretrievableArtifactId(e -> e + .typeId(UNRETRIEVABLE_ARTIFACT_ID.value()) + .artifactId(artifactId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(unretrievableArtifactId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(apicurioTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onRetrievableArtifactSubjectVersion( + long catalogId, + String subject, + String version) + { + ApicurioEventExFW extension = apicurioEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .retrievableArtifactSubjectVersion(e -> e + .typeId(RETRIEVED_ARTIFACT_SUBJECT_VERSION.value()) + .subject(subject) + .version(version) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(retrievableArtifactSubjectVersionId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(apicurioTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onRetrievableArtifactId( + long catalogId, + int artifactId) + { + ApicurioEventExFW extension = apicurioEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .retrievableArtifactId(e -> e + .typeId(RETRIEVED_ARTIFACT_ID.value()) + .artifactId(artifactId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(retrievableArtifactId) .timestamp(clock.millis()) .traceId(0L) .namespacedId(catalogId) diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventFormatter.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventFormatter.java index 63f94bbe5f..83947114e7 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventFormatter.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioEventFormatter.java @@ -18,14 +18,23 @@ import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.StringFW; import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioEventExFW; -import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioRemoteAccessRejectedExFW; +import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioRetrievableArtifactIdExFW; +import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioRetrievableArtifactSubjectVersionExFW; +import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioUnretrievableArtifactIdExFW; +import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioUnretrievableArtifactSubjectVersionExFW; +import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.ApicurioUnretrievableArtifactSubjectVersionStaleArtifactExFW; import io.aklivity.zilla.runtime.catalog.apicurio.internal.types.event.EventFW; import io.aklivity.zilla.runtime.engine.Configuration; import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; public final class ApicurioEventFormatter implements EventFormatterSpi { - private static final String REMOTE_ACCESS_REJECTED = "REMOTE_ACCESS_REJECTED %s %s %d"; + private static final String UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION = "UNRETRIEVABLE_ARTIFACT %s %s"; + private static final String UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT = + "UNRETRIEVABLE_ARTIFACT %s %s, USING_STALE_ARTIFACT %d"; + private static final String UNRETRIEVABLE_ARTIFACT_ID = "UNRETRIEVABLE_ARTIFACT_ID %d"; + private static final String RETRIEVED_ARTIFACT_SUBJECT_VERSION = "RETRIEVED_ARTIFACT_SUBJECT_VERSION %s %s"; + private static final String RETRIEVED_ARTIFACT_ID = "RETRIEVED_ARTIFACT_ID %d"; private final EventFW eventRO = new EventFW(); private final ApicurioEventExFW schemaRegistryEventExRO = new ApicurioEventExFW(); @@ -46,11 +55,36 @@ public String format( String result = null; switch (extension.kind()) { - case REMOTE_ACCESS_REJECTED: + case UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION: { - ApicurioRemoteAccessRejectedExFW ex = extension.remoteAccessRejected(); - result = String.format(REMOTE_ACCESS_REJECTED, asString(ex.method()), asString(ex.url()), - ex.status()); + ApicurioUnretrievableArtifactSubjectVersionExFW ex = extension.unretrievableArtifactSubjectVersion(); + result = String.format(UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION, asString(ex.subject()), asString(ex.version())); + break; + } + case UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT: + { + ApicurioUnretrievableArtifactSubjectVersionStaleArtifactExFW ex = extension + .unretrievableArtifactSubjectVersionStaleArtifact(); + result = String.format(UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT, asString(ex.subject()), + asString(ex.version()), ex.artifactId()); + break; + } + case UNRETRIEVABLE_ARTIFACT_ID: + { + ApicurioUnretrievableArtifactIdExFW ex = extension.unretrievableArtifactId(); + result = String.format(UNRETRIEVABLE_ARTIFACT_ID, ex.artifactId()); + break; + } + case RETRIEVED_ARTIFACT_SUBJECT_VERSION: + { + ApicurioRetrievableArtifactSubjectVersionExFW ex = extension.retrievableArtifactSubjectVersion(); + result = String.format(RETRIEVED_ARTIFACT_SUBJECT_VERSION, asString(ex.subject()), asString(ex.version())); + break; + } + case RETRIEVED_ARTIFACT_ID: + { + ApicurioRetrievableArtifactIdExFW ex = extension.retrievableArtifactId(); + result = String.format(RETRIEVED_ARTIFACT_ID, ex.artifactId()); break; } } diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifact.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifact.java new file mode 100644 index 0000000000..6f268c31eb --- /dev/null +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifact.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.catalog.apicurio.internal; + +import java.util.concurrent.atomic.AtomicInteger; + +public class CachedArtifact +{ + public static final String SCHEMA_PLACEHOLDER = "schema"; + public static final CachedArtifact IN_PROGRESS = new CachedArtifact(SCHEMA_PLACEHOLDER); + + public final String artifact; + public final AtomicInteger retryAttempts; + + public CachedArtifact( + String artifact) + { + this.artifact = artifact; + this.retryAttempts = new AtomicInteger(); + } + + public CachedArtifact( + String artifact, + AtomicInteger retryAttempts) + { + this.artifact = artifact; + this.retryAttempts = retryAttempts; + } +} diff --git a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifactId.java b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifactId.java index a2802828e6..2effd795b8 100644 --- a/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifactId.java +++ b/runtime/catalog-apicurio/src/main/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/CachedArtifactId.java @@ -14,16 +14,39 @@ */ package io.aklivity.zilla.runtime.catalog.apicurio.internal; +import java.util.concurrent.atomic.AtomicInteger; + public class CachedArtifactId { + public static final int ID_PLACEHOLDER = -1; + public static final CachedArtifactId IN_PROGRESS = new CachedArtifactId(Long.MAX_VALUE, ID_PLACEHOLDER, + new AtomicInteger(), Long.MAX_VALUE); + public long timestamp; public int id; + public final AtomicInteger retryAttempts; + public final long retryAfter; public CachedArtifactId( long timestamp, - int id) + int id, + AtomicInteger retryAttempts, + long retryAfter) { this.timestamp = timestamp; this.id = id; + this.retryAttempts = retryAttempts; + this.retryAfter = retryAfter; + } + + public boolean expired( + long maxAgeMillis) + { + return System.currentTimeMillis() - this.timestamp > maxAgeMillis; + } + + public boolean retry() + { + return System.currentTimeMillis() - this.timestamp > this.retryAfter; } } diff --git a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogFactoryTest.java b/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogFactoryTest.java index d9761d1103..b8bb3bdc97 100644 --- a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogFactoryTest.java +++ b/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioCatalogFactoryTest.java @@ -54,7 +54,7 @@ public void shouldLoadAndCreate() .idEncoding("legacy") .maxAge(Duration.ofSeconds(100)) .build(); - CatalogConfig options = new CatalogConfig("test", "catalog0", "schema-registry", catalogConfig); + CatalogConfig options = new CatalogConfig("test", "catalog0", "apicurio", catalogConfig); CatalogHandler handler = context.attach(options); assertThat(handler, instanceOf(ApicurioCatalogHandler.class)); diff --git a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioIT.java b/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioIT.java index 3bbe82c331..5905b7a904 100644 --- a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioIT.java +++ b/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/ApicurioIT.java @@ -15,9 +15,6 @@ package io.aklivity.zilla.runtime.catalog.apicurio.internal; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.rules.RuleChain.outerRule; import static org.mockito.Mockito.mock; @@ -39,16 +36,27 @@ import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer; +import io.aklivity.zilla.runtime.engine.test.EngineRule; +import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; public class ApicurioIT { private final K3poRule k3po = new K3poRule() + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application") .addScriptRoot("local", "io/aklivity/zilla/runtime/catalog/schema/registry/internal"); private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); + private final EngineRule engine = new EngineRule() + .directory("target/zilla-itests") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/catalog/apicurio/config") + .external("app0") + .clean(); + @Rule - public final TestRule chain = outerRule(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); private ApicurioOptionsConfig config; private EngineContext context = mock(EngineContext.class); @@ -64,151 +72,91 @@ public void setup() } @Test + @Configuration("resolve/artifact/global/id/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.artifact.via.global.id" }) public void shouldResolveArtifactViaGlobalId() throws Exception { - String expected = "asyncapi: 3.0.0\n" + - "info:\n" + - " title: Zilla MQTT Proxy\n" + - " version: 1.0.0\n" + - " license:\n" + - " name: Aklivity Community License\n" + - "servers:\n" + - " plain:\n" + - " host: mqtt://localhost:7183\n" + - " protocol: mqtt\n" + - "defaultContentType: application/json"; - - ApicurioCatalogHandler catalog = new ApicurioCatalogHandler(config, context, 0L); - - String artifact = catalog.resolve(1); - k3po.finish(); - - assertThat(artifact, not(nullValue())); - assertEquals(expected, artifact); } @Test + @Configuration("resolve/artifact/id/subject/version/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.artifact.via.artifactid.version" }) - public void shouldResolveArtifactViaArtifactIdVersion() throws Exception + public void shouldResolveArtifactIdViaSubjectAndVersion() throws Exception { - String expected = "asyncapi: 3.0.0\n" + - "info:\n" + - " title: Zilla MQTT Proxy\n" + - " version: 1.0.0\n" + - " license:\n" + - " name: Aklivity Community License\n" + - "servers:\n" + - " plain:\n" + - " host: mqtt://localhost:7183\n" + - " protocol: mqtt\n" + - "defaultContentType: application/json"; - - ApicurioCatalogHandler catalog = new ApicurioCatalogHandler(config, context, 0L); - - int globalId = catalog.resolve("artifactId", "0"); - - String artifact = catalog.resolve(globalId); - k3po.finish(); - - assertEquals(globalId, 1); - assertThat(artifact, not(nullValue())); - assertEquals(expected, artifact); } @Test + @Configuration("resolve/artifact/id/subject/version/latest/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.artifact.latest.version" }) - public void shouldResolveArtifactLatestVersion() throws Exception + public void shouldResolveArtifactIdViaSubjectAndLatestVersion() throws Exception { - String expected = "asyncapi: 3.0.0\n" + - "info:\n" + - " title: Zilla MQTT Proxy\n" + - " version: 1.0.0\n" + - " license:\n" + - " name: Aklivity Community License\n" + - "servers:\n" + - " plain:\n" + - " host: mqtt://localhost:7183\n" + - " protocol: mqtt\n" + - "defaultContentType: application/json"; - - ApicurioCatalogHandler catalog = new ApicurioCatalogHandler(config, context, 0L); - - int globalId = catalog.resolve("artifactId", "latest"); - - String artifact = catalog.resolve(globalId); - k3po.finish(); - - assertEquals(globalId, 1); - assertThat(artifact, not(nullValue())); - assertEquals(expected, artifact); } @Test + @Configuration("resolve/artifact/global/id/cache/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.artifact.via.global.id" }) public void shouldResolveArtifactViaGlobalIdFromCache() throws Exception { - String expected = "asyncapi: 3.0.0\n" + - "info:\n" + - " title: Zilla MQTT Proxy\n" + - " version: 1.0.0\n" + - " license:\n" + - " name: Aklivity Community License\n" + - "servers:\n" + - " plain:\n" + - " host: mqtt://localhost:7183\n" + - " protocol: mqtt\n" + - "defaultContentType: application/json"; - - ApicurioCatalogHandler catalog = new ApicurioCatalogHandler(config, context, 0L); - - catalog.resolve(1); - k3po.finish(); - - String artifact = catalog.resolve(1); - - assertThat(artifact, not(nullValue())); - assertEquals(expected, artifact); } @Test + @Configuration("resolve/artifact/id/subject/version/cache/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.artifact.via.artifactid.version" }) - public void shouldResolveArtifactViaArtifactIdVersionFromCache() throws Exception + public void shouldResolveArtifactIdViaSubjectAndVersionFromCache() throws Exception { - String expected = "asyncapi: 3.0.0\n" + - "info:\n" + - " title: Zilla MQTT Proxy\n" + - " version: 1.0.0\n" + - " license:\n" + - " name: Aklivity Community License\n" + - "servers:\n" + - " plain:\n" + - " host: mqtt://localhost:7183\n" + - " protocol: mqtt\n" + - "defaultContentType: application/json"; - - ApicurioCatalogHandler catalog = new ApicurioCatalogHandler(config, context, 0L); - - catalog.resolve(catalog.resolve("artifactId", "0")); - k3po.finish(); + } - int globalId = catalog.resolve("artifactId", "0"); + @Test + @Configuration("resolve/artifact/global/id/retry/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.artifact.via.global.id.retry" }) + public void shouldResolveArtifactViaGlobalIdRetry() throws Exception + { + k3po.finish(); + } - String artifact = catalog.resolve(globalId); + @Test + @Configuration("resolve/artifact/id/subject/version/retry/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.artifact.via.artifactid.version.retry" }) + public void shouldResolveArtifactIdViaSubjectAndVersionFromCacheAndRetry() throws Exception + { + k3po.finish(); + } - assertEquals(1, globalId); - assertThat(artifact, not(nullValue())); - assertEquals(expected, artifact); + @Test + @Configuration("resolve/artifact/id/subject/version/failed/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.artifact.via.artifactid.version.failed" }) + public void shouldResolveArtifactIdViaSubjectAndVersionFailed() throws Exception + { + k3po.finish(); } @Test diff --git a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/EventIT.java b/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/EventIT.java deleted file mode 100644 index 0582842292..0000000000 --- a/runtime/catalog-apicurio/src/test/java/io/aklivity/zilla/runtime/catalog/apicurio/internal/EventIT.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.catalog.apicurio.internal; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.junit.rules.RuleChain.outerRule; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.kaazing.k3po.junit.annotation.Specification; -import org.kaazing.k3po.junit.rules.K3poRule; - -import io.aklivity.zilla.runtime.engine.test.EngineRule; -import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; - -public class EventIT -{ - private final K3poRule k3po = new K3poRule() - .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") - .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); - - private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); - - private final EngineRule engine = new EngineRule() - .directory("target/zilla-itests") - .countersBufferCapacity(4096) - .configurationRoot("io/aklivity/zilla/specs/catalog/apicurio/config") - .external("app0") - .clean(); - - @Rule - public final TestRule chain = outerRule(engine).around(k3po).around(timeout); - - @Test - @Configuration("event.yaml") - @Specification({ - "${net}/event/client", - "${app}/event/server" - }) - public void shouldLogEvents() throws Exception - { - k3po.finish(); - } -} diff --git a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.latest.version.rpt b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.latest.version.rpt index 229aad406e..03140f481f 100644 --- a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.latest.version.rpt +++ b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.latest.version.rpt @@ -39,30 +39,3 @@ write '{' '}' write close - -accept "http://localhost:8080/apis/registry/v2/ids/globalIds/1" - -accepted -connected - -read http:method "GET" -read http:version "HTTP/1.1" -read closed - -write http:status "200" "OK" -write http:header "content-type" "application/json" -write http:content-length - -write 'asyncapi: 3.0.0\n' - 'info:\n' - ' title: Zilla MQTT Proxy\n' - ' version: 1.0.0\n' - ' license:\n' - ' name: Aklivity Community License\n' - 'servers:\n' - ' plain:\n' - ' host: mqtt://localhost:7183\n' - ' protocol: mqtt\n' - 'defaultContentType: application/json'; - -write close diff --git a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.failed.rpt b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.failed.rpt new file mode 100644 index 0000000000..59872e7a99 --- /dev/null +++ b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.failed.rpt @@ -0,0 +1,29 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8080/apis/registry/v2/groups/groupId/artifacts/artifactId/meta" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:header "content-type" "application/json" +write http:content-length + +write close diff --git a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.retry.rpt b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.retry.rpt new file mode 100644 index 0000000000..ea69fd92a2 --- /dev/null +++ b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.retry.rpt @@ -0,0 +1,79 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8080/apis/registry/v2/groups/groupId/artifacts/artifactId/meta" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/json" +write http:content-length + +write '{' + '\"contentId\": 1,' + '\"createdBy\": \"user1\",' + '\"createdOn\": \"2019-05-17T12:00:00Z\",' + '\"description\": \"The description of the artifact\",' + '\"globalId\": 1,' + '\"groupId\": \"groupId\",' + '\"id\": \"artifactId\",' + '\"type\":\"ASYNCAPI\",' + '\"version\": 0' + '}' + +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:header "content-type" "application/json" +write http:content-length + +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/json" +write http:content-length + +write '{' + '\"contentId\": 1,' + '\"createdBy\": \"user1\",' + '\"createdOn\": \"2019-05-17T12:00:00Z\",' + '\"description\": \"The description of the artifact\",' + '\"globalId\": 2,' + '\"groupId\": \"groupId\",' + '\"id\": \"artifactId\",' + '\"type\":\"ASYNCAPI\",' + '\"version\": 0' + '}' + +write close diff --git a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.rpt b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.rpt index bfd0ebe738..0b3adeb372 100644 --- a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.rpt +++ b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.artifactid.version.rpt @@ -40,30 +40,3 @@ write '{' '}' write close - -accept "http://localhost:8080/apis/registry/v2/ids/globalIds/1" - -accepted -connected - -read http:method "GET" -read http:version "HTTP/1.1" -read closed - -write http:status "200" "OK" -write http:header "content-type" "application/json" -write http:content-length - -write 'asyncapi: 3.0.0\n' - 'info:\n' - ' title: Zilla MQTT Proxy\n' - ' version: 1.0.0\n' - ' license:\n' - ' name: Aklivity Community License\n' - 'servers:\n' - ' plain:\n' - ' host: mqtt://localhost:7183\n' - ' protocol: mqtt\n' - 'defaultContentType: application/json'; - -write close diff --git a/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.global.id.retry.rpt b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.global.id.retry.rpt new file mode 100644 index 0000000000..342f89d94e --- /dev/null +++ b/runtime/catalog-apicurio/src/test/scripts/io/aklivity/zilla/runtime/catalog/schema/registry/internal/resolve.artifact.via.global.id.retry.rpt @@ -0,0 +1,54 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8080/apis/registry/v2/ids/globalIds/1" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:header "content-type" "application/json" +write http:content-length + +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/json" +write http:content-length + +write 'asyncapi: 3.0.0\n' + 'info:\n' + ' title: Zilla MQTT Proxy\n' + ' version: 1.0.0\n' + ' license:\n' + ' name: Aklivity Community License\n' + 'servers:\n' + ' plain:\n' + ' host: mqtt://localhost:7183\n' + ' protocol: mqtt\n' + 'defaultContentType: application/json'; + +write close diff --git a/runtime/catalog-inline/pom.xml b/runtime/catalog-inline/pom.xml index 3913b280fe..92398e7c88 100644 --- a/runtime/catalog-inline/pom.xml +++ b/runtime/catalog-inline/pom.xml @@ -6,7 +6,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/catalog-karapace/pom.xml b/runtime/catalog-karapace/pom.xml index e20601cd23..cc7a7dadb7 100644 --- a/runtime/catalog-karapace/pom.xml +++ b/runtime/catalog-karapace/pom.xml @@ -6,7 +6,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -24,7 +24,7 @@ 11 11 - 0.85 + 0.95 0 diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchema.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchema.java new file mode 100644 index 0000000000..46b495ae5e --- /dev/null +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchema.java @@ -0,0 +1,41 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.catalog.karapace.internal; + +import java.util.concurrent.atomic.AtomicInteger; + +public class CachedSchema +{ + public static final String SCHEMA_PLACEHOLDER = "schema"; + public static final CachedSchema IN_PROGRESS = new CachedSchema(SCHEMA_PLACEHOLDER); + + public final String schema; + public final AtomicInteger retryAttempts; + + public CachedSchema( + String schema) + { + this.schema = schema; + this.retryAttempts = new AtomicInteger(); + } + + public CachedSchema( + String schema, + AtomicInteger retryAttempts) + { + this.schema = schema; + this.retryAttempts = retryAttempts; + } +} diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchemaId.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchemaId.java index 733c75bab2..c678d4686f 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchemaId.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/CachedSchemaId.java @@ -14,16 +14,39 @@ */ package io.aklivity.zilla.runtime.catalog.karapace.internal; +import java.util.concurrent.atomic.AtomicInteger; + public class CachedSchemaId { - public long timestamp; - public int id; + public static final int PLACEHOLDER_SCHEMA_ID = -1; + public static final CachedSchemaId IN_PROGRESS = new CachedSchemaId(Long.MAX_VALUE, PLACEHOLDER_SCHEMA_ID, + new AtomicInteger(), Long.MAX_VALUE); + + public final long timestamp; + public final int id; + public final AtomicInteger retryAttempts; + public final long retryAfter; public CachedSchemaId( long timestamp, - int id) + int id, + AtomicInteger retryAttempts, + long retryAfter) { this.timestamp = timestamp; this.id = id; + this.retryAttempts = retryAttempts; + this.retryAfter = retryAfter; + } + + public boolean expired( + long maxAgeMillis) + { + return System.currentTimeMillis() - this.timestamp > maxAgeMillis; + } + + public boolean retry() + { + return System.currentTimeMillis() - this.timestamp > this.retryAfter; } } diff --git a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/ServerView.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCache.java similarity index 53% rename from incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/ServerView.java rename to runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCache.java index 244986a1be..f45384c100 100644 --- a/incubator/command-generate/src/main/java/io/aklivity/zilla/runtime/command/generate/internal/openapi/view/ServerView.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCache.java @@ -12,30 +12,20 @@ * WARRANTIES OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ -package io.aklivity.zilla.runtime.command.generate.internal.openapi.view; +package io.aklivity.zilla.runtime.catalog.karapace.internal; -import java.net.URI; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; -import io.aklivity.zilla.runtime.command.generate.internal.openapi.model.Server; - -public final class ServerView +public class KarapaceCache { - private URI url; - - private ServerView( - Server server) - { - this.url = URI.create(server.url); - } - - public URI url() - { - return url; - } + public final ConcurrentMap> schemas; + public final ConcurrentMap> schemaIds; - public static ServerView of( - Server server) + public KarapaceCache() { - return new ServerView(server); + this.schemas = new ConcurrentHashMap<>(); + this.schemaIds = new ConcurrentHashMap<>(); } } diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalog.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalog.java index a48d0bc3e6..291524a83d 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalog.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalog.java @@ -15,6 +15,8 @@ package io.aklivity.zilla.runtime.catalog.karapace.internal; import java.net.URL; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import io.aklivity.zilla.runtime.engine.Configuration; import io.aklivity.zilla.runtime.engine.EngineContext; @@ -25,9 +27,12 @@ public class KarapaceCatalog implements Catalog { public static final String NAME = "karapace"; + private final ConcurrentMap cache; + public KarapaceCatalog( Configuration config) { + this.cache = new ConcurrentHashMap<>(); } @Override @@ -40,7 +45,7 @@ public String name() public CatalogContext supply( EngineContext context) { - return new KarapaceCatalogContext(context); + return new KarapaceCatalogContext(context, cache); } @Override diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogContext.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogContext.java index 60eb06a5ba..9290af9245 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogContext.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogContext.java @@ -14,6 +14,8 @@ */ package io.aklivity.zilla.runtime.catalog.karapace.internal; +import java.util.concurrent.ConcurrentMap; + import io.aklivity.zilla.runtime.catalog.karapace.internal.config.KarapaceOptionsConfig; import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.catalog.CatalogContext; @@ -23,17 +25,21 @@ public class KarapaceCatalogContext implements CatalogContext { private final EngineContext context; + private final ConcurrentMap cachesById; public KarapaceCatalogContext( - EngineContext context) + EngineContext context, + ConcurrentMap cachesById) { this.context = context; + this.cachesById = cachesById; } @Override public CatalogHandler attach( CatalogConfig catalog) { - return new KarapaceCatalogHandler(KarapaceOptionsConfig.class.cast(catalog.options), context, catalog.id); + KarapaceCache cache = cachesById.computeIfAbsent(catalog.id, id -> new KarapaceCache()); + return new KarapaceCatalogHandler(KarapaceOptionsConfig.class.cast(catalog.options), context, catalog.id, cache); } } diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogHandler.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogHandler.java index dfc2051d15..da1e437166 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogHandler.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceCatalogHandler.java @@ -14,12 +14,17 @@ */ package io.aklivity.zilla.runtime.catalog.karapace.internal; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.CachedSchemaId.IN_PROGRESS; + import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.ByteOrder; import java.text.MessageFormat; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.CRC32C; import org.agrona.BitUtil; @@ -41,6 +46,8 @@ public class KarapaceCatalogHandler implements CatalogHandler private static final String REGISTER_SCHEMA_PATH = "/subjects/{0}/versions"; private static final int MAX_PADDING_LENGTH = 5; private static final byte MAGIC_BYTE = 0x0; + private static final long RESET_RETRY_DELAY_MS_DEFAULT = 0L; + private static final long RETRY_INITIAL_DELAY_MS_DEFAULT = 1000L; private final KarapacePrefixFW.Builder prefixRW = new KarapacePrefixFW.Builder() .wrap(new UnsafeBuffer(new byte[5]), 0, 5); @@ -54,11 +61,22 @@ public class KarapaceCatalogHandler implements CatalogHandler private final long maxAgeMillis; private final KarapaceEventContext event; private final long catalogId; + private final ConcurrentMap> cachedSchemas; + private final ConcurrentMap> cachedSchemaIds; public KarapaceCatalogHandler( KarapaceOptionsConfig config, EngineContext context, long catalogId) + { + this(config, context, catalogId, new KarapaceCache()); + } + + public KarapaceCatalogHandler( + KarapaceOptionsConfig config, + EngineContext context, + long catalogId, + KarapaceCache cache) { this.baseUrl = config.url; this.client = HttpClient.newHttpClient(); @@ -69,24 +87,83 @@ public KarapaceCatalogHandler( this.maxAgeMillis = config.maxAge.toMillis(); this.event = new KarapaceEventContext(context); this.catalogId = catalogId; + this.cachedSchemas = cache.schemas; + this.cachedSchemaIds = cache.schemaIds; } @Override public String resolve( int schemaId) { - String schema; - if (schemas.containsKey(schemaId)) + String schema = null; + if (schemaId != NO_SCHEMA_ID) { - schema = schemas.get(schemaId); - } - else - { - String response = sendHttpRequest(MessageFormat.format(SCHEMA_PATH, schemaId)); - schema = response != null ? request.resolveSchemaResponse(response) : null; - if (schema != null) + if (schemas.containsKey(schemaId)) + { + schema = schemas.get(schemaId); + } + else { - schemas.put(schemaId, schema); + AtomicInteger retryAttempts = new AtomicInteger(); + CompletableFuture newFuture = new CompletableFuture<>(); + CompletableFuture existing = cachedSchemas.get(schemaId); + if (existing != null && existing.isDone()) + { + try + { + CachedSchema cachedSchema = existing.get(); + if (cachedSchema != null) + { + retryAttempts = cachedSchema.retryAttempts; + } + } + catch (Throwable ex) + { + existing.completeExceptionally(ex); + } + } + CompletableFuture future = cachedSchemas.merge(schemaId, newFuture, (v1, v2) -> + v1.getNow(CachedSchema.IN_PROGRESS).schema == null ? v2 : v1); + if (future == newFuture) + { + try + { + String response = sendHttpRequest(MessageFormat.format(SCHEMA_PATH, schemaId)); + if (response == null) + { + if (retryAttempts.getAndIncrement() == 0) + { + event.onUnretrievableSchemaId(catalogId, schemaId); + } + newFuture.complete(new CachedSchema(null, retryAttempts)); + } + else + { + if (retryAttempts.getAndSet(0) > 0) + { + event.onRetrievableSchemaId(catalogId, schemaId); + } + newFuture.complete(new CachedSchema(request.resolveSchemaResponse(response), retryAttempts)); + } + } + catch (Throwable ex) + { + newFuture.completeExceptionally(ex); + } + } + assert future != null; + try + { + schema = future.get().schema; + if (schema != null) + { + schemas.put(schemaId, schema); + } + } + catch (Throwable ex) + { + future.completeExceptionally(ex); + } } } return schema; @@ -97,21 +174,99 @@ public int resolve( String subject, String version) { - int schemaId; + int schemaId = NO_SCHEMA_ID; - int checkSum = generateCRC32C(subject, version); - if (schemaIds.containsKey(checkSum) && - (System.currentTimeMillis() - schemaIds.get(checkSum).timestamp) < maxAgeMillis) + int schemaKey = generateCRC32C(subject, version); + if (schemaIds.containsKey(schemaKey) && !schemaIds.get(schemaKey).expired(maxAgeMillis)) { - schemaId = schemaIds.get(checkSum).id; + schemaId = schemaIds.get(schemaKey).id; } else { - String response = sendHttpRequest(MessageFormat.format(SUBJECT_VERSION_PATH, subject, version)); - schemaId = response != null ? request.resolveResponse(response) : NO_SCHEMA_ID; - if (schemaId != NO_SCHEMA_ID) + CachedSchemaId cachedSchemaId = null; + AtomicInteger retryAttempts = new AtomicInteger(); + long retryAfter = RESET_RETRY_DELAY_MS_DEFAULT; + CompletableFuture newFuture = new CompletableFuture<>(); + CompletableFuture existing = cachedSchemaIds.get(schemaKey); + if (existing != null && existing.isDone()) + { + try + { + cachedSchemaId = existing.get(); + if (cachedSchemaId != null) + { + retryAttempts = cachedSchemaId.retryAttempts; + } + } + catch (Throwable ex) + { + existing.completeExceptionally(ex); + } + } + CompletableFuture future = cachedSchemaIds.merge(schemaKey, newFuture, (v1, v2) -> + v1.getNow(IN_PROGRESS).retry() && + (v1.getNow(IN_PROGRESS).id == NO_SCHEMA_ID || v1.getNow(IN_PROGRESS).expired(maxAgeMillis)) ? v2 : v1); + if (future == newFuture) { - schemaIds.put(checkSum, new CachedSchemaId(System.currentTimeMillis(), schemaId)); + try + { + String response = sendHttpRequest(MessageFormat.format(SUBJECT_VERSION_PATH, subject, version)); + if (response == null) + { + if (retryAttempts.getAndIncrement() == 0) + { + retryAfter = RETRY_INITIAL_DELAY_MS_DEFAULT; + event.onUnretrievableSchemaSubjectVersion(catalogId, subject, version); + if (cachedSchemaId != null && cachedSchemaId.id != NO_SCHEMA_ID) + { + event.onUnretrievableSchemaSubjectVersionStaleSchema(catalogId, subject, version, + cachedSchemaId.id); + } + } + + if (cachedSchemaId != null) + { + if (cachedSchemaId.retryAfter != RESET_RETRY_DELAY_MS_DEFAULT) + { + retryAfter = Math.min(cachedSchemaId.retryAfter << 1, maxAgeMillis); + } + newFuture.complete(new CachedSchemaId(cachedSchemaId.timestamp, cachedSchemaId.id, + retryAttempts, retryAfter)); + } + else + { + newFuture.complete(new CachedSchemaId(System.currentTimeMillis(), NO_SCHEMA_ID, + retryAttempts, retryAfter)); + } + } + else if (response != null) + { + if (retryAttempts.getAndSet(0) > 0) + { + event.onRetrievableSchemaSubjectVersion(catalogId, subject, version); + } + newFuture.complete(new CachedSchemaId(System.currentTimeMillis(), request.resolveResponse(response), + retryAttempts, retryAfter)); + } + } + catch (Throwable ex) + { + newFuture.completeExceptionally(ex); + } + } + assert future != null; + try + { + cachedSchemaId = future.get(); + schemaId = cachedSchemaId.id; + if (schemaId != NO_SCHEMA_ID) + { + schemaIds.put(schemaKey, cachedSchemaId); + } + } + catch (Throwable ex) + { + future.completeExceptionally(ex); } } return schemaId; @@ -190,22 +345,17 @@ private String sendHttpRequest( .build(); // TODO: introduce interrupt/timeout for request to schema registry + String responseBody; try { HttpResponse httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString()); - boolean success = httpResponse.statusCode() == 200; - String responseBody = success ? httpResponse.body() : null; - if (!success) - { - event.remoteAccessRejected(catalogId, httpRequest, httpResponse.statusCode()); - } - return responseBody; + responseBody = httpResponse.statusCode() == 200 ? httpResponse.body() : null; } catch (Exception ex) { - event.remoteAccessRejected(catalogId, httpRequest, 0); + responseBody = null; } - return null; + return responseBody; } private URI toURI( diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventContext.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventContext.java index b4bc268d6b..74c78934b8 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventContext.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventContext.java @@ -14,10 +14,12 @@ */ package io.aklivity.zilla.runtime.catalog.karapace.internal; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.RETRIEVED_SCHEMA_ID; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.RETRIEVED_SCHEMA_SUBJECT_VERSION; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.UNRETRIEVABLE_SCHEMA_ID; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION; +import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA; -import static io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventType.REMOTE_ACCESS_REJECTED; - -import java.net.http.HttpRequest; import java.nio.ByteBuffer; import java.time.Clock; @@ -38,7 +40,11 @@ public class KarapaceEventContext private final EventFW.Builder eventRW = new EventFW.Builder(); private final KarapaceEventExFW.Builder karapaceEventExRW = new KarapaceEventExFW.Builder(); private final int karapaceTypeId; - private final int remoteAccessRejectedEventId; + private final int unretrievableSchemaSubjectVersionId; + private final int staleSchemaID; + private final int unretrievableSchemaId; + private final int retrievableSchemaSubjectVersionId; + private final int retrievableSchemaId; private final MessageConsumer eventWriter; private final Clock clock; @@ -46,28 +52,125 @@ public KarapaceEventContext( EngineContext context) { this.karapaceTypeId = context.supplyTypeId(KarapaceCatalog.NAME); - this.remoteAccessRejectedEventId = context.supplyEventId("catalog.karapace.remote.access.rejected"); + this.unretrievableSchemaSubjectVersionId = context.supplyEventId("catalog.karapace.unretrievable.schema.subject.version"); + this.staleSchemaID = context.supplyEventId("catalog.karapace.unretrievable.schema.subject.version.stale.schema"); + this.unretrievableSchemaId = context.supplyEventId("catalog.karapace.unretrievable.schema.id"); + this.retrievableSchemaSubjectVersionId = context.supplyEventId("catalog.karapace.retrievable.schema.subject.version"); + this.retrievableSchemaId = context.supplyEventId("catalog.karapace.retrievable.schema.id"); this.eventWriter = context.supplyEventWriter(); this.clock = context.clock(); } - public void remoteAccessRejected( + public void onUnretrievableSchemaSubjectVersion( + long catalogId, + String subject, + String version) + { + KarapaceEventExFW extension = karapaceEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .unretrievableSchemaSubjectVersion(e -> e + .typeId(UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION.value()) + .subject(subject) + .version(version) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(unretrievableSchemaSubjectVersionId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(karapaceTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onUnretrievableSchemaSubjectVersionStaleSchema( + long catalogId, + String subject, + String version, + int schemaId) + { + KarapaceEventExFW extension = karapaceEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .unretrievableSchemaSubjectVersionStaleSchema(e -> e + .typeId(UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA.value()) + .subject(subject) + .version(version) + .schemaId(schemaId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(staleSchemaID) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(karapaceTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onUnretrievableSchemaId( + long catalogId, + int schemaId) + { + KarapaceEventExFW extension = karapaceEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .unretrievableSchemaId(e -> e + .typeId(UNRETRIEVABLE_SCHEMA_ID.value()) + .schemaId(schemaId) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(unretrievableSchemaId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(karapaceTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onRetrievableSchemaSubjectVersion( + long catalogId, + String subject, + String version) + { + KarapaceEventExFW extension = karapaceEventExRW + .wrap(extensionBuffer, 0, extensionBuffer.capacity()) + .retrievableSchemaSubjectVersion(e -> e + .typeId(RETRIEVED_SCHEMA_SUBJECT_VERSION.value()) + .subject(subject) + .version(version) + ) + .build(); + EventFW event = eventRW + .wrap(eventBuffer, 0, eventBuffer.capacity()) + .id(retrievableSchemaSubjectVersionId) + .timestamp(clock.millis()) + .traceId(0L) + .namespacedId(catalogId) + .extension(extension.buffer(), extension.offset(), extension.limit()) + .build(); + eventWriter.accept(karapaceTypeId, event.buffer(), event.offset(), event.limit()); + } + + public void onRetrievableSchemaId( long catalogId, - HttpRequest httpRequest, - int status) + int schemaId) { KarapaceEventExFW extension = karapaceEventExRW .wrap(extensionBuffer, 0, extensionBuffer.capacity()) - .remoteAccessRejected(e -> e - .typeId(REMOTE_ACCESS_REJECTED.value()) - .method(httpRequest.method()) - .url(httpRequest.uri().toString()) - .status((short) status) + .retrievableSchemaId(e -> e + .typeId(RETRIEVED_SCHEMA_ID.value()) + .schemaId(schemaId) ) .build(); EventFW event = eventRW .wrap(eventBuffer, 0, eventBuffer.capacity()) - .id(remoteAccessRejectedEventId) + .id(retrievableSchemaId) .timestamp(clock.millis()) .traceId(0L) .namespacedId(catalogId) diff --git a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventFormatter.java b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventFormatter.java index 8f388b9d72..8c342dd962 100644 --- a/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventFormatter.java +++ b/runtime/catalog-karapace/src/main/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceEventFormatter.java @@ -19,13 +19,22 @@ import io.aklivity.zilla.runtime.catalog.karapace.internal.types.StringFW; import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.EventFW; import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceEventExFW; -import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceRemoteAccessRejectedExFW; +import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceRetrievableSchemaIdExFW; +import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceRetrievableSchemaSubjectVersionExFW; +import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceUnretrievableSchemaIdExFW; +import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceUnretrievableSchemaSubjectVersionExFW; +import io.aklivity.zilla.runtime.catalog.karapace.internal.types.event.KarapaceUnretrievableSchemaSubjectVersionStaleSchemaExFW; import io.aklivity.zilla.runtime.engine.Configuration; import io.aklivity.zilla.runtime.engine.event.EventFormatterSpi; public final class KarapaceEventFormatter implements EventFormatterSpi { - private static final String REMOTE_ACCESS_REJECTED = "REMOTE_ACCESS_REJECTED %s %s %d"; + private static final String UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION = "UNRETRIEVABLE_SCHEMA %s %s"; + private static final String UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA = + "UNRETRIEVABLE_SCHEMA %s %s, USING_STALE_SCHEMA %d"; + private static final String UNRETRIEVABLE_SCHEMA_ID = "UNRETRIEVABLE_SCHEMA_ID %d"; + private static final String RETRIEVED_SCHEMA_SUBJECT_VERSION = "RETRIEVED_SCHEMA_SUBJECT_VERSION %s %s"; + private static final String RETRIEVED_SCHEMA_ID = "RETRIEVED_SCHEMA_ID %d"; private final EventFW eventRO = new EventFW(); private final KarapaceEventExFW karapaceEventExRO = new KarapaceEventExFW(); @@ -46,11 +55,36 @@ public String format( String result = null; switch (extension.kind()) { - case REMOTE_ACCESS_REJECTED: + case UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION: { - KarapaceRemoteAccessRejectedExFW ex = extension.remoteAccessRejected(); - result = String.format(REMOTE_ACCESS_REJECTED, asString(ex.method()), asString(ex.url()), - ex.status()); + KarapaceUnretrievableSchemaSubjectVersionExFW ex = extension.unretrievableSchemaSubjectVersion(); + result = String.format(UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION, asString(ex.subject()), asString(ex.version())); + break; + } + case UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA: + { + KarapaceUnretrievableSchemaSubjectVersionStaleSchemaExFW ex = extension + .unretrievableSchemaSubjectVersionStaleSchema(); + result = String.format(UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA, asString(ex.subject()), + asString(ex.version()), ex.schemaId()); + break; + } + case UNRETRIEVABLE_SCHEMA_ID: + { + KarapaceUnretrievableSchemaIdExFW ex = extension.unretrievableSchemaId(); + result = String.format(UNRETRIEVABLE_SCHEMA_ID, ex.schemaId()); + break; + } + case RETRIEVED_SCHEMA_SUBJECT_VERSION: + { + KarapaceRetrievableSchemaSubjectVersionExFW ex = extension.retrievableSchemaSubjectVersion(); + result = String.format(RETRIEVED_SCHEMA_SUBJECT_VERSION, asString(ex.subject()), asString(ex.version())); + break; + } + case RETRIEVED_SCHEMA_ID: + { + KarapaceRetrievableSchemaIdExFW ex = extension.retrievableSchemaId(); + result = String.format(RETRIEVED_SCHEMA_ID, ex.schemaId()); break; } } diff --git a/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/EventIT.java b/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/EventIT.java deleted file mode 100644 index a4865b6e8c..0000000000 --- a/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/EventIT.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2021-2023 Aklivity Inc - * - * Licensed under the Aklivity Community License (the "License"); you may not use - * this file except in compliance with the License. You may obtain a copy of the - * License at - * - * https://www.aklivity.io/aklivity-community-license/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - */ -package io.aklivity.zilla.runtime.catalog.karapace.internal; - -import static java.util.concurrent.TimeUnit.SECONDS; -import static org.junit.rules.RuleChain.outerRule; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.DisableOnDebug; -import org.junit.rules.TestRule; -import org.junit.rules.Timeout; -import org.kaazing.k3po.junit.annotation.Specification; -import org.kaazing.k3po.junit.rules.K3poRule; - -import io.aklivity.zilla.runtime.engine.test.EngineRule; -import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; - -public class EventIT -{ - private final K3poRule k3po = new K3poRule() - .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") - .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application"); - - private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); - - private final EngineRule engine = new EngineRule() - .directory("target/zilla-itests") - .countersBufferCapacity(4096) - .configurationRoot("io/aklivity/zilla/specs/catalog/karapace/config") - .external("app0") - .clean(); - - @Rule - public final TestRule chain = outerRule(engine).around(k3po).around(timeout); - - @Test - @Configuration("event.yaml") - @Specification({ - "${net}/event/client", - "${app}/event/server" - }) - public void shouldLogEvents() throws Exception - { - k3po.finish(); - } -} diff --git a/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceIT.java b/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceIT.java index 86fd28023a..5ab4852340 100644 --- a/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceIT.java +++ b/runtime/catalog-karapace/src/test/java/io/aklivity/zilla/runtime/catalog/karapace/internal/KarapaceIT.java @@ -15,9 +15,6 @@ package io.aklivity.zilla.runtime.catalog.karapace.internal; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.rules.RuleChain.outerRule; import static org.mockito.Mockito.mock; @@ -39,16 +36,27 @@ import io.aklivity.zilla.runtime.engine.EngineContext; import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.model.function.ValueConsumer; +import io.aklivity.zilla.runtime.engine.test.EngineRule; +import io.aklivity.zilla.runtime.engine.test.annotation.Configuration; public class KarapaceIT { private final K3poRule k3po = new K3poRule() + .addScriptRoot("net", "io/aklivity/zilla/specs/engine/streams/network") + .addScriptRoot("app", "io/aklivity/zilla/specs/engine/streams/application") .addScriptRoot("local", "io/aklivity/zilla/runtime/catalog/karapace/internal"); private final TestRule timeout = new DisableOnDebug(new Timeout(10, SECONDS)); + private final EngineRule engine = new EngineRule() + .directory("target/zilla-itests") + .countersBufferCapacity(4096) + .configurationRoot("io/aklivity/zilla/specs/catalog/karapace/config") + .external("app0") + .clean(); + @Rule - public final TestRule chain = outerRule(k3po).around(timeout); + public final TestRule chain = outerRule(engine).around(k3po).around(timeout); private KarapaceOptionsConfig config; private EngineContext context = mock(EngineContext.class); @@ -64,89 +72,91 @@ public void setup() } @Test + @Configuration("resolve/schema/id/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.schema.via.schema.id" }) public void shouldResolveSchemaViaSchemaId() throws Exception { - String expected = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," + - "{\"name\":\"status\",\"type\":\"string\"}]," + - "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}"; - - KarapaceCatalogHandler catalog = new KarapaceCatalogHandler(config, context, 0L); - - String schema = catalog.resolve(9); - k3po.finish(); - - assertThat(schema, not(nullValue())); - assertEquals(expected, schema); } @Test + @Configuration("resolve/subject/version/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.schema.via.subject.version" }) - public void shouldResolveSchemaViaSubjectVersion() throws Exception + public void shouldResolveSchemaIdViaSubjectVersion() throws Exception { - String expected = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," + - "{\"name\":\"status\",\"type\":\"string\"}]," + - "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}"; - - KarapaceCatalogHandler catalog = new KarapaceCatalogHandler(config, context, 0L); - - int schemaId = catalog.resolve("items-snapshots-value", "latest"); - - String schema = catalog.resolve(schemaId); - k3po.finish(); - - assertEquals(schemaId, 9); - assertThat(schema, not(nullValue())); - assertEquals(expected, schema); } @Test + @Configuration("resolve/schema/id/cache/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.schema.via.schema.id" }) public void shouldResolveSchemaViaSchemaIdFromCache() throws Exception { - String expected = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," + - "{\"name\":\"status\",\"type\":\"string\"}]," + - "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}"; - - KarapaceCatalogHandler catalog = new KarapaceCatalogHandler(config, context, 0L); - - catalog.resolve(9); - k3po.finish(); - - String schema = catalog.resolve(9); - - assertThat(schema, not(nullValue())); - assertEquals(expected, schema); } @Test + @Configuration("resolve/subject/version/cache/zilla.yaml") @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", "${local}/resolve.schema.via.subject.version" }) - public void shouldResolveSchemaViaSubjectVersionFromCache() throws Exception + public void shouldResolveSchemaIdViaSubjectVersionFromCache() throws Exception { - String expected = "{\"fields\":[{\"name\":\"id\",\"type\":\"string\"}," + - "{\"name\":\"status\",\"type\":\"string\"}]," + - "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}"; - - KarapaceCatalogHandler catalog = new KarapaceCatalogHandler(config, context, 0L); - - catalog.resolve(catalog.resolve("items-snapshots-value", "latest")); + k3po.finish(); + } + @Test + @Configuration("unretrievable/schema/id/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.schema.via.schema.id.failed"}) + public void shouldLogFailedRegistryResponseForSchema() throws Exception + { k3po.finish(); + } - int schemaId = catalog.resolve("items-snapshots-value", "latest"); + @Test + @Configuration("unretrievable/schema/subject/version/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.schema.via.subject.version.failed"}) + public void shouldLogFailedRegistryResponseForSchemaId() throws Exception + { + k3po.finish(); + } - String schema = catalog.resolve(schemaId); + @Test + @Configuration("resolve/schema/id/retry/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.schema.via.schema.id.on.retry" }) + public void shouldResolveSchemaViaSchemaIdOnRetry() throws Exception + { + k3po.finish(); + } - assertEquals(schemaId, 9); - assertThat(schema, not(nullValue())); - assertEquals(expected, schema); + @Test + @Configuration("resolve/subject/version/retry/zilla.yaml") + @Specification({ + "${net}/handshake/client", + "${app}/handshake/server", + "${local}/resolve.schema.via.subject.version.retry"}) + public void shouldResolveSchemaIdFromCacheAndRetry() throws Exception + { + k3po.finish(); } @Test diff --git a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.failed.rpt b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.failed.rpt new file mode 100644 index 0000000000..96d4a27b52 --- /dev/null +++ b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.failed.rpt @@ -0,0 +1,27 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8081/schemas/ids/1" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:content-length +write close diff --git a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.on.retry.rpt b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.on.retry.rpt new file mode 100644 index 0000000000..f6cc39b199 --- /dev/null +++ b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.schema.id.on.retry.rpt @@ -0,0 +1,59 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8081/schemas/ids/1" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:content-length +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/vnd.schemaregistry.v1+json" +write http:content-length + +write '{' + '"schema":"' + '{' + '\\"fields\\":[' + '{' + '\\"name\\":\\"id\\",' + '\\"type\\":\\"string\\"' + '},' + '{' + '\\"name\\":\\"status\\",' + '\\"type\\":\\"string\\"' + '}' + '],' + '\\"name\\":\\"Event\\",' + '\\"namespace\\":\\"io.aklivity.example\\",' + '\\"type\\":\\"record\\"' + '}"' + '}' + +write close diff --git a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.failed.rpt b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.failed.rpt new file mode 100644 index 0000000000..0b3fe2ab5c --- /dev/null +++ b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.failed.rpt @@ -0,0 +1,27 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8081/subjects/items-snapshots-value/versions/latest" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:content-length +write close diff --git a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.retry.rpt b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.retry.rpt new file mode 100644 index 0000000000..0c98c18f30 --- /dev/null +++ b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.retry.rpt @@ -0,0 +1,97 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "http://localhost:8081/subjects/items-snapshots-value/versions/latest" + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/vnd.schemaregistry.v1+json" +write http:content-length + +write '{' + '"subject":"items-snapshots-value",' + '"id":9,' + '"version":"latest",' + '"schema":"' + '{' + '\\"fields\\":[' + '{' + '\\"name\\":\\"id\\",' + '\\"type\\":\\"string\\"' + '},' + '{' + '\\"name\\":\\"status\\",' + '\\"type\\":\\"string\\"' + '}' + '],' + '\\"name\\":\\"Event\\",' + '\\"namespace\\":\\"io.aklivity.example\\",' + '\\"type\\":\\"record\\"' + '}"' + '}' + +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "500" "Internal Server Error" +write http:content-length +write close + +accepted +connected + +read http:method "GET" +read http:version "HTTP/1.1" +read closed + +write http:status "200" "OK" +write http:header "content-type" "application/vnd.schemaregistry.v1+json" +write http:content-length + +write '{' + '"subject":"items-snapshots-value",' + '"id":10,' + '"version":"latest",' + '"schema":"' + '{' + '\\"fields\\":[' + '{' + '\\"name\\":\\"id\\",' + '\\"type\\":\\"int\\"' + '},' + '{' + '\\"name\\":\\"status\\",' + '\\"type\\":\\"string\\"' + '}' + '],' + '\\"name\\":\\"Event\\",' + '\\"namespace\\":\\"io.aklivity.example\\",' + '\\"type\\":\\"record\\"' + '}"' + '}' + +write close diff --git a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.rpt b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.rpt index 18d624a727..ce59f33d9d 100644 --- a/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.rpt +++ b/runtime/catalog-karapace/src/test/scripts/io/aklivity/zilla/runtime/catalog/karapace/internal/resolve.schema.via.subject.version.rpt @@ -49,37 +49,3 @@ write '{' '}' write close - -accept "http://localhost:8081/schemas/ids/9" - -accepted -connected - -read http:method "GET" -read http:version "HTTP/1.1" -read closed - -write http:status "200" "OK" -write http:header "content-type" "application/vnd.schemaregistry.v1+json" -write http:content-length - -write '{' - '"schema":"' - '{' - '\\"fields\\":[' - '{' - '\\"name\\":\\"id\\",' - '\\"type\\":\\"string\\"' - '},' - '{' - '\\"name\\":\\"status\\",' - '\\"type\\":\\"string\\"' - '}' - '],' - '\\"name\\":\\"Event\\",' - '\\"namespace\\":\\"io.aklivity.example\\",' - '\\"type\\":\\"record\\"' - '}"' - '}' - -write close diff --git a/runtime/command-metrics/pom.xml b/runtime/command-metrics/pom.xml index b8a5d062d9..d66192ff19 100644 --- a/runtime/command-metrics/pom.xml +++ b/runtime/command-metrics/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/command-start/pom.xml b/runtime/command-start/pom.xml index d3c8a7be68..9f962bcfb6 100644 --- a/runtime/command-start/pom.xml +++ b/runtime/command-start/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/command-stop/pom.xml b/runtime/command-stop/pom.xml index 9c840eb0fe..f7ad41a242 100644 --- a/runtime/command-stop/pom.xml +++ b/runtime/command-stop/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/command/pom.xml b/runtime/command/pom.xml index c179aab3fb..1e5b449c31 100644 --- a/runtime/command/pom.xml +++ b/runtime/command/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/common/pom.xml b/runtime/common/pom.xml index 9a00c5b9b3..8f973f8767 100644 --- a/runtime/common/pom.xml +++ b/runtime/common/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/engine/pom.xml b/runtime/engine/pom.xml index 8f71bfe53a..c2874c930a 100644 --- a/runtime/engine/pom.xml +++ b/runtime/engine/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java index 7c866f7707..c504dc9531 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/Engine.java @@ -68,6 +68,7 @@ import io.aklivity.zilla.runtime.engine.internal.Info; import io.aklivity.zilla.runtime.engine.internal.LabelManager; import io.aklivity.zilla.runtime.engine.internal.Tuning; +import io.aklivity.zilla.runtime.engine.internal.layouts.EventsLayout; import io.aklivity.zilla.runtime.engine.internal.registry.EngineManager; import io.aklivity.zilla.runtime.engine.internal.registry.EngineWorker; import io.aklivity.zilla.runtime.engine.internal.registry.FileWatcherTask; @@ -523,10 +524,20 @@ public int supplyLabelId( private final class EventReader implements MessageReader { + private final EventsLayout.EventAccessor[] accessors; private final EventFW eventRO = new EventFW(); private int minWorkerIndex; private long minTimeStamp; + EventReader() + { + accessors = new EventsLayout.EventAccessor[workers.size()]; + for (int i = 0; i < workers.size(); i++) + { + accessors[i] = workers.get(i).createEventAccessor(); + } + } + @Override public int read( MessageConsumer handler, @@ -542,7 +553,7 @@ public int read( for (int j = 0; j < workers.size(); j++) { final int workerIndex = j; - int eventPeeked = workers.get(workerIndex).peekEvent((m, b, i, l) -> + int eventPeeked = accessors[workerIndex].peekEvent((m, b, i, l) -> { eventRO.wrap(b, i, i + l); if (eventRO.timestamp() < minTimeStamp) @@ -556,7 +567,7 @@ public int read( empty = eventCount == 0; if (!empty) { - messagesRead += workers.get(minWorkerIndex).readEvent(handler, 1); + messagesRead += accessors[minWorkerIndex].readEvent(handler, 1); } } return messagesRead; diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/guard/GuardHandler.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/guard/GuardHandler.java index a9da2772fe..5294bfe0e4 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/guard/GuardHandler.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/guard/GuardHandler.java @@ -53,6 +53,16 @@ void deauthorize( String identity( long sessionId); + /* + * Returns the authorized credentials. + * + * @param sessionId the session identifier + * + * @return the authorized credentials + */ + String credentials( + long sessionId); + /* * Returns the session expiration time in UTC milliseconds. * diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/concurent/ManyToOneRingBuffer.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/concurent/ManyToOneRingBuffer.java index ae6ff01a23..22dca63a04 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/concurent/ManyToOneRingBuffer.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/concurent/ManyToOneRingBuffer.java @@ -31,6 +31,9 @@ package io.aklivity.zilla.runtime.engine.internal.concurent; import static org.agrona.BitUtil.align; +import static org.agrona.concurrent.ControlledMessageHandler.Action.ABORT; +import static org.agrona.concurrent.ControlledMessageHandler.Action.BREAK; +import static org.agrona.concurrent.ControlledMessageHandler.Action.COMMIT; import static org.agrona.concurrent.ringbuffer.RecordDescriptor.ALIGNMENT; import static org.agrona.concurrent.ringbuffer.RecordDescriptor.HEADER_LENGTH; import static org.agrona.concurrent.ringbuffer.RecordDescriptor.checkTypeId; @@ -48,6 +51,7 @@ import org.agrona.DirectBuffer; import org.agrona.UnsafeAccess; import org.agrona.concurrent.AtomicBuffer; +import org.agrona.concurrent.ControlledMessageHandler; import org.agrona.concurrent.MessageHandler; import org.agrona.concurrent.ringbuffer.RingBuffer; import org.agrona.concurrent.ringbuffer.RingBufferDescriptor; @@ -58,14 +62,9 @@ public class ManyToOneRingBuffer implements RingBuffer { /** - * Record type is padding to prevent fragmentation in the buffer. + * Minimal required capacity of the ring buffer excluding {@link RingBufferDescriptor#TRAILER_LENGTH}. */ - public static final int PADDING_MSG_TYPE_ID = -1; - - /** - * Buffer has insufficient capacity to record a message. - */ - private static final int INSUFFICIENT_CAPACITY = -2; + public static final int MIN_CAPACITY = HEADER_LENGTH; private final int capacity; private final int maxMsgLength; @@ -88,7 +87,7 @@ public class ManyToOneRingBuffer implements RingBuffer public ManyToOneRingBuffer(final AtomicBuffer buffer) { this.buffer = buffer; - checkCapacity(buffer.capacity()); + checkCapacity(buffer.capacity(), MIN_CAPACITY); capacity = buffer.capacity() - TRAILER_LENGTH; buffer.verifyAlignment(); @@ -125,8 +124,8 @@ public boolean write(final int msgTypeId, final DirectBuffer srcBuffer, final in if (INSUFFICIENT_CAPACITY != recordIndex) { - buffer.putInt(typeOffset(recordIndex), msgTypeId); buffer.putBytes(encodedMsgOffset(recordIndex), srcBuffer, srcIndex, length); + buffer.putInt(typeOffset(recordIndex), msgTypeId); buffer.putIntOrdered(lengthOffset(recordIndex), recordLength); isSuccessful = true; @@ -135,6 +134,55 @@ public boolean write(final int msgTypeId, final DirectBuffer srcBuffer, final in return isSuccessful; } + /** + * {@inheritDoc} + */ + public int tryClaim(final int msgTypeId, final int length) + { + checkTypeId(msgTypeId); + checkMsgLength(length); + + final AtomicBuffer buffer = this.buffer; + final int recordLength = length + HEADER_LENGTH; + final int recordIndex = claimCapacity(buffer, recordLength); + + if (INSUFFICIENT_CAPACITY == recordIndex) + { + return recordIndex; + } + + buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); + UnsafeAccess.UNSAFE.storeFence(); + buffer.putInt(typeOffset(recordIndex), msgTypeId); + + return encodedMsgOffset(recordIndex); + } + + /** + * {@inheritDoc} + */ + public void commit(final int index) + { + final int recordIndex = computeRecordIndex(index); + final AtomicBuffer buffer = this.buffer; + final int recordLength = verifyClaimedSpaceNotReleased(buffer, recordIndex); + + buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); + } + + /** + * {@inheritDoc} + */ + public void abort(final int index) + { + final int recordIndex = computeRecordIndex(index); + final AtomicBuffer buffer = this.buffer; + final int recordLength = verifyClaimedSpaceNotReleased(buffer, recordIndex); + + buffer.putInt(typeOffset(recordIndex), PADDING_MSG_TYPE_ID); + buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); + } + /** * {@inheritDoc} */ @@ -192,6 +240,82 @@ public int read(final MessageHandler handler, final int messageCountLimit) return messagesRead; } + public int controlledRead(final ControlledMessageHandler handler) + { + return controlledRead(handler, Integer.MAX_VALUE); + } + + /** + * {@inheritDoc} + */ + public int controlledRead(final ControlledMessageHandler handler, final int messageCountLimit) + { + int messagesRead = 0; + + final AtomicBuffer buffer = this.buffer; + final int headPositionIndex = this.headPositionIndex; + long head = buffer.getLong(headPositionIndex); + + final int capacity = this.capacity; + int headIndex = (int)head & (capacity - 1); + final int maxBlockLength = capacity - headIndex; + int bytesRead = 0; + + try + { + while (bytesRead < maxBlockLength && messagesRead < messageCountLimit) + { + final int recordIndex = headIndex + bytesRead; + final int recordLength = buffer.getIntVolatile(lengthOffset(recordIndex)); + if (recordLength <= 0) + { + break; + } + + final int alignedLength = align(recordLength, ALIGNMENT); + bytesRead += alignedLength; + + final int messageTypeId = buffer.getInt(typeOffset(recordIndex)); + if (PADDING_MSG_TYPE_ID == messageTypeId) + { + continue; + } + + final ControlledMessageHandler.Action action = handler.onMessage( + messageTypeId, buffer, recordIndex + HEADER_LENGTH, recordLength - HEADER_LENGTH); + + if (ABORT == action) + { + bytesRead -= alignedLength; + break; + } + + ++messagesRead; + + if (BREAK == action) + { + break; + } + if (COMMIT == action) + { + buffer.putLongOrdered(headPositionIndex, head + bytesRead); + headIndex += bytesRead; + head += bytesRead; + bytesRead = 0; + } + } + } + finally + { + if (bytesRead > 0) + { + buffer.putLongOrdered(headPositionIndex, head + bytesRead); + } + } + + return messagesRead; + } + /** * {@inheritDoc} */ @@ -253,6 +377,9 @@ public long consumerPosition() */ public int size() { + final AtomicBuffer buffer = this.buffer; + final int headPositionIndex = this.headPositionIndex; + final int tailPositionIndex = this.tailPositionIndex; long headBefore; long tail; long headAfter = buffer.getLongVolatile(headPositionIndex); @@ -265,7 +392,17 @@ public int size() } while (headAfter != headBefore); - return (int)(tail - headAfter); + final long size = tail - headAfter; + if (size < 0) + { + return 0; + } + else if (size > capacity) + { + return capacity; + } + + return (int)size; } /** @@ -321,54 +458,6 @@ else if (0 == length) return unblocked; } - /** - * {@inheritDoc} - */ - public int tryClaim(final int msgTypeId, final int length) - { - checkTypeId(msgTypeId); - checkMsgLength(length); - - final AtomicBuffer buffer = this.buffer; - final int recordLength = length + HEADER_LENGTH; - final int recordIndex = claimCapacity(buffer, recordLength); - - if (INSUFFICIENT_CAPACITY == recordIndex) - { - return recordIndex; - } - - buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); - UnsafeAccess.UNSAFE.storeFence(); - buffer.putInt(typeOffset(recordIndex), msgTypeId); - - return encodedMsgOffset(recordIndex); - } - - /** - * {@inheritDoc} - */ - public void commit(final int index) - { - final int recordIndex = computeRecordIndex(index); - final AtomicBuffer buffer = this.buffer; - final int recordLength = verifyClaimedSpaceNotReleased(buffer, recordIndex); - - buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); - } - - /** - * {@inheritDoc} - */ - public void abort(final int index) - { - final int recordIndex = computeRecordIndex(index); - final AtomicBuffer buffer = this.buffer; - final int recordLength = verifyClaimedSpaceNotReleased(buffer, recordIndex); - - buffer.putInt(typeOffset(recordIndex), PADDING_MSG_TYPE_ID); - buffer.putIntOrdered(lengthOffset(recordIndex), -recordLength); - } private static boolean scanBackToConfirmStillZeroed(final AtomicBuffer buffer, final int from, final int limit) { int i = from - ALIGNMENT; @@ -389,7 +478,11 @@ private static boolean scanBackToConfirmStillZeroed(final AtomicBuffer buffer, f private void checkMsgLength(final int length) { - if (length > maxMsgLength) + if (length < 0) + { + throw new IllegalArgumentException("invalid message length=" + length); + } + else if (length > maxMsgLength) { throw new IllegalArgumentException(String.format( "encoded message exceeds maxMsgLength of %d, length=%d", maxMsgLength, length)); diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayout.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayout.java index ee3670f16b..04cd8f602d 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayout.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayout.java @@ -28,7 +28,11 @@ import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; import org.agrona.CloseHelper; import org.agrona.DirectBuffer; @@ -46,20 +50,19 @@ public final class EventsLayout implements AutoCloseable { private final Path path; private final long capacity; + private final List accessors; private RingBuffer buffer; - private RingBufferSpy bufferSpy; private EventsLayout( Path path, long capacity, - RingBuffer buffer, - RingBufferSpy bufferSpy) + RingBuffer buffer) { this.path = path; this.capacity = capacity; this.buffer = buffer; - this.bufferSpy = bufferSpy; + this.accessors = new ArrayList<>(); } @Override @@ -82,17 +85,12 @@ public void writeEvent( } } - public int readEvent( - MessageConsumer handler, - int messageCountLimit) + public EventAccessor createEventAccessor() { - return bufferSpy.spy(handler, messageCountLimit); - } - - public int peekEvent( - MessageConsumer handler) - { - return bufferSpy.peek(handler); + RingBufferSpy ringBufferSpy = createRingBufferSpy(); + EventAccessor accessor = new EventAccessor(ringBufferSpy); + accessors.add(accessor); + return accessor; } private void rotateFile() @@ -110,7 +108,15 @@ private void rotateFile() rethrowUnchecked(ex); } buffer = createRingBuffer(path, capacity); - bufferSpy = createRingBufferSpy(path); + accessors.forEach(a -> a.addNextBufferSpy(createRingBufferSpy())); + } + + private RingBufferSpy createRingBufferSpy() + { + AtomicBuffer atomicBuffer = createAtomicBuffer(path, 0, false); + OneToOneRingBufferSpy spy = new OneToOneRingBufferSpy(atomicBuffer); + spy.spyAt(ZERO); + return spy; } private static AtomicBuffer createAtomicBuffer( @@ -135,13 +141,48 @@ private static RingBuffer createRingBuffer( return new OneToOneRingBuffer(atomicBuffer); } - private static RingBufferSpy createRingBufferSpy( - Path path) + public static final class EventAccessor { - AtomicBuffer atomicBuffer = createAtomicBuffer(path, 0, false); - OneToOneRingBufferSpy spy = new OneToOneRingBufferSpy(atomicBuffer); - spy.spyAt(ZERO); - return spy; + private final Queue nextBufferSpies; + private RingBufferSpy bufferSpy; + + private EventAccessor( + RingBufferSpy bufferSpy) + { + this.nextBufferSpies = new LinkedList<>(); + this.bufferSpy = bufferSpy; + } + + public int readEvent( + MessageConsumer handler, + int messageCountLimit) + { + int result = bufferSpy.spy(handler, messageCountLimit); + if (result == 0 && !nextBufferSpies.isEmpty()) + { + bufferSpy = nextBufferSpies.poll(); + result = bufferSpy.spy(handler, messageCountLimit); + } + return result; + } + + public int peekEvent( + MessageConsumer handler) + { + int result = bufferSpy.peek(handler); + if (result == 0 && !nextBufferSpies.isEmpty()) + { + bufferSpy = nextBufferSpies.poll(); + result = bufferSpy.peek(handler); + } + return result; + } + + private void addNextBufferSpy( + RingBufferSpy bufferSpy) + { + this.nextBufferSpies.add(bufferSpy); + } } public static final class Builder @@ -166,8 +207,7 @@ public Builder path( public EventsLayout build() { RingBuffer ringBuffer = createRingBuffer(path, capacity); - RingBufferSpy ringBufferSpy = createRingBufferSpy(path); - return new EventsLayout(path, capacity, ringBuffer, ringBufferSpy); + return new EventsLayout(path, capacity, ringBuffer); } } } diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java index 3ebac9de88..0d535e2d8a 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/registry/EngineWorker.java @@ -225,7 +225,7 @@ public class EngineWorker implements EngineContext, Agent private final HistogramsLayout histogramsLayout; private final EventsLayout eventsLayout; private final Supplier supplyEventReader; - private final EventFormatter eventFormatter; + private final EventFormatterFactory eventFormatterFactory; private long initialId; private long promiseId; @@ -435,7 +435,7 @@ public EngineWorker( this.errorHandler = errorHandler; this.exportersById = new Long2ObjectHashMap<>(); this.supplyEventReader = supplyEventReader; - this.eventFormatter = eventFormatterFactory.create(config, this); + this.eventFormatterFactory = eventFormatterFactory; } public static int indexOfId( @@ -1718,17 +1718,9 @@ public MessageConsumer supplyReceiver( return writersByIndex.computeIfAbsent(remoteIndex, supplyWriter); } - public int readEvent( - MessageConsumer handler, - int messageCountLimit) + public EventsLayout.EventAccessor createEventAccessor() { - return eventsLayout.readEvent(handler, messageCountLimit); - } - - public int peekEvent( - MessageConsumer handler) - { - return eventsLayout.peekEvent(handler); + return eventsLayout.createEventAccessor(); } public MessageReader supplyEventReader() @@ -1738,7 +1730,7 @@ public MessageReader supplyEventReader() public EventFormatter supplyEventFormatter() { - return this.eventFormatter; + return eventFormatterFactory.create(config, this); } private MessageConsumer supplyWriter( @@ -2132,7 +2124,7 @@ private void signal( } } - private static class Affinity + private static final class Affinity { BitSet mask; int nextIndex; diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/spy/OneToOneRingBufferSpy.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/spy/OneToOneRingBufferSpy.java index 4104b505ff..4f2d469b9d 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/spy/OneToOneRingBufferSpy.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/spy/OneToOneRingBufferSpy.java @@ -43,7 +43,7 @@ public OneToOneRingBufferSpy( final AtomicBuffer buffer) { this.buffer = buffer; - checkCapacity(buffer.capacity()); + checkCapacity(buffer.capacity(), 0); capacity = buffer.capacity() - TRAILER_LENGTH; buffer.verifyAlignment(); diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/StreamId.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/StreamId.java index 378332b9c4..e52d4eb35b 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/StreamId.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/StreamId.java @@ -71,6 +71,12 @@ public static boolean isInitial( return (streamId & 0x0000_0000_0000_0001L) != 0L; } + public static boolean isThrottle( + int typeId) + { + return (typeId & 0x4000_0000) != 0; + } + private static boolean isInitial( int instanceId) { diff --git a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/Target.java b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/Target.java index 39f79a60f7..354bcea507 100644 --- a/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/Target.java +++ b/runtime/engine/src/main/java/io/aklivity/zilla/runtime/engine/internal/stream/Target.java @@ -330,8 +330,8 @@ private void doSyntheticReset( .originId(syntheticId) .routedId(syntheticId) .streamId(streamId) - .sequence(-1L) - .acknowledge(-1L) + .sequence(Long.MAX_VALUE) + .acknowledge(0L) .maximum(0) .build(); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/ManyToOneRingBufferTest.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/ManyToOneRingBufferTest.java index 8f15d1a54d..6d4408c7ad 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/ManyToOneRingBufferTest.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/ManyToOneRingBufferTest.java @@ -201,8 +201,8 @@ public void shouldInsertPaddingRecordPlusMessageOnBufferWrapWithHeadEqualToTail( inOrder.verify(buffer).putInt(lengthOffset(alignedRecordLength), 0); inOrder.verify(buffer).putLongOrdered(TAIL_COUNTER_INDEX, tail + alignedRecordLength + HEADER_LENGTH); - inOrder.verify(buffer).putInt(typeOffset(0), MSG_TYPE_ID); inOrder.verify(buffer).putBytes(encodedMsgOffset(0), srcBuffer, srcIndex, length); + inOrder.verify(buffer).putInt(typeOffset(0), MSG_TYPE_ID); inOrder.verify(buffer).putIntOrdered(lengthOffset(0), recordLength); } @@ -408,7 +408,7 @@ public void shouldCalculateCapacityForBuffer() assertThat(ringBuffer.capacity(), equalTo(CAPACITY)); } - @Test(expected = IllegalStateException.class) + @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionForCapacityThatIsNotPowerOfTwo() { final int capacity = 777; diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/bench/BufferBM.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/bench/BufferBM.java index 2b84b74e72..112dd0aedf 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/bench/BufferBM.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/concurrent/bench/BufferBM.java @@ -30,7 +30,6 @@ import org.agrona.MutableDirectBuffer; import org.agrona.concurrent.AtomicBuffer; import org.agrona.concurrent.UnsafeBuffer; -import org.agrona.concurrent.ringbuffer.ManyToOneRingBuffer; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; @@ -51,6 +50,8 @@ import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; +import io.aklivity.zilla.runtime.engine.internal.concurent.ManyToOneRingBuffer; + @State(Scope.Benchmark) @BenchmarkMode(Mode.Throughput) @Fork(3) diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayoutTest.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayoutTest.java index a0aeda974b..c0078a49df 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayoutTest.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/internal/layouts/EventsLayoutTest.java @@ -15,8 +15,8 @@ */ package io.aklivity.zilla.runtime.engine.internal.layouts; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; -import static org.junit.Assert.assertThat; import java.nio.file.Path; import java.nio.file.Paths; @@ -42,9 +42,10 @@ public void shouldWriteAndReadEvents() .build(); layout.writeEvent(42, new UnsafeBuffer(), 0, 0); msgTypeId = 0; + EventsLayout.EventAccessor accessor = layout.createEventAccessor(); // WHEN - int count = layout.readEvent(this::readEvent, 1); + int count = accessor.readEvent(this::readEvent, 1); // THEN assertThat(count, equalTo(1)); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java index 543bf5ea67..bb43baa392 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("server.event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/DuplexIT.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/DuplexIT.java index ee4e530291..a00df66314 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/DuplexIT.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/DuplexIT.java @@ -198,6 +198,16 @@ public void shouldReadAndWriteIntegersInNetworkByteOrder() throws Exception k3po.finish(); } + @Test + @Specification({ + "timestamps.false/client", + "timestamps.false/server" + }) + public void shouldConnectWithoutTimestamps() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "client.sent.data/client", diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java index a56b723aff..22c7112144 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/TestBindingFactory.java @@ -27,10 +27,14 @@ import io.aklivity.zilla.runtime.engine.binding.function.MessageConsumer; import io.aklivity.zilla.runtime.engine.catalog.CatalogHandler; import io.aklivity.zilla.runtime.engine.config.BindingConfig; +import io.aklivity.zilla.runtime.engine.config.CatalogedConfig; import io.aklivity.zilla.runtime.engine.config.RouteConfig; +import io.aklivity.zilla.runtime.engine.config.SchemaConfig; import io.aklivity.zilla.runtime.engine.guard.GuardHandler; import io.aklivity.zilla.runtime.engine.namespace.NamespacedId; import io.aklivity.zilla.runtime.engine.test.internal.binding.config.TestBindingOptionsConfig; +import io.aklivity.zilla.runtime.engine.test.internal.binding.config.TestBindingOptionsConfig.CatalogAssertion; +import io.aklivity.zilla.runtime.engine.test.internal.binding.config.TestBindingOptionsConfig.Event; import io.aklivity.zilla.runtime.engine.test.internal.event.TestEventContext; import io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.OctetsFW; import io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.stream.AbortFW; @@ -73,9 +77,11 @@ final class TestBindingFactory implements BindingHandler private final TestEventContext event; private List catalogs; + private SchemaConfig catalog; + private List catalogAssertions; private GuardHandler guard; private String credentials; - private List events; + private List events; private int eventIndex; TestBindingFactory( @@ -102,15 +108,18 @@ public void attach( TestBindingOptionsConfig options = (TestBindingOptionsConfig) binding.options; if (options != null) { - if (options.catalogs != null) + if (options.cataloged != null) { + this.catalog = options.cataloged.size() != 0 ? options.cataloged.get(0).schemas.get(0) : null; this.catalogs = new LinkedList<>(); - for (String catalog : options.catalogs) + for (CatalogedConfig catalog : options.cataloged) { int namespaceId = context.supplyTypeId(binding.namespace); - int catalogId = context.supplyTypeId(catalog); + int catalogId = context.supplyTypeId(catalog.name); catalogs.add(context.supplyCatalog(NamespacedId.id(namespaceId, catalogId))); } + this.catalogAssertions = options.catalogAssertions != null && !options.catalogAssertions.isEmpty() ? + options.catalogAssertions.get(0).assertions : null; } if (options.authorization != null) { @@ -246,9 +255,51 @@ private void onInitialBegin( if (catalogs != null) { - for (CatalogHandler catalog : catalogs) + CatalogHandler handler = catalogs.get(0); + if (catalogAssertions != null && !catalogAssertions.isEmpty()) { - catalog.resolve(0); + for (CatalogAssertion assertion : catalogAssertions) + { + try + { + Thread.sleep(assertion.delay); + } + catch (Exception ex) + { + throw new RuntimeException(ex); + } + if (catalog.subject != null && catalog.version != null) + { + int id = handler.resolve(catalog.subject, catalog.version); + if (id != assertion.id) + { + doInitialReset(traceId); + } + } + else + { + String schema = handler.resolve(catalog.id); + if (assertion.schema == null && schema != null) + { + doInitialReset(traceId); + } + else if (assertion.schema != null && !assertion.schema.equals(schema)) + { + doInitialReset(traceId); + } + } + } + } + else + { + if (catalog.subject != null && catalog.version != null) + { + handler.resolve(catalog.subject, catalog.version); + } + else + { + handler.resolve(catalog.id); + } } } if (guard != null) @@ -257,7 +308,7 @@ private void onInitialBegin( } while (events != null && eventIndex < events.size()) { - TestBindingOptionsConfig.Event e = events.get(eventIndex); + Event e = events.get(eventIndex); event.connected(traceId, routedId, e.timestamp, e.message); eventIndex++; } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java index 96e006b403..69ff33e9f3 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfig.java @@ -18,14 +18,16 @@ import java.util.List; import java.util.function.Function; +import io.aklivity.zilla.runtime.engine.config.CatalogedConfig; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; public final class TestBindingOptionsConfig extends OptionsConfig { public final String mode; public final TestAuthorizationConfig authorization; - public final List catalogs; + public final List cataloged; public final List events; + public final List catalogAssertions; public static TestBindingOptionsConfigBuilder builder() { @@ -41,13 +43,15 @@ public static TestBindingOptionsConfigBuilder builder( TestBindingOptionsConfig( String mode, TestAuthorizationConfig authorization, - List catalogs, - List events) + List cataloged, + List events, + List catalogAssertions) { this.mode = mode; this.authorization = authorization; - this.catalogs = catalogs; + this.cataloged = cataloged; this.events = events; + this.catalogAssertions = catalogAssertions; } public static final class Event @@ -63,4 +67,35 @@ public Event( this.message = message; } } + + public static final class CatalogAssertions + { + public final String name; + public final List assertions; + + public CatalogAssertions( + String name, + List assertions) + { + this.name = name; + this.assertions = assertions; + } + } + + public static final class CatalogAssertion + { + public final int id; + public final String schema; + public final long delay; + + public CatalogAssertion( + int id, + String schema, + long delay) + { + this.id = id; + this.schema = schema; + this.delay = delay; + } + } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java index 6a0b4878d1..6840c32814 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigAdapter.java @@ -15,26 +15,37 @@ */ package io.aklivity.zilla.runtime.engine.test.internal.binding.config; +import java.util.LinkedList; +import java.util.List; + import jakarta.json.Json; import jakarta.json.JsonArray; import jakarta.json.JsonArrayBuilder; import jakarta.json.JsonObject; import jakarta.json.JsonObjectBuilder; -import jakarta.json.JsonString; import jakarta.json.JsonValue; +import io.aklivity.zilla.runtime.engine.config.CatalogedConfig; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; import io.aklivity.zilla.runtime.engine.config.OptionsConfigAdapterSpi; +import io.aklivity.zilla.runtime.engine.config.SchemaConfig; +import io.aklivity.zilla.runtime.engine.config.SchemaConfigAdapter; public final class TestBindingOptionsConfigAdapter implements OptionsConfigAdapterSpi { private static final String MODE_NAME = "mode"; - private static final String CATALOGS_NAME = "catalogs"; + private static final String CATALOG_NAME = "catalog"; private static final String AUTHORIZATION_NAME = "authorization"; private static final String CREDENTIALS_NAME = "credentials"; private static final String EVENTS_NAME = "events"; private static final String TIMESTAMP_NAME = "timestamp"; private static final String MESSAGE_NAME = "message"; + private static final String ASSERTIONS_NAME = "assertions"; + private static final String ID_NAME = "id"; + private static final String SCHEMA_NAME = "schema"; + private static final String DELAY_NAME = "delay"; + + private final SchemaConfigAdapter schema = new SchemaConfigAdapter(); @Override public Kind kind() @@ -60,14 +71,39 @@ public JsonObject adaptToJson( { object.add(MODE_NAME, testOptions.mode); } - if (testOptions.catalogs != null) + if (testOptions.cataloged != null && !testOptions.cataloged.isEmpty()) { - JsonArrayBuilder catalogs = Json.createArrayBuilder(); - for (String catalog : testOptions.catalogs) + JsonObjectBuilder catalogs = Json.createObjectBuilder(); + for (CatalogedConfig catalog : testOptions.cataloged) { - catalogs.add(catalog); + JsonArrayBuilder array = Json.createArrayBuilder(); + for (SchemaConfig schemaItem: catalog.schemas) + { + array.add(schema.adaptToJson(schemaItem)); + } + catalogs.add(catalog.name, array); + } + object.add(CATALOG_NAME, catalogs); + } + if (testOptions.catalogAssertions != null) + { + JsonObjectBuilder assertions = Json.createObjectBuilder(); + JsonObjectBuilder catalogAssertions = Json.createObjectBuilder(); + for (TestBindingOptionsConfig.CatalogAssertions c : testOptions.catalogAssertions) + { + JsonArrayBuilder array = Json.createArrayBuilder(); + for (TestBindingOptionsConfig.CatalogAssertion a: c.assertions) + { + JsonObjectBuilder assertion = Json.createObjectBuilder(); + assertion.add(ID_NAME, a.id); + assertion.add(SCHEMA_NAME, a.schema); + assertion.add(DELAY_NAME, a.delay); + array.add(assertion); + } + catalogAssertions.add(c.name, array); } - object.add(CATALOGS_NAME, catalogs); + assertions.add(CATALOG_NAME, catalogAssertions); + object.add(ASSERTIONS_NAME, assertions); } if (testOptions.authorization != null) { @@ -105,12 +141,44 @@ public OptionsConfig adaptFromJson( { testOptions.mode(object.getString(MODE_NAME)); } - if (object.containsKey(CATALOGS_NAME)) + if (object.containsKey(CATALOG_NAME)) { - JsonArray catalogs = object.getJsonArray(CATALOGS_NAME); - for (JsonValue catalog : catalogs) + JsonObject catalogsJson = object.getJsonObject(CATALOG_NAME); + List catalogs = new LinkedList<>(); + for (String catalogName: catalogsJson.keySet()) { - testOptions.catalog(((JsonString) catalog).getString()); + JsonArray schemasJson = catalogsJson.getJsonArray(catalogName); + List schemas = new LinkedList<>(); + for (JsonValue item : schemasJson) + { + JsonObject schemaJson = (JsonObject) item; + SchemaConfig schemaElement = schema.adaptFromJson(schemaJson); + schemas.add(schemaElement); + } + catalogs.add(new CatalogedConfig(catalogName, schemas)); + } + testOptions.catalog(catalogs); + } + if (object.containsKey(ASSERTIONS_NAME)) + { + JsonObject assertionsJson = object.getJsonObject(ASSERTIONS_NAME); + if (assertionsJson.containsKey(CATALOG_NAME)) + { + JsonObject catalogsJson = assertionsJson.getJsonObject(CATALOG_NAME); + for (String catalogName: catalogsJson.keySet()) + { + JsonArray catalogAssertionsJson = catalogsJson.getJsonArray(catalogName); + List catalogAssertions = new LinkedList<>(); + for (JsonValue assertion : catalogAssertionsJson) + { + JsonObject c = assertion.asJsonObject(); + catalogAssertions.add(new TestBindingOptionsConfig.CatalogAssertion( + c.containsKey(ID_NAME) ? c.getInt(ID_NAME) : 0, + c.containsKey(SCHEMA_NAME) ? !c.isNull(SCHEMA_NAME) ? c.getString(SCHEMA_NAME) : null : null, + c.containsKey(DELAY_NAME) ? c.getJsonNumber(DELAY_NAME).longValue() : 0L)); + } + testOptions.catalogAssertions(catalogName, catalogAssertions); + } } } if (object.containsKey(AUTHORIZATION_NAME)) diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java index dadfe4a81f..4ceeb1aa42 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/binding/config/TestBindingOptionsConfigBuilder.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.function.Function; +import io.aklivity.zilla.runtime.engine.config.CatalogedConfig; import io.aklivity.zilla.runtime.engine.config.ConfigBuilder; import io.aklivity.zilla.runtime.engine.config.OptionsConfig; @@ -28,8 +29,9 @@ public final class TestBindingOptionsConfigBuilder extends ConfigBuilder catalogs; + private List catalogs; private List events; + private List catalogAssertions; TestBindingOptionsConfigBuilder( Function mapper) @@ -52,13 +54,9 @@ public TestBindingOptionsConfigBuilder mode( } public TestBindingOptionsConfigBuilder catalog( - String catalog) + List catalogs) { - if (this.catalogs == null) - { - this.catalogs = new LinkedList<>(); - } - this.catalogs.add(catalog); + this.catalogs = catalogs; return this; } @@ -82,9 +80,21 @@ public TestBindingOptionsConfigBuilder event( return this; } + public TestBindingOptionsConfigBuilder catalogAssertions( + String name, + List assertions) + { + if (this.catalogAssertions == null) + { + this.catalogAssertions = new LinkedList<>(); + } + this.catalogAssertions.add(new TestBindingOptionsConfig.CatalogAssertions(name, assertions)); + return this; + } + @Override public T build() { - return mapper.apply(new TestBindingOptionsConfig(mode, authorization, catalogs, events)); + return mapper.apply(new TestBindingOptionsConfig(mode, authorization, catalogs, events, catalogAssertions)); } } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/guard/TestGuardHandler.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/guard/TestGuardHandler.java index ccc663209e..de967814c9 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/guard/TestGuardHandler.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/guard/TestGuardHandler.java @@ -84,6 +84,13 @@ public String identity( return "test"; } + @Override + public String credentials( + long sessionId) + { + return credentials; + } + @Override public long expiresAt( long sessionId) diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaChannelConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaChannelConfig.java index 08295df459..4724da6644 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaChannelConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaChannelConfig.java @@ -26,6 +26,7 @@ import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_SHARED_WINDOW; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_STREAM_ID; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_THROTTLE; +import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TIMESTAMPS; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TRANSMISSION; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_UPDATE; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_WINDOW; @@ -49,11 +50,13 @@ public class DefaultZillaChannelConfig extends DefaultChannelConfig implements Z private ZillaUpdateMode update = ZillaUpdateMode.STREAM; private long affinity; private byte capabilities; + private boolean timestamps; public DefaultZillaChannelConfig() { super(); setBufferFactory(NATIVE_BUFFER_FACTORY); + setTimestamps(true); } @Override @@ -189,6 +192,19 @@ public byte getCapabilities() return capabilities; } + @Override + public void setTimestamps( + boolean timestamps) + { + this.timestamps = timestamps; + } + + @Override + public boolean hasTimestamps() + { + return timestamps; + } + @Override protected boolean setOption0( String key, @@ -242,6 +258,10 @@ else if (OPTION_CAPABILITIES.getName().equals(key)) { setCapabilities(convertToByte(value)); } + else if (OPTION_TIMESTAMPS.getName().equals(key)) + { + setTimestamps(Boolean.parseBoolean(Objects.toString(value, "false"))); + } else { return false; diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaServerChannelConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaServerChannelConfig.java index 1a917a8f53..7bfefbd95e 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaServerChannelConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/DefaultZillaServerChannelConfig.java @@ -25,6 +25,7 @@ import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_SHARED_WINDOW; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_STREAM_ID; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_THROTTLE; +import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TIMESTAMPS; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TRANSMISSION; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_UPDATE; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_WINDOW; @@ -48,11 +49,13 @@ public class DefaultZillaServerChannelConfig extends DefaultServerChannelConfig private ZillaUpdateMode update = ZillaUpdateMode.STREAM; private long affinity; private byte capabilities; + private boolean timestamps; public DefaultZillaServerChannelConfig() { super(); setBufferFactory(NATIVE_BUFFER_FACTORY); + setTimestamps(true); } @Override @@ -189,6 +192,19 @@ public byte getCapabilities() return capabilities; } + @Override + public void setTimestamps( + boolean timestamps) + { + this.timestamps = timestamps; + } + + @Override + public boolean hasTimestamps() + { + return timestamps; + } + @Override protected boolean setOption0( String key, @@ -239,6 +255,10 @@ else if (OPTION_CAPABILITIES.getName().equals(key)) { setCapabilities(convertToByte(value)); } + else if (OPTION_TIMESTAMPS.getName().equals(key)) + { + setTimestamps(Boolean.parseBoolean(Objects.toString(value, "false"))); + } else { return false; diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannel.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannel.java index 69f3267edc..8416d4a8af 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannel.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannel.java @@ -213,6 +213,11 @@ public String toString() return String.format("%s [sourceId=%d, targetId=%d]", description, sourceId, targetId); } + public long timestamp() + { + return getConfig().hasTimestamps() ? System.nanoTime() : 0L; + } + public void acknowledgeBytes( int reserved) { diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelAddressFactory.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelAddressFactory.java index 04ad0df527..8badcf6604 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelAddressFactory.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelAddressFactory.java @@ -23,6 +23,7 @@ import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_REPLY_TO; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_STREAM_ID; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_THROTTLE; +import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TIMESTAMPS; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_TRANSMISSION; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_UPDATE; import static io.aklivity.zilla.runtime.engine.test.internal.k3po.ext.types.ZillaTypeSystem.OPTION_WINDOW; @@ -75,7 +76,7 @@ protected ChannelAddress newChannelAddress0( Collection> allOptionTypes = asList(OPTION_EPHEMERAL, OPTION_REPLY_TO, OPTION_WINDOW, OPTION_BUDGET_ID, OPTION_STREAM_ID, OPTION_PADDING, OPTION_UPDATE, OPTION_AUTHORIZATION, OPTION_THROTTLE, - OPTION_TRANSMISSION, OPTION_BYTE_ORDER); + OPTION_TRANSMISSION, OPTION_BYTE_ORDER, OPTION_TIMESTAMPS); for (TypeInfo optionType : allOptionTypes) { if (options != null && options.containsKey(optionType.getName())) diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelConfig.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelConfig.java index 134f0a60f0..1cdaa52a35 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelConfig.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaChannelConfig.java @@ -60,4 +60,8 @@ public interface ZillaChannelConfig extends ChannelConfig void setCapabilities(byte capabilities); byte getCapabilities(); + + void setTimestamps(boolean timestamps); + + boolean hasTimestamps(); } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaEngine.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaEngine.java index 7033437c59..4fd1550010 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaEngine.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaEngine.java @@ -285,7 +285,7 @@ private ZillaScope newScope( int scopeIndex) { ZillaScope scope = new ZillaScope(config, labels, scopeIndex, this::lookupTargetIndex, - System::nanoTime, traceIds::incrementAndGet); + traceIds::incrementAndGet); this.scopes = ArrayUtil.add(this.scopes, scope); return scope; } diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaPartition.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaPartition.java index cc6fcd6aba..8ff4988344 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaPartition.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaPartition.java @@ -416,6 +416,7 @@ private ZillaChildChannel doAccept( childConfig.setPadding(serverConfig.getPadding()); childConfig.setAlignment(serverConfig.getAlignment()); childConfig.setCapabilities(serverConfig.getCapabilities()); + childConfig.setTimestamps(serverConfig.hasTimestamps()); if (childConfig.getTransmission() == SIMPLEX) { diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaScope.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaScope.java index 1a6bbf5886..5e6cfd8bf6 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaScope.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaScope.java @@ -57,7 +57,6 @@ public final class ZillaScope implements AutoCloseable private final Long2ObjectHashMap throttlesById; private final Long2ObjectHashMap correlations; private final ToIntFunction lookupTargetIndex; - private final LongSupplier supplyTimestamp; private final LongSupplier supplyTraceId; private final ZillaSource source; @@ -68,7 +67,6 @@ public ZillaScope( LabelManager labels, int scopeIndex, ToIntFunction lookupTargetIndex, - LongSupplier supplyTimestamp, LongSupplier supplyTraceId) { this.config = config; @@ -81,7 +79,6 @@ public ZillaScope( this.targetsByIndex = new Int2ObjectHashMap<>(); this.debitorsByIndex = new Int2ObjectHashMap<>(); this.lookupTargetIndex = lookupTargetIndex; - this.supplyTimestamp = supplyTimestamp; this.supplyTraceId = supplyTraceId; this.source = new ZillaSource(config, scopeIndex, supplyTraceId, correlations::remove, this::supplySender, this::supplyTarget, @@ -365,7 +362,7 @@ private ZillaTarget newTarget( final ZillaTarget target = new ZillaTarget(source.scopeIndex(), targetPath, layout, writeBuffer, throttlesById::put, throttlesById::remove, correlations::put, - supplyTimestamp, supplyTraceId); + supplyTraceId); this.targets = ArrayUtil.add(this.targets, target); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaStreamFactory.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaStreamFactory.java index d826b33978..cc26a2396c 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaStreamFactory.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaStreamFactory.java @@ -105,7 +105,7 @@ public void doChallenge( final int maximum = channel.sourceMax(); final ZillaTarget sender = supplySender.apply(streamId); - sender.doChallenge(originId, routedId, streamId, sequence, acknowledge, traceId, maximum, challengeExt); + sender.doChallenge(channel, originId, routedId, streamId, sequence, acknowledge, traceId, maximum, challengeExt); } public MessageHandler newStream( diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaTarget.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaTarget.java index fdb89d99b5..e3e357b5b9 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaTarget.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/behavior/ZillaTarget.java @@ -104,7 +104,6 @@ final class ZillaTarget implements AutoCloseable private final LongConsumer unregisterThrottle; private final MutableDirectBuffer writeBuffer; private final LongObjectBiConsumer correlateNew; - private final LongSupplier supplyTimestamp; private final LongSupplier supplyTraceId; ZillaTarget( @@ -115,7 +114,6 @@ final class ZillaTarget implements AutoCloseable LongObjectBiConsumer registerThrottle, LongConsumer unregisterThrottle, LongObjectBiConsumer correlateNew, - LongSupplier supplyTimestamp, LongSupplier supplyTraceId) { this.scopeIndex = scopeIndex; @@ -127,7 +125,6 @@ final class ZillaTarget implements AutoCloseable this.registerThrottle = registerThrottle; this.unregisterThrottle = unregisterThrottle; this.correlateNew = correlateNew; - this.supplyTimestamp = supplyTimestamp; this.supplyTraceId = supplyTraceId; } @@ -154,6 +151,7 @@ public void doSystemWindow( int maximum) { final WindowFW window = windowRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) .routedId(0L) .streamId(0L) .sequence(0L) @@ -172,6 +170,7 @@ public void doSystemFlush( long budgetId) { final FlushFW flush = flushRW.wrap(writeBuffer, 0, writeBuffer.capacity()) + .originId(0L) .routedId(0L) .streamId(0L) .sequence(0L) @@ -268,7 +267,7 @@ public void doConnect( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(client.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(authorization) .affinity(affinity) @@ -332,14 +331,14 @@ public void operationComplete( } public void doConnectAbort( - ZillaClientChannel clientChannel) + ZillaClientChannel client) { - final long originId = clientChannel.originId(); - final long routedId = clientChannel.routedId(); - final long initialId = clientChannel.targetId(); - final long sequence = clientChannel.targetSeq(); - final long acknowledge = clientChannel.targetAck(); - final int maximum = clientChannel.targetMax(); + final long originId = client.originId(); + final long routedId = client.routedId(); + final long initialId = client.targetId(); + final long sequence = client.targetSeq(); + final long acknowledge = client.targetAck(); + final int maximum = client.targetMax(); final AbortFW abort = abortRW.wrap(writeBuffer, 0, writeBuffer.capacity()) .originId(originId) @@ -348,7 +347,7 @@ public void doConnectAbort( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(client.timestamp()) .traceId(supplyTraceId.getAsLong()) .build(); @@ -388,7 +387,7 @@ public void doBeginReply( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .affinity(affinity) .extension(p -> p.set(beginExtCopy)) @@ -493,7 +492,7 @@ private void doAdviseOutputFlush( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(authorization) .budgetId(budgetId) @@ -533,7 +532,7 @@ public void doAbortOutput( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(authorization) .extension(p -> p.set(abortExtCopy)) @@ -583,7 +582,7 @@ public void doShutdownOutput( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(authorization) .extension(p -> p.set(endExtCopy)) @@ -629,7 +628,7 @@ public void doClose( .sequence(sequence) .acknowledge(acknowledge) .maximum(channel.targetMax()) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(channel.targetAuth()) .extension(p -> p.set(endExtCopy)) @@ -765,7 +764,7 @@ private boolean flushData( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .authorization(authorization) .flags(flags) @@ -837,7 +836,7 @@ void doWindow( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .budgetId(budgetId) .padding(padding) @@ -878,7 +877,6 @@ void doReset( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) .traceId(traceId) .build(); @@ -906,7 +904,7 @@ void doAbortInput( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(traceId) .extension(p -> p.set(extensionCopy)) .build(); @@ -915,6 +913,7 @@ void doAbortInput( } void doChallenge( + final ZillaChannel channel, final long originId, final long routedId, final long streamId, @@ -933,7 +932,7 @@ void doChallenge( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(traceId) .extension(p -> p.set(extensionCopy)) .build(); @@ -1126,7 +1125,7 @@ private void onHandshakeCompleted( .sequence(sequence) .acknowledge(acknowledge) .maximum(maximum) - .timestamp(supplyTimestamp.getAsLong()) + .timestamp(channel.timestamp()) .traceId(supplyTraceId.getAsLong()) .build(); diff --git a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/types/ZillaTypeSystem.java b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/types/ZillaTypeSystem.java index d404938aef..e3c5556390 100644 --- a/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/types/ZillaTypeSystem.java +++ b/runtime/engine/src/test/java/io/aklivity/zilla/runtime/engine/test/internal/k3po/ext/types/ZillaTypeSystem.java @@ -45,6 +45,7 @@ public final class ZillaTypeSystem implements TypeSystemSpi public static final TypeInfo OPTION_ALIGNMENT = new TypeInfo<>("alignment", String.class); public static final TypeInfo OPTION_AFFINITY = new TypeInfo<>("affinity", Long.class); public static final TypeInfo OPTION_CAPABILITIES = new TypeInfo<>("capabilities", Byte.class); + public static final TypeInfo OPTION_TIMESTAMPS = new TypeInfo<>("timestamps", String.class); public static final TypeInfo OPTION_FLAGS = new TypeInfo<>("flags", Integer.class); public static final TypeInfo OPTION_ACK = new TypeInfo<>("ack", Integer.class); @@ -93,6 +94,7 @@ public ZillaTypeSystem() acceptOptions.add(OPTION_BYTE_ORDER); acceptOptions.add(OPTION_ALIGNMENT); acceptOptions.add(OPTION_CAPABILITIES); + acceptOptions.add(OPTION_TIMESTAMPS); this.acceptOptions = unmodifiableSet(acceptOptions); Set> connectOptions = new LinkedHashSet<>(); @@ -111,6 +113,7 @@ public ZillaTypeSystem() connectOptions.add(OPTION_ALIGNMENT); connectOptions.add(OPTION_AFFINITY); connectOptions.add(OPTION_CAPABILITIES); + connectOptions.add(OPTION_TIMESTAMPS); this.connectOptions = unmodifiableSet(connectOptions); Set> readOptions = new LinkedHashSet<>(); diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt b/runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/client.rpt similarity index 80% rename from specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt rename to runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/client.rpt index 73deb25750..42f208bfae 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/client.rpt +++ b/runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/client.rpt @@ -14,7 +14,8 @@ # under the License. # -connect "zilla://streams/net0" - option zilla:window 8192 - +connect "zilla://streams/server#0" + option zilla:transmission "duplex" + option zilla:window 8192 + option zilla:timestamps "false" connected diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt b/runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/server.rpt similarity index 81% rename from specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt rename to runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/server.rpt index f48bc644a1..7016cbf838 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/event/server.rpt +++ b/runtime/engine/src/test/scripts/io/aklivity/zilla/runtime/engine/test/k3po/ext/duplex/timestamps.false/server.rpt @@ -14,8 +14,10 @@ # under the License. # -accept "zilla://streams/net0" - option zilla:window 8192 +accept "zilla://streams/server#0" + option zilla:transmission "duplex" + option zilla:window 8192 + option zilla:timestamps "false" accepted connected diff --git a/runtime/exporter-otlp/pom.xml b/runtime/exporter-otlp/pom.xml index 85ac746f1b..6deb81e934 100644 --- a/runtime/exporter-otlp/pom.xml +++ b/runtime/exporter-otlp/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/exporter-otlp/src/test/java/io/aklivity/zilla/runtime/exporter/otlp/internal/EventIT.java b/runtime/exporter-otlp/src/test/java/io/aklivity/zilla/runtime/exporter/otlp/internal/EventIT.java index 51fe527631..efa6b44ea0 100644 --- a/runtime/exporter-otlp/src/test/java/io/aklivity/zilla/runtime/exporter/otlp/internal/EventIT.java +++ b/runtime/exporter-otlp/src/test/java/io/aklivity/zilla/runtime/exporter/otlp/internal/EventIT.java @@ -23,6 +23,7 @@ import org.junit.rules.DisableOnDebug; import org.junit.rules.TestRule; import org.junit.rules.Timeout; +import org.kaazing.k3po.junit.annotation.ScriptProperty; import org.kaazing.k3po.junit.annotation.Specification; import org.kaazing.k3po.junit.rules.K3poRule; @@ -52,9 +53,11 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", + "${net}/handshake/client", + "${net}/handshake/server", "${app}/event/server" }) + @ScriptProperty("serverAddress \"zilla://streams/app0\"") public void shouldPostEventLogToOtlpCollector() throws Exception { k3po.finish(); diff --git a/runtime/exporter-prometheus/pom.xml b/runtime/exporter-prometheus/pom.xml index 9b0cb1090b..1e6c7d23d6 100644 --- a/runtime/exporter-prometheus/pom.xml +++ b/runtime/exporter-prometheus/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/exporter-prometheus/src/main/java/io/aklivity/zilla/runtime/exporter/prometheus/internal/PrometheusExporterHandler.java b/runtime/exporter-prometheus/src/main/java/io/aklivity/zilla/runtime/exporter/prometheus/internal/PrometheusExporterHandler.java index 11c6ae904b..f69d67c470 100644 --- a/runtime/exporter-prometheus/src/main/java/io/aklivity/zilla/runtime/exporter/prometheus/internal/PrometheusExporterHandler.java +++ b/runtime/exporter-prometheus/src/main/java/io/aklivity/zilla/runtime/exporter/prometheus/internal/PrometheusExporterHandler.java @@ -122,7 +122,7 @@ private String generateOutput() return output; } - private class MetricsHttpHandler implements HttpHandler + private final class MetricsHttpHandler implements HttpHandler { private static final int NO_RESPONSE_BODY = -1; diff --git a/runtime/exporter-stdout/pom.xml b/runtime/exporter-stdout/pom.xml index 0a5e339404..495e134595 100644 --- a/runtime/exporter-stdout/pom.xml +++ b/runtime/exporter-stdout/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java b/runtime/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java index b31462dda6..c5b019b33e 100644 --- a/runtime/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java +++ b/runtime/exporter-stdout/src/test/java/io/aklivity/zilla/runtime/exporter/stdout/internal/events/EventIT.java @@ -55,8 +55,8 @@ public class EventIT @Test @Configuration("server.event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) @Configure(name = STDOUT_OUTPUT_NAME, value = "io.aklivity.zilla.runtime.exporter.stdout.internal.events.StdoutOutputRule.OUT") diff --git a/runtime/guard-jwt/pom.xml b/runtime/guard-jwt/pom.xml index 886072141d..b97acbc88f 100644 --- a/runtime/guard-jwt/pom.xml +++ b/runtime/guard-jwt/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml @@ -46,7 +46,7 @@ org.bitbucket.b_c jose4j - 0.9.3 + 0.9.6 org.slf4j diff --git a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtGuardHandler.java b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtGuardHandler.java index b34a2edd36..d166b336c6 100644 --- a/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtGuardHandler.java +++ b/runtime/guard-jwt/src/main/java/io/aklivity/zilla/runtime/guard/jwt/internal/JwtGuardHandler.java @@ -178,6 +178,7 @@ public long reauthorize( JwtSessionStore sessionStore = supplySessionStore(contextId); session = sessionStore.supplySession(subject, roles); + session.credentials = credentials; session.roles = roles; session.expiresAt = notAfter != null ? Math.max(session.expiresAt, notAfter.getValueInMillis()) @@ -224,6 +225,14 @@ public String identity( return session != null ? session.subject : null; } + @Override + public String credentials( + long sessionId) + { + JwtSession session = sessionsById.get(sessionId); + return session != null ? session.credentials : null; + } + @Override public long expiresAt( long sessionId) @@ -337,6 +346,7 @@ private final class JwtSession private final String subject; private final Consumer unshare; + private String credentials; private long expiresAt; private long challengeAt; private long challengedAt; diff --git a/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java b/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java index d6dc34cf9c..b90241f39e 100644 --- a/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java +++ b/runtime/guard-jwt/src/test/java/io/aklivity/zilla/runtime/guard/jwt/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/metrics-grpc/pom.xml b/runtime/metrics-grpc/pom.xml index 50b3c0f859..077ae91724 100644 --- a/runtime/metrics-grpc/pom.xml +++ b/runtime/metrics-grpc/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/metrics-http/pom.xml b/runtime/metrics-http/pom.xml index 41e13a00e8..4fbb848bcb 100644 --- a/runtime/metrics-http/pom.xml +++ b/runtime/metrics-http/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/metrics-http/src/main/java/io/aklivity/zilla/runtime/metrics/http/internal/HttpUtils.java b/runtime/metrics-http/src/main/java/io/aklivity/zilla/runtime/metrics/http/internal/HttpUtils.java index 2ecda67419..4bf079b8a1 100644 --- a/runtime/metrics-http/src/main/java/io/aklivity/zilla/runtime/metrics/http/internal/HttpUtils.java +++ b/runtime/metrics-http/src/main/java/io/aklivity/zilla/runtime/metrics/http/internal/HttpUtils.java @@ -63,7 +63,8 @@ public static long parseContentLength( { DirectBuffer buffer = contentLength.value().value(); assert buffer != null; - return buffer.parseLongAscii(0, buffer.capacity()); + int capacity = buffer.capacity(); + return capacity == 0 ? 0L : buffer.parseLongAscii(0, capacity); } else { diff --git a/runtime/metrics-stream/pom.xml b/runtime/metrics-stream/pom.xml index 331ce57e60..3e34ef56c7 100644 --- a/runtime/metrics-stream/pom.xml +++ b/runtime/metrics-stream/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/model-avro/pom.xml b/runtime/model-avro/pom.xml index 8f3f284639..f362bd8594 100644 --- a/runtime/model-avro/pom.xml +++ b/runtime/model-avro/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java b/runtime/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java index cb9aeacfad..e2fc37713d 100644 --- a/runtime/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java +++ b/runtime/model-avro/src/main/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelHandler.java @@ -50,6 +50,10 @@ public abstract class AvroModelHandler private static final InputStream EMPTY_INPUT_STREAM = new ByteArrayInputStream(new byte[0]); private static final OutputStream EMPTY_OUTPUT_STREAM = new ByteArrayOutputStream(0); private static final int JSON_FIELD_STRUCTURE_LENGTH = "\"\":\"\",".length(); + private static final int JSON_FIELD_UNION_LENGTH = "\"\":{\"DATA_TYPE\":\"\"},".length(); + private static final int COMMA_LENGTH = ",".length(); + private static final int JSON_FIELD_ARRAY_LENGTH = "\"\":[]," .length() + COMMA_LENGTH * 100; + private static final int JSON_FIELD_MAP_LENGTH = "\"\":{},".length(); protected final SchemaConfig catalog; protected final CatalogHandler handler; @@ -207,15 +211,40 @@ private int calculatePadding( if (schema != null) { padding = 2; - for (Schema.Field field : schema.getFields()) + if (schema.getType().equals(Schema.Type.RECORD)) { - if (field.schema().getType().equals(Schema.Type.RECORD)) + for (Schema.Field field : schema.getFields()) { - padding += calculatePadding(field.schema()); - } - else - { - padding += field.name().getBytes().length + JSON_FIELD_STRUCTURE_LENGTH; + switch (field.schema().getType()) + { + case RECORD: + { + padding += calculatePadding(field.schema()); + break; + } + case UNION: + { + padding += field.name().getBytes().length + JSON_FIELD_UNION_LENGTH; + break; + } + case MAP: + { + padding += field.name().getBytes().length + JSON_FIELD_MAP_LENGTH + + calculatePadding(field.schema().getValueType()); + break; + } + case ARRAY: + { + padding += field.name().getBytes().length + JSON_FIELD_ARRAY_LENGTH + + calculatePadding(field.schema().getElementType()); + break; + } + default: + { + padding += field.name().getBytes().length + JSON_FIELD_STRUCTURE_LENGTH; + break; + } + } } } } diff --git a/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java b/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java index f39cfc3d43..3047700ebe 100644 --- a/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java +++ b/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/AvroModelTest.java @@ -39,6 +39,16 @@ public class AvroModelTest "{\"name\":\"status\",\"type\":\"string\"}]," + "\"name\":\"Event\",\"namespace\":\"io.aklivity.example\",\"type\":\"record\"}"; + private static final String COMPLEX_SCHEMA = "{\"type\":\"record\",\"name\":\"example\",\"namespace\":\"com.example\"," + + "\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"preferences\",\"" + + "type\":{\"type\":\"map\",\"values\":\"string\"}},{\"name\":\"attributes\",\"" + + "type\":{\"type\":\"map\",\"values\":{\"type\":\"record\",\"name\":\"Attribute\"," + + "\"fields\":[{\"name\":\"value\",\"type\":\"string\"},{\"name\":\"timestamp\",\"type\":\"long\"}]}}}," + + "{\"name\":\"addresses\",\"type\":{\"type\":\"array\",\"items\":{\"type\":\"record\",\"name\":\"Address\"," + + "\"fields\":[{\"name\":\"street\",\"type\":\"string\"},{\"name\":\"city\",\"type\":\"string\"}," + + "{\"name\":\"state\",\"type\":\"string\"},{\"name\":\"zip\",\"type\":\"string\"}]}}}," + + "{\"name\":\"source\",\"type\":[\"null\",\"string\"],\"default\":null}]}"; + private final AvroModelConfig avroConfig = AvroModelConfig.builder() .catalog() .name("test0") @@ -205,7 +215,7 @@ public void shouldVerifyPaddingLength() { TestCatalogOptionsConfig testCatalogOptionsConfig = TestCatalogOptionsConfig.builder() .id(9) - .schema(SCHEMA) + .schema(COMPLEX_SCHEMA) .build(); CatalogConfig catalogConfig = new CatalogConfig("test", "test0", "test", testCatalogOptionsConfig); when(context.supplyCatalog(catalogConfig.id)).thenReturn(new TestCatalogHandler(testCatalogOptionsConfig)); @@ -228,7 +238,7 @@ public void shouldVerifyPaddingLength() 0x30, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65}; data.wrap(bytes, 0, bytes.length); - assertEquals(22, converter.padding(data, 0, data.capacity())); + assertEquals(260, converter.padding(data, 0, data.capacity())); } } diff --git a/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/EventIT.java b/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/EventIT.java index c39e60be4d..3045d11789 100644 --- a/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/EventIT.java +++ b/runtime/model-avro/src/test/java/io/aklivity/zilla/runtime/model/avro/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/model-core/pom.xml b/runtime/model-core/pom.xml index aa9f3094df..db68da602a 100644 --- a/runtime/model-core/pom.xml +++ b/runtime/model-core/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringPattern.java b/runtime/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringPattern.java new file mode 100644 index 0000000000..044944f31c --- /dev/null +++ b/runtime/model-core/src/main/java/io/aklivity/zilla/runtime/model/core/config/StringPattern.java @@ -0,0 +1,47 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.model.core.config; + +public enum StringPattern +{ + EMAIL("^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}"), + DATE("^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"), + DATE_TIME("^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])T([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)Z"); + + public final String pattern; + + StringPattern( + String pattern) + { + this.pattern = pattern; + } + + + public static String of( + String format) + { + switch (format) + { + case "email": + return EMAIL.pattern; + case "date": + return DATE.pattern; + case "date-time": + return DATE_TIME.pattern; + default: + return null; + } + } +} diff --git a/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/EventIT.java b/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/EventIT.java index 524c64f591..73f247f551 100644 --- a/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/EventIT.java +++ b/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringPatternTest.java b/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringPatternTest.java new file mode 100644 index 0000000000..1c5e00215b --- /dev/null +++ b/runtime/model-core/src/test/java/io/aklivity/zilla/runtime/model/core/internal/config/StringPatternTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2021-2023 Aklivity Inc + * + * Licensed under the Aklivity Community License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of the + * License at + * + * https://www.aklivity.io/aklivity-community-license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package io.aklivity.zilla.runtime.model.core.internal.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.regex.Pattern; + +import org.junit.Test; + +import io.aklivity.zilla.runtime.model.core.config.StringPattern; + +public class StringPatternTest +{ + @Test + public void shouldVerifyStringPatternOf() + { + assertEquals(StringPattern.EMAIL.pattern, StringPattern.of("email")); + assertEquals(StringPattern.DATE.pattern, StringPattern.of("date")); + assertEquals(StringPattern.DATE_TIME.pattern, StringPattern.of("date-time")); + } + + @Test + public void shouldValidateEmailPattern() + { + Pattern pattern = Pattern.compile(StringPattern.of("email")); + assertTrue(pattern.matcher("abc@test.com").matches()); + assertFalse(pattern.matcher("abc@test.123").matches()); + assertTrue(pattern.matcher("1.2-3_.abc@test.in").matches()); + assertFalse(pattern.matcher("abc@abc@test.123").matches()); + } + + @Test + public void shouldValidateDatePattern() + { + Pattern pattern = Pattern.compile(StringPattern.of("date")); + assertTrue(pattern.matcher("2017-07-02").matches()); + assertFalse(pattern.matcher("2017-07-2").matches()); + assertFalse(pattern.matcher("2017-17-20").matches()); + assertFalse(pattern.matcher("2017-07-35").matches()); + } + + @Test + public void shouldValidateDateTimePattern() + { + Pattern pattern = Pattern.compile(StringPattern.of("date-time")); + assertTrue(pattern.matcher("2017-07-21T17:32:28Z").matches()); + assertFalse(pattern.matcher("2017-07-21T17:32:28").matches()); + assertFalse(pattern.matcher("2017-07-21T17:32Z").matches()); + assertFalse(pattern.matcher("2017-07-21T17:2:28A").matches()); + } +} diff --git a/runtime/model-json/pom.xml b/runtime/model-json/pom.xml index de86de429a..a988d6955e 100644 --- a/runtime/model-json/pom.xml +++ b/runtime/model-json/pom.xml @@ -6,7 +6,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/EventIT.java b/runtime/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/EventIT.java index f61735b986..a3d2de2cde 100644 --- a/runtime/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/EventIT.java +++ b/runtime/model-json/src/test/java/io/aklivity/zilla/runtime/model/json/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/model-protobuf/pom.xml b/runtime/model-protobuf/pom.xml index fe4f58ad46..2f60d401dc 100644 --- a/runtime/model-protobuf/pom.xml +++ b/runtime/model-protobuf/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/EventIT.java b/runtime/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/EventIT.java index 3cd3a546fc..f337a652d6 100644 --- a/runtime/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/EventIT.java +++ b/runtime/model-protobuf/src/test/java/io/aklivity/zilla/runtime/model/protobuf/internal/EventIT.java @@ -49,8 +49,8 @@ public class EventIT @Test @Configuration("event.yaml") @Specification({ - "${net}/event/client", - "${app}/event/server" + "${net}/handshake/client", + "${app}/handshake/server" }) public void shouldLogEvents() throws Exception { diff --git a/runtime/pom.xml b/runtime/pom.xml index e1ff133846..a9785fe3d7 100644 --- a/runtime/pom.xml +++ b/runtime/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/resolver-env/pom.xml b/runtime/resolver-env/pom.xml index 0714a44e51..575876dff5 100644 --- a/runtime/resolver-env/pom.xml +++ b/runtime/resolver-env/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/runtime/vault-filesystem/pom.xml b/runtime/vault-filesystem/pom.xml index 8697572219..4ce55a9392 100644 --- a/runtime/vault-filesystem/pom.xml +++ b/runtime/vault-filesystem/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla runtime - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-asyncapi.spec/pom.xml b/specs/binding-asyncapi.spec/pom.xml index 6a10af9e3b..585ee020c8 100644 --- a/specs/binding-asyncapi.spec/pom.xml +++ b/specs/binding-asyncapi.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml index f91c24416f..5931f33bf1 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.http.yaml @@ -20,6 +20,7 @@ catalogs: catalog0: type: test options: + id: 1 subject: petstore schema: | asyncapi: 3.0.0 diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.multi.protocol.yaml b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.multi.protocol.yaml new file mode 100644 index 0000000000..dab9239d7b --- /dev/null +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/config/server.multi.protocol.yaml @@ -0,0 +1,206 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +catalogs: + catalog0: + type: test + options: + id: 0 + subject: smartylighting + schema: | + asyncapi: 3.0.0 + info: + title: Zilla MQTT Proxy + version: 1.0.0 + license: + name: Aklivity Community License + servers: + production: + host: '{subdomain}.example.com:{port}' + protocol: mqtt + variables: + subdomain: + $ref: '#/components/serverVariables/subdomain' + port: + $ref: '#/components/serverVariables/port' + development: + host: '{subdomain}.dev.example.com:{port}' + protocol: mqtt + variables: + subdomain: + $ref: '#/components/serverVariables/subdomain' + port: + $ref: '#/components/serverVariables/port' + defaultContentType: application/json + channels: + sensors: + address: "sensors/{sensorId}" + title: MQTT Topic to produce & consume topic. + parameters: + streetlightId: + $ref: '#/components/parameters/sensorId' + messages: + items: + $ref: '#/components/messages/item' + + operations: + sendEvents: + action: send + channel: + $ref: '#/channels/sensors' + + receiveEvents: + action: receive + channel: + $ref: '#/channels/sensors' + + components: + serverVariables: + subdomain: + enum: + - development + - staging + - production + default: development + port: + default: '1883' + enum: + - '1883' + - '8883' + parameters: + sensorId: + description: Sensor ID + location: $message.header#/id + messages: + item: + name: event + title: An event + headers: + type: object + properties: + idempotency-key: + description: Unique identifier for a given event + type: string + id: + description: Sensor ID + type: string + catalog1: + type: test + options: + id: 1 + subject: petstore + schema: | + asyncapi: 3.0.0 + info: + title: AsyncAPI Petstore + license: + name: MIT + version: 1.0.0 + servers: + plain: + host: localhost:8080 + protocol: http + protocolVersion: '2.0' + defaultContentType: application/json + + channels: + pets: + address: /pets + messages: + pet: + $ref: '#/components/messages/pet' + showPetById: + address: /pets/{id} + messages: + pet: + $ref: '#/components/messages/pet' + + operations: + createPet: + action: send + bindings: + http: + method: POST + channel: + $ref: '#/channels/pets' + listPets: + action: receive + bindings: + http: + method: GET + channel: + $ref: '#/channels/pets' + getPets: + action: receive + bindings: + http: + method: GET + query: + type: object + properties: + limit: + type: number + channel: + $ref: '#/channels/showPetById' + + components: + correlationIds: + petsCorrelationId: + location: '$message.header#/idempotency-key' + schemas: + petPayload: + type: object + properties: + id: + type: integer + minimum: 0 + description: Pet id. + name: + type: string + description: Pet name. + tag: + type: string + description: Tag. + messages: + pet: + name: Pet + title: Pet + summary: >- + Inform about Pet. + contentType: application/json + payload: + $ref: '#/components/schemas/petPayload' +bindings: + composite0: + type: asyncapi + kind: server + options: + specs: + mqtt_api: + servers: + - host: 'development.dev.example.com:1883' + catalog: + catalog0: + subject: smartylighting + version: latest + http_api: + catalog: + catalog1: + subject: petstore + version: latest + exit: asyncapi0 diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt index 667f0a8097..ff78135bb3 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/client.rpt @@ -20,7 +20,7 @@ connect "zilla://streams/asyncapi0" write zilla:begin.ext ${asyncapi:beginEx() .typeId(zilla:id("asyncapi")) - .apiId(0) + .apiId(1) .operationId("createPet") .extension(http:beginEx() .typeId(zilla:id("http")) diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt index 36d33be6a9..d1a94ab5db 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/http/create.pet/server.rpt @@ -22,7 +22,7 @@ accepted read zilla:begin.ext ${asyncapi:matchBeginEx() .typeId(zilla:id("asyncapi")) - .apiId(0) + .apiId(1) .operationId("createPet") .extension(http:beginEx() .typeId(zilla:id("http")) diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt index 2395d09f1e..1121c17782 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/asyncapi/mqtt/publish.and.subscribe/client.rpt @@ -42,9 +42,11 @@ read zilla:begin.ext ${asyncapi:matchBeginEx() connected read zilla:data.empty +read notify RECEIVED_SESSION_STATE -connect "zilla://streams/asyncapi0" +connect await RECEIVED_SESSION_STATE + "zilla://streams/asyncapi0" option zilla:window 8192 option zilla:transmission "duplex" @@ -75,9 +77,11 @@ write zilla:data.ext ${mqtt:dataEx() .build()} write "asyncapiMessage" write flush +write notify DATA_PUBLISHED -connect "zilla://streams/asyncapi0" +connect await DATA_PUBLISHED + "zilla://streams/asyncapi0" option zilla:window 8192 option zilla:transmission "duplex" diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt index 519bc10f7d..9369358417 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/http/create.pet/client.rpt @@ -17,7 +17,7 @@ connect "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:ephemeral "test:composite0/http" + option zilla:ephemeral "test:composite0/http_api" write zilla:begin.ext ${http:beginEx() .typeId(zilla:id("http")) diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt index 1e13239fe6..5586f02b59 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/kafka/produce.message/client.rpt @@ -20,7 +20,7 @@ property newTimestamp ${kafka:timestamp() + deltaMillis} connect "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:ephemeral "test:composite0/kafka" + option zilla:ephemeral "test:composite0/kafka_api" write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) diff --git a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt index c0de30bc54..0d625cf82a 100644 --- a/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt +++ b/specs/binding-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/asyncapi/streams/mqtt/publish.and.subscribe/client.rpt @@ -17,7 +17,7 @@ connect "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "duplex" - option zilla:ephemeral "test:composite0/mqtt" + option zilla:ephemeral "test:composite0/mqtt_api" write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) @@ -43,7 +43,7 @@ connect await RECEIVED_SESSION_STATE "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "duplex" - option zilla:ephemeral "test:composite0/mqtt" + option zilla:ephemeral "test:composite0/mqtt_api" write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) @@ -75,7 +75,7 @@ connect await RECEIVED_SESSION_STATE "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "duplex" - option zilla:ephemeral "test:composite0/mqtt" + option zilla:ephemeral "test:composite0/mqtt_api" write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) diff --git a/specs/binding-echo.spec/pom.xml b/specs/binding-echo.spec/pom.xml index 75060b8aa2..fe92e2d655 100644 --- a/specs/binding-echo.spec/pom.xml +++ b/specs/binding-echo.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-fan.spec/pom.xml b/specs/binding-fan.spec/pom.xml index 0804b04ef4..9b416238ba 100644 --- a/specs/binding-fan.spec/pom.xml +++ b/specs/binding-fan.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-filesystem.spec/pom.xml b/specs/binding-filesystem.spec/pom.xml index 56403d8c9b..dc7adf68f4 100644 --- a/specs/binding-filesystem.spec/pom.xml +++ b/specs/binding-filesystem.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/config/files/empty.txt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/config/files/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/client.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/client.rpt new file mode 100644 index 0000000000..61e9b3b163 --- /dev/null +++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/client.rpt @@ -0,0 +1,38 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/app0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${filesystem:beginEx() + .typeId(zilla:id("filesystem")) + .capabilities("READ_PAYLOAD") + .path("empty.txt") + .build()} +connected + +write close + +read zilla:begin.ext ${filesystem:matchBeginEx() + .typeId(zilla:id("filesystem")) + .capabilities("READ_PAYLOAD") + .path("empty.txt") + .type("text/plain") + .payloadSize(0) + .tag("d41d8cd98f00b204e9800998ecf8427e") + .build()} + +read closed diff --git a/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/server.rpt b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/server.rpt new file mode 100644 index 0000000000..88e266a3b0 --- /dev/null +++ b/specs/binding-filesystem.spec/src/main/scripts/io/aklivity/zilla/specs/binding/filesystem/streams/application/read.file.payload.empty/server.rpt @@ -0,0 +1,40 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/app0" + option zilla:window 8192 + option zilla:transmission "half-duplex" +accepted + +read zilla:begin.ext ${filesystem:matchBeginEx() + .typeId(zilla:id("filesystem")) + .capabilities("READ_PAYLOAD") + .path("empty.txt") + .build()} +connected + +read closed + +write zilla:begin.ext ${filesystem:beginEx() + .typeId(zilla:id("filesystem")) + .capabilities("READ_PAYLOAD") + .path("empty.txt") + .type("text/plain") + .payloadSize(0) + .tag("d41d8cd98f00b204e9800998ecf8427e") + .build()} +write flush + +write close diff --git a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java index 19c5e2f21a..f61420e338 100644 --- a/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java +++ b/specs/binding-filesystem.spec/src/test/java/io/aklivity/zilla/specs/binding/filesystem/streams/application/FileSystemIT.java @@ -55,6 +55,16 @@ public void shouldReadFileExtensionDefault() throws Exception k3po.finish(); } + @Test + @Specification({ + "${app}/read.file.payload.empty/client", + "${app}/read.file.payload.empty/server", + }) + public void shouldReadFilePayloadEmpty() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${app}/read.file.payload/client", diff --git a/specs/binding-grpc-kafka.spec/pom.xml b/specs/binding-grpc-kafka.spec/pom.xml index e086ece5e2..29b16dff35 100644 --- a/specs/binding-grpc-kafka.spec/pom.xml +++ b/specs/binding-grpc-kafka.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-grpc.spec/pom.xml b/specs/binding-grpc.spec/pom.xml index a8fd02813b..69f12490f1 100644 --- a/specs/binding-grpc.spec/pom.xml +++ b/specs/binding-grpc.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.binary.metadata.yaml b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.binary.metadata.yaml index 1833674fdf..5e267a1aa5 100644 --- a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.binary.metadata.yaml +++ b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.binary.metadata.yaml @@ -19,9 +19,6 @@ bindings: app0: type: grpc kind: client - options: - services: - - protobuf/echo.proto routes: - exit: net0 when: diff --git a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.yaml b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.yaml index 49d8b95acb..a90925f4d6 100644 --- a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.yaml +++ b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/config/client.when.yaml @@ -19,9 +19,6 @@ bindings: app0: type: grpc kind: client - options: - services: - - protobuf/echo.proto routes: - exit: net0 when: diff --git a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/schema/grpc.schema.patch.json b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/schema/grpc.schema.patch.json index 514b16bf6b..414ed70113 100644 --- a/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/schema/grpc.schema.patch.json +++ b/specs/binding-grpc.spec/src/main/scripts/io/aklivity/zilla/specs/binding/grpc/schema/grpc.schema.patch.json @@ -32,24 +32,6 @@ "enum": [ "server", "client"] }, "vault": false, - "options": - { - "properties": - { - "services": - { - "title": "Services", - "type": "array", - "items": - { - "title": "Service", - "type": "string" - }, - "deprecated": true - } - }, - "additionalProperties": false - }, "routes": { "items": @@ -115,6 +97,46 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "server" + }, + "options": + { + "properties": + { + "services": + { + "title": "Services", + "type": "array", + "items": + { + "title": "Service", + "type": "string" + }, + "deprecated": true + } + }, + "additionalProperties": false + } + } + }, + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": false + } + } ] } } diff --git a/specs/binding-grpc.spec/src/test/java/io/aklivity/zilla/specs/binding/grpc/config/SchemaTest.java b/specs/binding-grpc.spec/src/test/java/io/aklivity/zilla/specs/binding/grpc/config/SchemaTest.java index 755360e0b5..c61ce654d1 100644 --- a/specs/binding-grpc.spec/src/test/java/io/aklivity/zilla/specs/binding/grpc/config/SchemaTest.java +++ b/specs/binding-grpc.spec/src/test/java/io/aklivity/zilla/specs/binding/grpc/config/SchemaTest.java @@ -31,6 +31,7 @@ public class SchemaTest public final ConfigSchemaRule schema = new ConfigSchemaRule() .schemaPatch("io/aklivity/zilla/specs/binding/grpc/schema/grpc.schema.patch.json") .schemaPatch("io/aklivity/zilla/specs/engine/schema/guard/test.schema.patch.json") + .schemaPatch("io/aklivity/zilla/specs/engine/schema/catalog/test.schema.patch.json") .configurationRoot("io/aklivity/zilla/specs/binding/grpc/config"); @Test @@ -48,4 +49,36 @@ public void shouldValidateClient() assertThat(config, not(nullValue())); } + + @Test + public void shouldValidateClientWhen() + { + JsonObject config = schema.validate("client.when.yaml"); + + assertThat(config, not(nullValue())); + } + + @Test + public void shouldValidateServerWhenBinaryMetadata() + { + JsonObject config = schema.validate("server.when.binary.metadata.yaml"); + + assertThat(config, not(nullValue())); + } + + @Test + public void shouldValidateClientWhenBinaryMetadata() + { + JsonObject config = schema.validate("client.when.binary.metadata.yaml"); + + assertThat(config, not(nullValue())); + } + + @Test + public void shouldValidateServerWhenCatalog() + { + JsonObject config = schema.validate("server.when.catalog.yaml"); + + assertThat(config, not(nullValue())); + } } diff --git a/specs/binding-http-filesystem.spec/pom.xml b/specs/binding-http-filesystem.spec/pom.xml index dc2b971c1a..adac8b85c0 100644 --- a/specs/binding-http-filesystem.spec/pom.xml +++ b/specs/binding-http-filesystem.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-http-kafka.spec/pom.xml b/specs/binding-http-kafka.spec/pom.xml index d25f88278c..694db8139a 100644 --- a/specs/binding-http-kafka.spec/pom.xml +++ b/specs/binding-http-kafka.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-http.spec/pom.xml b/specs/binding-http.spec/pom.xml index a8109e782f..2074da7c4e 100644 --- a/specs/binding-http.spec/pom.xml +++ b/specs/binding-http.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json index 353ba8d2b3..62f6124fe5 100644 --- a/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json +++ b/specs/binding-http.spec/src/main/scripts/io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json @@ -388,6 +388,35 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "server" + } + } + }, + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": + { + "properties": + { + "access-control": false, + "authorization": false + } + } + } + } ] } } diff --git a/specs/binding-http.spec/src/test/java/io/aklivity/zilla/specs/binding/http/config/SchemaTest.java b/specs/binding-http.spec/src/test/java/io/aklivity/zilla/specs/binding/http/config/SchemaTest.java index c6f93dbdd3..5299abbd37 100644 --- a/specs/binding-http.spec/src/test/java/io/aklivity/zilla/specs/binding/http/config/SchemaTest.java +++ b/specs/binding-http.spec/src/test/java/io/aklivity/zilla/specs/binding/http/config/SchemaTest.java @@ -32,6 +32,7 @@ public class SchemaTest public final ConfigSchemaRule schema = new ConfigSchemaRule() .schemaPatch("io/aklivity/zilla/specs/binding/http/schema/http.schema.patch.json") .schemaPatch("io/aklivity/zilla/specs/engine/schema/guard/test.schema.patch.json") + .schemaPatch("io/aklivity/zilla/specs/engine/schema/model/test.schema.patch.json") .configurationRoot("io/aklivity/zilla/specs/binding/http/config"); @Test @@ -170,6 +171,14 @@ public void shouldValidateHttp2Client() assertThat(config, not(nullValue())); } + @Test + public void shouldValidateHttp2ClientWithValidation() + { + JsonObject config = schema.validate("v2/client.validation.yaml"); + + assertThat(config, not(nullValue())); + } + @Test public void shouldValidateHttp2ClientOverride() { diff --git a/specs/binding-kafka-grpc.spec/pom.xml b/specs/binding-kafka-grpc.spec/pom.xml index 31f2ae007e..36cb37dd1a 100644 --- a/specs/binding-kafka-grpc.spec/pom.xml +++ b/specs/binding-kafka-grpc.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-kafka.spec/pom.xml b/specs/binding-kafka.spec/pom.xml index 4e0ae33879..97f163d033 100644 --- a/specs/binding-kafka.spec/pom.xml +++ b/specs/binding-kafka.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/cache.options.merged.yaml b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/cache.options.merged.yaml index 58694552d9..1b1b70795b 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/cache.options.merged.yaml +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/cache.options.merged.yaml @@ -20,9 +20,6 @@ bindings: app0: type: kafka kind: cache_client - options: - merged: - - test routes: - exit: cache0 when: diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.options.merged.yaml b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.options.merged.yaml index 4987d8fd1d..4f0ed0e4d2 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.options.merged.yaml +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/config/client.options.merged.yaml @@ -23,6 +23,4 @@ bindings: options: servers: - localhost:9092 - merged: - - test exit: net0 diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/schema/kafka.schema.patch.json b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/schema/kafka.schema.patch.json index 5a6ddf1efe..15b1c2fe79 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/schema/kafka.schema.patch.json +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/schema/kafka.schema.patch.json @@ -32,82 +32,6 @@ "enum": [ "cache_client", "cache_server", "client" ] }, "vault": false, - "options": - { - "properties": - { - "merged": - { - "title": "Merged", - "type": "array", - "items": - { - "type": "string" - }, - "deprecated": true - }, - "bootstrap": - { - "title": "Bootstrap", - "type": "array", - "items": - { - "type": "string" - } - }, - "topics": - { - "title": "Topics", - "type": "array", - "items": - { - "type": "object", - "additionalProperties": false, - "properties": - { - "name": - { - "type": "string" - }, - "defaultOffset": - { - "type": "string", - "enum": [ "live", "historical" ] - }, - "deltaType": - { - "type": "string", - "enum": [ "none", "json_patch" ], - "deprecated": true - }, - "key": - { - "$ref": "#/$defs/converter" - }, - "value": - { - "$ref": "#/$defs/converter" - } - } - } - }, - "servers": - { - "title": "Servers", - "type": "array", - "items": - { - "type": "string", - "pattern": "([^\\:]+):(\\d+)" - } - }, - "sasl": - { - "$ref": "#/$defs/options/binding/kafka/sasl" - } - }, - "additionalProperties": false - }, "routes": { "items": @@ -154,6 +78,141 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "cache_client" + }, + "options": + { + "properties": + { + "topics": + { + "title": "Topics", + "type": "array", + "items": + { + "type": "object", + "additionalProperties": false, + "properties": + { + "name": + { + "type": "string" + }, + "key": + { + "$ref": "#/$defs/converter" + }, + "value": + { + "$ref": "#/$defs/converter" + } + } + } + } + }, + "additionalProperties": false + } + } + }, + { + "properties": + { + "kind": + { + "const": "cache_server" + }, + "options": + { + "properties": + { + "bootstrap": + { + "title": "Bootstrap", + "type": "array", + "items": + { + "type": "string" + } + }, + "topics": + { + "title": "Topics", + "type": "array", + "items": + { + "type": "object", + "additionalProperties": false, + "properties": + { + "name": + { + "type": "string" + }, + "defaultOffset": + { + "type": "string", + "enum": [ "live", "historical" ] + }, + "deltaType": + { + "type": "string", + "enum": [ "none", "json_patch" ], + "deprecated": true + }, + "key": + { + "$ref": "#/$defs/converter" + }, + "value": + { + "$ref": "#/$defs/converter" + } + } + } + } + }, + "additionalProperties": false + } + } + }, + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": + { + "properties": + { + "servers": + { + "title": "Servers", + "type": "array", + "items": + { + "type": "string", + "pattern": "([^\\:]+):(\\d+)" + } + }, + "sasl": + { + "$ref": "#/$defs/options/binding/kafka/sasl" + } + }, + "additionalProperties": false + } + } + } ] } } diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/client.rpt index 05d9edd9da..63fc3acfce 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/client.rpt @@ -158,12 +158,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/server.rpt index 180178cfba..aeca0db3e9 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/bootstrap/unmerged.group.fetch.message.value/server.rpt @@ -158,12 +158,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/client.rpt index 072b950b50..c267fe86fc 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/client.rpt @@ -72,32 +72,32 @@ read advised zilla:flush ${kafka:flushEx() .build()} write ${kafka:memberAssignment() - .member("memberId-1") + .member("memberId-2") .assignment() .topic("test") - .partitionId(1) + .partitionId(0) + .consumer() + .id("consumer-2") + .partitionId(0) + .build() .consumer() .id("consumer-1") .partitionId(1) .build() - .consumer() - .id("consumer-2") - .partitionId(0) - .build() .build() .build() - .member("memberId-2") + .member("memberId-1") .assignment() .topic("test") - .partitionId(0) + .partitionId(1) .consumer() - .id("consumer-1") - .partitionId(1) - .build() + .id("consumer-2") + .partitionId(0) + .build() .consumer() - .id("consumer-2") - .partitionId(0) - .build() + .id("consumer-1") + .partitionId(1) + .build() .build() .build() .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/server.rpt index 2d99a56c80..92d2f9ae08 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/consumer/commit.acknowledge.message.offset/server.rpt @@ -77,32 +77,32 @@ write advise zilla:flush ${kafka:flushEx() .build()} read ${kafka:memberAssignment() - .member("memberId-1") + .member("memberId-2") .assignment() .topic("test") - .partitionId(1) - .consumer() - .id("consumer-1") - .partitionId(1) - .build() + .partitionId(0) .consumer() .id("consumer-2") .partitionId(0) .build() - .build() - .build() - .member("memberId-2") - .assignment() - .topic("test") - .partitionId(0) .consumer() .id("consumer-1") .partitionId(1) .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(1) .consumer() .id("consumer-2") .partitionId(0) .build() + .consumer() + .id("consumer-1") + .partitionId(1) + .build() .build() .build() .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/client.rpt index 988d1a1100..15481f9540 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/client.rpt @@ -70,32 +70,32 @@ read advised zilla:flush ${kafka:flushEx() .build()} write ${kafka:memberAssignment() - .member("memberId-1") + .member("memberId-2") .assignment() .topic("test") - .partitionId(1) + .partitionId(0) + .consumer() + .id("consumer-2") + .partitionId(0) + .build() .consumer() .id("consumer-1") .partitionId(1) .build() - .consumer() - .id("consumer-2") - .partitionId(0) - .build() .build() .build() - .member("memberId-2") + .member("memberId-1") .assignment() .topic("test") - .partitionId(0) + .partitionId(1) .consumer() - .id("consumer-1") - .partitionId(1) - .build() + .id("consumer-2") + .partitionId(0) + .build() .consumer() - .id("consumer-2") - .partitionId(0) - .build() + .id("consumer-1") + .partitionId(1) + .build() .build() .build() .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/server.rpt index b102c31df0..82c05087d2 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/partition.assignment/server.rpt @@ -75,32 +75,32 @@ write advise zilla:flush ${kafka:flushEx() .build()} read ${kafka:memberAssignment() - .member("memberId-1") + .member("memberId-2") .assignment() .topic("test") - .partitionId(1) - .consumer() - .id("consumer-1") - .partitionId(1) - .build() + .partitionId(0) .consumer() .id("consumer-2") .partitionId(0) .build() - .build() - .build() - .member("memberId-2") - .assignment() - .topic("test") - .partitionId(0) .consumer() .id("consumer-1") .partitionId(1) .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(1) .consumer() .id("consumer-2") .partitionId(0) .build() + .consumer() + .id("consumer-1") + .partitionId(1) + .build() .build() .build() .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/client.rpt index ccc26b884e..953a94d702 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/client.rpt @@ -66,12 +66,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() @@ -99,13 +99,13 @@ write advise zilla:flush ${kafka:flushEx() .members("memberId-1", kafka:memberMetadata() .consumerId("consumer-1") .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build()) .build() @@ -120,13 +120,13 @@ read advised zilla:flush ${kafka:flushEx() .members("memberId-1", kafka:memberMetadata() .consumerId("consumer-1") .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build()) .build() @@ -134,28 +134,28 @@ read advised zilla:flush ${kafka:flushEx() write ${kafka:memberAssignment() .member("memberId-1") - .assignment() - .topic("test-1") - .partitionId(0) - .partitionId(1) - .consumer() - .id("consumer-1") - .partitionId(0) - .partitionId(1) - .build() - .build() .assignment() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build() + .assignment() + .topic("test-1") + .partitionId(1) + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(1) + .partitionId(0) + .build() + .build() .build() .build()} write flush diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/server.rpt index cf1a74abf1..f3d2dfc858 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/group/reassign.new.topic/server.rpt @@ -71,12 +71,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() @@ -104,13 +104,13 @@ read advised zilla:flush ${kafka:flushEx() .members("memberId-1", kafka:memberMetadata() .consumerId("consumer-1") .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build()) .build() @@ -125,13 +125,13 @@ write advise zilla:flush ${kafka:flushEx() .members("memberId-1", kafka:memberMetadata() .consumerId("consumer-1") .topic("test-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build()) .build() @@ -139,28 +139,28 @@ write advise zilla:flush ${kafka:flushEx() read ${kafka:memberAssignment() .member("memberId-1") - .assignment() - .topic("test-1") - .partitionId(0) - .partitionId(1) - .consumer() - .id("consumer-1") - .partitionId(0) - .partitionId(1) - .build() - .build() .assignment() .topic("test-2") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) - .partitionId(1) .partitionId(2) + .partitionId(1) + .partitionId(0) .build() .build() + .assignment() + .topic("test-1") + .partitionId(1) + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(1) + .partitionId(0) + .build() + .build() .build() .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/client.rpt new file mode 100644 index 0000000000..bb450a6ce6 --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/client.rpt @@ -0,0 +1,44 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/app0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("test") + .groupId("client-1") + .consumerId("consumer-2") + .timeout(45000) + .partition(0, 1) + .partition(1, 1) + .partition(-1, 1) + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("test") + .partition(0, 2, 2, 2, "test-meta") + .build() + .build()} diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/server.rpt new file mode 100644 index 0000000000..abc1dc86a0 --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/merged.fetch.unsubscribe/server.rpt @@ -0,0 +1,50 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + +accept "zilla://streams/app0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("test") + .groupId("client-1") + .consumerId("consumer-2") + .timeout(45000) + .partition(0, 1) + .partition(1, 1) + .partition(-1, 1) + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("test") + .partition(0, 2, 2, 2, "test-meta") + .build() + .build()} +write flush diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/client.rpt index 90e4cefb3d..66983edbcb 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/client.rpt @@ -174,13 +174,13 @@ connect await PARTITION_COUNT_4 "zilla://streams/app1" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:affinity 0x02 + option zilla:affinity 0x03 write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, -2) + .partition(3, -2) .build() .build()} @@ -190,26 +190,22 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, 1, 2) + .partition(3, 1, 2) .build() .build()} -write aborted -read abort - -write notify PARTITION_TWO_LEADER_ABORTED connect await PARTITION_COUNT_4 "zilla://streams/app1" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:affinity 0x03 + option zilla:affinity 0x02 write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, -2) + .partition(2, -2) .build() .build()} @@ -219,10 +215,15 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, 1, 2) + .partition(2, 1, 2) .build() .build()} +write aborted +read abort + +write notify PARTITION_TWO_LEADER_ABORTED + connect await PARTITION_ONE_LEADER_ABORTED "zilla://streams/app1" option zilla:window 8192 diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/server.rpt index b967a6face..5e0d83af3b 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.aborted/server.rpt @@ -183,14 +183,13 @@ write await ABORT_PARTITION_LEADERS_ONE_AND_TWO read abort write aborted - accepted read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, -2) + .partition(3, -2) .build() .build()} @@ -200,17 +199,12 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, 1, 2) + .partition(3, 1, 2) .build() .build()} write flush -write notify PARTITION_TWO_LEADER_READY - -write await ABORT_PARTITION_LEADERS_ONE_AND_TWO - -read abort -write aborted +write notify PARTITION_THREE_LEADER_READY accepted @@ -219,7 +213,7 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, -2) + .partition(2, -2) .build() .build()} @@ -229,13 +223,17 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, 1, 2) + .partition(2, 1, 2) .build() .build()} write flush -write notify PARTITION_THREE_LEADER_READY +write notify PARTITION_TWO_LEADER_READY + +write await ABORT_PARTITION_LEADERS_ONE_AND_TWO +read abort +write aborted # rejected zilla:resetEx ${kafka:resetEx("NOT_LEADER_FOR_PARTITION")} rejected diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/client.rpt index 658a342752..12d5766f1e 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/client.rpt @@ -180,7 +180,7 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, -2) + .partition(3, -2) .build() .build()} @@ -190,10 +190,14 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, 1, 3) + .partition(3, 1, 3) .build() .build()} +# write zilla:resetEx ${kafka:resetEx("NOT_LEADER_FOR_PARTITION")} +write aborted +read abort + connect await PARTITION_COUNT_4 "zilla://streams/app1" option zilla:window 8192 @@ -204,7 +208,7 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, -2) + .partition(2, -2) .build() .build()} @@ -214,14 +218,10 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, 1, 3) + .partition(2, 1, 3) .build() .build()} -# write zilla:resetEx ${kafka:resetEx("NOT_LEADER_FOR_PARTITION")} -write aborted -read abort - connect await PARTITION_LEADER_CHANGED "zilla://streams/app1" option zilla:window 8192 diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/server.rpt index a791515b19..1f14fd4351 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.fetch.partition.leader.changed/server.rpt @@ -178,7 +178,7 @@ read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, -2) + .partition(3, -2) .build() .build()} @@ -188,18 +188,24 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(2, 1, 3) + .partition(3, 1, 3) .build() .build()} write flush +read await CHANGED_PARTITION_LEADER + +# read zilla:resetEx ${kafka:resetEx("NOT_LEADER_FOR_PARTITION")} +read abort +write aborted + accepted read zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, -2) + .partition(2, -2) .build() .build()} @@ -209,17 +215,11 @@ write zilla:begin.ext ${kafka:beginEx() .typeId(zilla:id("kafka")) .fetch() .topic("test") - .partition(3, 1, 3) + .partition(2, 1, 3) .build() .build()} write flush -read await CHANGED_PARTITION_LEADER - -# read zilla:resetEx ${kafka:resetEx("NOT_LEADER_FOR_PARTITION")} -read abort -write aborted - accepted read zilla:begin.ext ${kafka:beginEx() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/client.rpt new file mode 100644 index 0000000000..3e6750c6de --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/client.rpt @@ -0,0 +1,413 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .describe() + .config("cleanup.policy", "delete") + .config("max.message.bytes", 1000012) + .config("segment.bytes", 1073741824) + .config("segment.index.bytes", 10485760) + .config("segment.ms", 604800000) + .config("retention.bytes", -1) + .config("retention.ms", 604800000) + .config("delete.retention.ms", 86400000) + .config("min.compaction.lag.ms", 0) + .config("max.compaction.lag.ms", 9223372036854775807) + .config("min.cleanable.dirty.ratio", 0.5) + .build() + .build()} + +read notify RECEIVED_CONFIG + +connect await RECEIVED_CONFIG + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .meta() + .partition(0, 2) + .build() + .build()} + + +read notify PARTITION_COUNT_2 + +connect await PARTITION_COUNT_2 + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .timeout(45000) + .metadata(kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .host("broker1.example.com") + .port(9092) + .timeout(30000) + .build() + .build()} + +read advised zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(0) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write ${kafka:memberAssignment() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} +write flush + +read ${kafka:topicAssignment() + .topic() + .id("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build()} + +write notify FETCH_REQUEST_RECEIVED + +read advised zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write flush + +read ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} + +write notify OFFSET_FETCH_REQUEST_RECEIVED + +read advised zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write flush + +read ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} + +read notify RECEIVED_CONSUMER + +connect await RECEIVED_CONSUMER + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .partition(0) + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .partition(0, 2, 0, "test-meta") + .build() + .build()} +read zilla:data.empty + +write close + +read notify RECEIVED_OFFSET_FETCH + +connect await RECEIVED_OFFSET_FETCH + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, -2) + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, 2, 2) + .build() + .build()} + +write abort + +read notify RECEIVED_REASSIGNMENT_FIRST + +connect await RECEIVED_REASSIGNMENT_FIRST + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +write abort + +read notify RECEIVED_REASSIGNMENT_SECOND + +connect await RECEIVED_REASSIGNMENT_SECOND + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .build() + .build()} + +read zilla:data.empty + +write close diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/server.rpt new file mode 100644 index 0000000000..0808c5deec --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.assignment.incomplete/server.rpt @@ -0,0 +1,402 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + +accept "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} +write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .describe() + .config("cleanup.policy", "delete") + .config("max.message.bytes", 1000012) + .config("segment.bytes", 1073741824) + .config("segment.index.bytes", 10485760) + .config("segment.ms", 604800000) + .config("retention.bytes", -1) + .config("retention.ms", 604800000) + .config("delete.retention.ms", 86400000) + .config("min.compaction.lag.ms", 0) + .config("max.compaction.lag.ms", 9223372036854775807) + .config("min.cleanable.dirty.ratio", 0.5) + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} +write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .meta() + .partition(0, 2) + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .timeout(45000) + .metadata(kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .instanceId("zilla") + .host("broker1.example.com") + .port(9092) + .timeout(30000) + .build() + .build()} + +write flush + +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(0) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write flush + +read ${kafka:memberAssignment() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write ${kafka:topicAssignment() + .topic() + .id("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build()} +write flush + +write await FETCH_REQUEST_RECEIVED + +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} +write flush + +read ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} +write flush + +write await OFFSET_FETCH_REQUEST_RECEIVED + +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} +write flush + +read ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .partition(0) + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .partition(0, 2, 0, "test-meta") + .build() + .build()} +write zilla:data.empty +write flush + +read closed + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, -2) + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, 2, 2) + .build() + .build()} +write flush + +write notify FETCH_REQUEST_RECEIVED + +read aborted + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +write notify OFFSET_FETCH_REQUEST_RECEIVED + +read aborted + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .build() + .build()} +write zilla:data.empty +write flush + +read closed diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/client.rpt index 0d306a2e59..3b180999ee 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/client.rpt @@ -161,12 +161,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/server.rpt index ada4fbf33e..ffa7e5e1d4 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.ack/server.rpt @@ -161,12 +161,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/client.rpt index e42199851b..144f69f58b 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/client.rpt @@ -160,12 +160,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/server.rpt index b95174c38d..c2fc22fd2c 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.message.value/server.rpt @@ -160,12 +160,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/client.rpt new file mode 100644 index 0000000000..ce045c0551 --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/client.rpt @@ -0,0 +1,329 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .describe() + .config("cleanup.policy", "delete") + .config("max.message.bytes", 1000012) + .config("segment.bytes", 1073741824) + .config("segment.index.bytes", 10485760) + .config("segment.ms", 604800000) + .config("retention.bytes", -1) + .config("retention.ms", 604800000) + .config("delete.retention.ms", 86400000) + .config("min.compaction.lag.ms", 0) + .config("max.compaction.lag.ms", 9223372036854775807) + .config("min.cleanable.dirty.ratio", 0.5) + .build() + .build()} + +read notify RECEIVED_CONFIG + +connect await RECEIVED_CONFIG + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .meta() + .partition(0, 2) + .build() + .build()} + + +read notify PARTITION_COUNT_2 + +connect await PARTITION_COUNT_2 + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .timeout(45000) + .metadata(kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .host("broker1.example.com") + .port(9092) + .timeout(30000) + .build() + .build()} + +read advised zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(0) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write ${kafka:memberAssignment() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} +write flush + +read ${kafka:topicAssignment() + .topic() + .id("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build()} + +write notify FETCH_REQUEST_RECEIVED + +read advised zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write flush + +read ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} + +read notify RECEIVED_CONSUMER + +connect await RECEIVED_CONSUMER + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .partition(0) + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .partition(0, 2, 0, "test-meta") + .build() + .build()} +read zilla:data.empty + +write close + +read notify RECEIVED_OFFSET_FETCH + +connect await RECEIVED_OFFSET_FETCH + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, -2) + .build() + .build()} + +connected + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, 2, 2) + .build() + .build()} + +write abort + +read notify RECEIVED_UNSUBSCRIPTION + +connect await RECEIVED_UNSUBSCRIPTION + "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .build() + .build()} + +read zilla:data.empty + +write close diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/server.rpt new file mode 100644 index 0000000000..84b6eeb883 --- /dev/null +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.fetch.unsubscribe/server.rpt @@ -0,0 +1,321 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + +accept "zilla://streams/app1" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .describe() + .topic("test") + .config("cleanup.policy") + .config("max.message.bytes") + .config("segment.bytes") + .config("segment.index.bytes") + .config("segment.ms") + .config("retention.bytes") + .config("retention.ms") + .config("delete.retention.ms") + .config("min.compaction.lag.ms") + .config("max.compaction.lag.ms") + .config("min.cleanable.dirty.ratio") + .build() + .build()} +write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .describe() + .config("cleanup.policy", "delete") + .config("max.message.bytes", 1000012) + .config("segment.bytes", 1073741824) + .config("segment.index.bytes", 10485760) + .config("segment.ms", 604800000) + .config("retention.bytes", -1) + .config("retention.ms", 604800000) + .config("delete.retention.ms", 86400000) + .config("min.compaction.lag.ms", 0) + .config("max.compaction.lag.ms", 9223372036854775807) + .config("min.cleanable.dirty.ratio", 0.5) + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .meta() + .topic("test") + .build() + .build()} +write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .meta() + .partition(0, 2) + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .timeout(45000) + .metadata(kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-1") + .protocol("rebalance") + .instanceId("zilla") + .host("broker1.example.com") + .port(9092) + .timeout(30000) + .build() + .build()} + +write flush + +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(0) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} + +write flush + +read ${kafka:memberAssignment() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write ${kafka:topicAssignment() + .topic() + .id("test") + .partitionId(0) + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build()} +write flush + +write await FETCH_REQUEST_RECEIVED + +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .generationId(1) + .leaderId("memberId-1") + .memberId("memberId-1") + .members("memberId-1", kafka:memberMetadata() + .consumerId("consumer-1") + .topic("test") + .partitionId(0) + .build() + .build()) + .members("memberId-2", kafka:memberMetadata() + .consumerId("consumer-2") + .topic("test") + .partitionId(0) + .build() + .build()) + .build() + .build()} +write flush + +read ${kafka:memberAssignment() + .member("memberId-2") + .assignment() + .topic("test") + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .member("memberId-1") + .assignment() + .topic("test") + .partitionId(0) + .consumer() + .id("consumer-2") + .build() + .consumer() + .id("consumer-1") + .partitionId(0) + .build() + .build() + .build() + .build()} + +write ${kafka:topicAssignment() + .topic() + .id("test") + .consumer() + .id("consumer-2") + .partitionId(0) + .build() + .build() + .build()} +write flush + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .partition(0) + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .partition(0, 2, 0, "test-meta") + .build() + .build()} +write zilla:data.empty +write flush + +read closed + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, -2) + .build() + .build()} + +connected + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .fetch() + .topic("test") + .partition(0, 2, 2) + .build() + .build()} +write flush + +write notify FETCH_REQUEST_RECEIVED + +read aborted + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .groupId("client-1") + .host("broker1.example.com") + .port(9092) + .topic("test") + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .offsetFetch() + .build() + .build()} +write zilla:data.empty +write flush + +read closed diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/client.rpt index f43f28565c..05014c30bf 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/client.rpt @@ -156,12 +156,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/server.rpt index 4e31b9f587..1f7f7b2be7 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.invalid.partition/server.rpt @@ -158,12 +158,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/client.rpt index 791e2589b6..04ee44e7ba 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/client.rpt @@ -156,12 +156,12 @@ write ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/server.rpt index 9edfd5f2d7..e5c5e72ceb 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/merged/unmerged.group.produce.message.value/server.rpt @@ -158,12 +158,12 @@ read ${kafka:memberAssignment() .member("memberId-1") .assignment() .topic("test") - .partitionId(0) .partitionId(1) + .partitionId(0) .consumer() .id("consumer-1") - .partitionId(0) .partitionId(1) + .partitionId(0) .build() .build() .build() diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/message.values.producer.id.changes/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/message.values.producer.id.changes/client.rpt index 4b980edead..b2cec8629d 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/message.values.producer.id.changes/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/message.values.producer.id.changes/client.rpt @@ -15,7 +15,8 @@ # property deltaMillis 0L -property newTimestamp ${kafka:timestamp() + deltaMillis} +property timestamp 1715191875046L +property newTimestamp ${timestamp + deltaMillis} connect "zilla://streams/app0" option zilla:window 8192 diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/client.rpt index 5a4a635593..70e5986a84 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/client.rpt @@ -70,11 +70,19 @@ write zilla:data.ext ${kafka:dataEx() .build()} write flush -write "Hello, world" -write flush write "Hello, again" write flush +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .produce() + .timestamp(newTimestamp) + .build() + .build()} +write flush +write "Hello, world" +write flush + read zilla:reset.ext ${kafka:resetEx() .typeId(zilla:id("kafka")) .error(6) @@ -114,7 +122,14 @@ write zilla:data.ext ${kafka:dataEx() .timestamp(newTimestamp) .build() .build()} -write "Hello, world" -write flush write "Hello, again" write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .produce() + .timestamp(newTimestamp) + .build() + .build()} +write "Hello, world" +write flush diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/server.rpt index 9195ec8d01..3b990edeeb 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/application/produce/partition.not.leader.reconnect.parallel/server.rpt @@ -72,9 +72,15 @@ read zilla:data.ext ${kafka:matchDataEx() .produce() .build() .build()} -read "Hello, world" read "Hello, again" +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .produce() + .build() + .build()} +read "Hello, world" + write zilla:reset.ext ${kafka:resetEx() .typeId(zilla:id("kafka")) .error(6) @@ -107,8 +113,16 @@ read zilla:data.ext ${kafka:matchDataEx() .produce() .build() .build()} -read "Hello, world" read "Hello, again" +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .produce() + .build() + .build()} +read "Hello, world" + + + read option zilla:ack 24 write flush diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/client.rpt index f452e74075..acff5e148e 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/client.rpt @@ -19,6 +19,9 @@ property networkConnectWindow 8192 property newRequestId ${kafka:newRequestId()} property produceWaitMax 500 +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + connect "zilla://streams/net0" option zilla:window ${networkConnectWindow} option zilla:transmission "duplex" @@ -98,7 +101,7 @@ write 140 # size 83 # length -1 [0x02] - 0x4e8723aa + 0x0460c54e9 0s 0 # last offset delta ${newTimestamp} # first timestamp @@ -148,7 +151,7 @@ write 140 # size 83 # length -1 [0x02] - 0x4e8723aa + 0x026cd6cf 0s 0 # last offset delta ${newTimestamp} # first timestamp diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/server.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/server.rpt index f9741db993..f0bbfa17ef 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/server.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id.changes/server.rpt @@ -16,9 +16,6 @@ property networkAcceptWindow 8192 -property deltaMillis 0L -property newTimestamp ${kafka:timestamp() + deltaMillis} - accept "zilla://streams/net0" option zilla:window ${networkAcceptWindow} option zilla:transmission "duplex" @@ -94,7 +91,7 @@ read 140 83 # length -1 [0x02] - [0..4] + 0x0460c54e9 0s 0 # last offset delta (long:timestamp) # first timestamp @@ -144,7 +141,7 @@ read 140 83 # length -1 [0x02] - [0..4] + 0x026cd6cf 0s 0 # last offset delta (long:timestamp) # first timestamp diff --git a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id/client.rpt b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id/client.rpt index c0652f5969..7c13c115d4 100644 --- a/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id/client.rpt +++ b/specs/binding-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/kafka/streams/network/produce.v3/message.values.producer.id/client.rpt @@ -19,6 +19,9 @@ property networkConnectWindow 8192 property newRequestId ${kafka:newRequestId()} property produceWaitMax 500 +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + connect "zilla://streams/net0" option zilla:window ${networkConnectWindow} option zilla:transmission "duplex" diff --git a/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/internal/KafkaFunctionsTest.java b/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/internal/KafkaFunctionsTest.java index 4f2b862f5f..aa6e3dbcdd 100644 --- a/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/internal/KafkaFunctionsTest.java +++ b/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/internal/KafkaFunctionsTest.java @@ -151,9 +151,9 @@ public void shouldGenerateMemberAssignment() .partitionId(0) .partitionId(1) .build() + .build() .build() - .build() - .build(); + .build(); DirectBuffer buffer = new UnsafeBuffer(build); Array32FW assignments = @@ -4386,8 +4386,8 @@ public void shouldGenerateOffsetFetchDataExtension() .typeId(0x01) .offsetFetch() .partition(0, 1L, 0, "test-meta") - .build() - .build(); + .build() + .build(); DirectBuffer buffer = new UnsafeBuffer(build); KafkaDataExFW dataEx = new KafkaDataExFW().wrap(buffer, 0, buffer.capacity()); diff --git a/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/streams/application/MergedIT.java b/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/streams/application/MergedIT.java index 49e72ce225..6ae0943d59 100644 --- a/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/streams/application/MergedIT.java +++ b/specs/binding-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/kafka/streams/application/MergedIT.java @@ -891,4 +891,31 @@ public void shouldProduceUnmergedMessageValueByGettingPartitionId() throws Excep k3po.finish(); } + @Test + @Specification({ + "${app}/merged.fetch.unsubscribe/client", + "${app}/merged.fetch.unsubscribe/server"}) + public void shouldUnsubscribeOnPartitionReassignment() throws Exception + { + k3po.finish(); + } + + @Test + @Specification({ + "${app}/unmerged.group.fetch.unsubscribe/client", + "${app}/unmerged.group.fetch.unsubscribe/server"}) + public void shouldUnsubscribeUnmergeOnPartitionReassignment() throws Exception + { + k3po.finish(); + } + + @Test + @Specification({ + "${app}/unmerged.group.fetch.assignment.incomplete/client", + "${app}unmerged.group.fetch.assignment.incomplete/server"}) + public void shouldCancelUnmergedPreviousIncompleteOffsetFetchRequest() throws Exception + { + k3po.finish(); + } + } diff --git a/specs/binding-mqtt-kafka.spec/pom.xml b/specs/binding-mqtt-kafka.spec/pom.xml index 32b677ac9d..dad9e2e0d9 100644 --- a/specs/binding-mqtt-kafka.spec/pom.xml +++ b/specs/binding-mqtt-kafka.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.publish.topic.with.messages.params.yaml b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.publish.topic.with.messages.params.yaml new file mode 100644 index 0000000000..1bfe463bdb --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.publish.topic.with.messages.params.yaml @@ -0,0 +1,34 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +bindings: + mqtt0: + type: mqtt-kafka + kind: proxy + options: + topics: + sessions: mqtt-sessions + messages: mqtt-messages + retained: mqtt-retained + routes: + - exit: kafka0 + when: + - publish: + - topic: sensor/{sensorId} + with: + messages: sensors.${params.sensorId} + diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.subscribe.topic.with.messages.params.yaml b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.subscribe.topic.with.messages.params.yaml new file mode 100644 index 0000000000..48712f2d93 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/config/proxy.when.subscribe.topic.with.messages.params.yaml @@ -0,0 +1,33 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +bindings: + mqtt0: + type: mqtt-kafka + kind: proxy + options: + topics: + sessions: mqtt-sessions + messages: mqtt-messages + retained: mqtt-retained + routes: + - exit: kafka0 + when: + - subscribe: + - topic: sensor/{sensorId} + with: + messages: sensors.${params.sensorId} diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/client.rpt new file mode 100644 index 0000000000..ff3f089433 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/client.rpt @@ -0,0 +1,55 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("sensors.one") + .partition(-1, -2) + .ackMode("NONE") + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client") + .headerInt("zilla:expiry", 15) + .header("zilla:content-type", "message") + .header("zilla:format", "TEXT") + .header("zilla:reply-to", "sensors.one") + .header("zilla:reply-key", "sensor/one") + .header("zilla:reply-filter", "sensor") + .header("zilla:reply-filter", "one") + .header("zilla:correlation-id", "info") + .header("zilla:qos", "0") + .build() + .build()} + + +write "message" diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/server.rpt new file mode 100644 index 0000000000..679c10cfac --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.one.message.resolve.topic.params/server.rpt @@ -0,0 +1,57 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("sensors.one") + .partition(-1, -2) + .ackMode("NONE") + .build() + .build()} + + +connected + +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client") + .headerInt("zilla:expiry", 15) + .header("zilla:content-type", "message") + .header("zilla:format", "TEXT") + .header("zilla:reply-to", "sensors.one") + .header("zilla:reply-key", "sensor/one") + .header("zilla:reply-filter", "sensor") + .header("zilla:reply-filter", "one") + .header("zilla:correlation-id", "info") + .header("zilla:qos", "0") + .build() + .build()} + +read "message" diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/client.rpt index c3a673319e..acb2a65cf3 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/client.rpt @@ -277,25 +277,4 @@ write zilla:data.ext ${kafka:dataEx() .build()} write flush -write zilla:data.ext ${kafka:dataEx() - .typeId(zilla:id("kafka")) - .merged() - .produce() - .deferred(0) - .partition(-1, -1) - .key("client#expiry-signal") - .hashKey("client") - .header("type", "expiry-signal") - .build() - .build()} -write ${mqtt:sessionSignal() - .expiry() - .instanceId("zilla-1") - .clientId("client") - .delay(1000) - .expireAt(-1) - .build() - .build()} -write flush - read advised zilla:flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/server.rpt index 728b295bb3..e46ed2ec69 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.qos2.recovery/server.rpt @@ -250,39 +250,4 @@ read zilla:begin.ext ${kafka:matchBeginEx() connected -# session expiry cancellation signal for client -read zilla:data.ext ${kafka:matchDataEx() - .typeId(zilla:id("kafka")) - .merged() - .produce() - .deferred(0) - .partition(-1, -1) - .key("client#expiry-signal") - .hashKey("client") - .header("type", "expiry-signal") - .build() - .build()} -read zilla:data.null - -# session expire later signal for client -read zilla:data.ext ${kafka:matchDataEx() - .typeId(zilla:id("kafka")) - .merged() - .produce() - .deferred(0) - .partition(-1, -1) - .key("client#expiry-signal") - .hashKey("client") - .header("type", "expiry-signal") - .build() - .build()} -read ${mqtt:sessionSignal() - .expiry() - .instanceId("zilla-1") - .clientId("client") - .delay(1000) - .expireAt(-1) - .build() - .build()} - write advise zilla:flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/client.rpt new file mode 100644 index 0000000000..3fdd0c6ee0 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/client.rpt @@ -0,0 +1,138 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_AND_FETCH") + .topic("mqtt-sessions") + .filter() + .key("client#migrate") + .headerNot("sender-id", "sender-1") + .build() + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#migrate") + .hashKey("client") + .header("sender-id", "sender-1") + .build() + .build()} +write zilla:data.empty +write flush +write notify SENT_INIT_MIGRATE + +write close +read closed + + +connect await SENT_INIT_MIGRATE + "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-session") + .protocol("highlander") + .timeout(1000) + .build() + .build()} + +connected + +read advised zilla:flush ${kafka:matchFlushEx() + .typeId(zilla:id("kafka")) + .group() + .leaderId("consumer-1") + .memberId("consumer-1") + .members("consumer-1") + .build() + .build()} +read notify RECEIVED_LEADER + +write zilla:data.empty + + +connect await RECEIVED_LEADER + "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_AND_FETCH") + .topic("mqtt-sessions") + .filter() + .key("client") + .build() + .filter() + .key("client#migrate") + .headerNot("sender-id", "sender-1") + .build() + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#expiry-signal") + .hashKey("client") + .header("type", "expiry-signal") + .build() + .build()} +write flush + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#expiry-signal") + .hashKey("client") + .header("type", "expiry-signal") + .build() + .build()} +write ${mqtt:sessionSignal() + .expiry() + .instanceId("zilla-1") + .clientId("client") + .delay(1000) + .expireAt(-1) + .build() + .build()} +write flush + +read advised zilla:flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/server.rpt new file mode 100644 index 0000000000..18fedbb5d2 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.reject.qos2/server.rpt @@ -0,0 +1,134 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_AND_FETCH") + .topic("mqtt-sessions") + .filter() + .key("client#migrate") + .headerNot("sender-id", "sender-1") + .build() + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#migrate") + .hashKey("client") + .header("sender-id", "sender-1") + .build() + .build()} +read zilla:data.empty + +read closed +write close + + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .group() + .groupId("client-session") + .protocol("highlander") + .timeout(1000) + .build() + .build()} + +connected + +# This is the second prerequisite +write advise zilla:flush ${kafka:flushEx() + .typeId(zilla:id("kafka")) + .group() + .leaderId("consumer-1") + .memberId("consumer-1") + .members("consumer-1") + .build() + .build()} +write flush + +read zilla:data.empty + + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_AND_FETCH") + .topic("mqtt-sessions") + .filter() + .key("client") + .build() + .filter() + .key("client#migrate") + .headerNot("sender-id", "sender-1") + .build() + .build() + .build()} + +connected + +# session expiry cancellation signal for client +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#expiry-signal") + .hashKey("client") + .header("type", "expiry-signal") + .build() + .build()} +read zilla:data.null + +# session expire later signal for client +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("client#expiry-signal") + .hashKey("client") + .header("type", "expiry-signal") + .build() + .build()} +read ${mqtt:sessionSignal() + .expiry() + .instanceId("zilla-1") + .clientId("client") + .delay(1000) + .expireAt(-1) + .build() + .build()} + +write advise zilla:flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/client.rpt new file mode 100644 index 0000000000..10b19eb268 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/client.rpt @@ -0,0 +1,49 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("sensors.one") + .partition(-1, -2) + .ackMode("NONE") + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client-1") + .header("zilla:format", "TEXT") + .header("zilla:qos", "0") + .build() + .build()} + +write "Hello, world" +write flush + diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/server.rpt new file mode 100644 index 0000000000..1239ee98f2 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/publish.topic.space.with.params/server.rpt @@ -0,0 +1,50 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("sensors.one") + .partition(-1, -2) + .ackMode("NONE") + .build() + .build()} + + +connected + +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .deferred(0) + .partition(-1, -1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client-1") + .header("zilla:format", "TEXT") + .header("zilla:qos", "0") + .build() + .build()} + +read "Hello, world" diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/client.rpt new file mode 100644 index 0000000000..dd5361a50e --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/client.rpt @@ -0,0 +1,53 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("sensors.one") + .filter() + .headers("zilla:filter") + .sequence("sensor") + .sequence("one") + .build() + .build() + .evaluation("EAGER") + .build() + .build()} + +connected + +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .fetch() + .filters(1) + .partition(0, 1, 2) + .progress(0, 2) + .progress(1, 1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client") + .header("zilla:format", "TEXT") + .build() + .build()} + +read "message" diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/server.rpt new file mode 100644 index 0000000000..dcbef7d027 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/kafka/subscribe.one.message.resolve.topic.params/server.rpt @@ -0,0 +1,57 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/kafka0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${kafka:matchBeginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("sensors.one") + .filter() + .headers("zilla:filter") + .sequence("sensor") + .sequence("one") + .build() + .build() + .evaluation("EAGER") + .build() + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .fetch() + .timestamp(kafka:timestamp()) + .filters(1) + .partition(0, 1, 2) + .progress(0, 2) + .progress(1, 1) + .key("sensor/one") + .header("zilla:filter", "sensor") + .header("zilla:filter", "one") + .header("zilla:local", "client") + .header("zilla:format", "TEXT") + .build() + .build()} + +write "message" +write flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/client.rpt index b69e3f718e..fb1cc73124 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/client.rpt @@ -33,6 +33,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/server.rpt index 770df0be77..6d855f0140 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.mixture.qos/server.rpt @@ -35,6 +35,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/client.rpt index 72055eab6e..4edcfec6c8 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/client.rpt @@ -33,6 +33,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/server.rpt index 46a062b407..572f3caea2 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase1/server.rpt @@ -35,6 +35,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/client.rpt index d41271d752..cf3ba2db5c 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/client.rpt @@ -33,6 +33,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/server.rpt index 30e1bbe368..615b859b60 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.offset.commit.abort.phase2/server.rpt @@ -35,6 +35,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/client.rpt index eb207d9b9a..966b74a438 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/client.rpt @@ -20,7 +20,6 @@ connect "zilla://streams/mqtt0" write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) .session() - .flags("CLEAN_START") .expiry(1) .publishQosMax(2) .capabilities("REDIRECT") @@ -33,6 +32,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .packetId(1) diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/server.rpt index 43882d38cd..2d7b9e1ec5 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.recovery/server.rpt @@ -22,7 +22,6 @@ accepted read zilla:begin.ext ${mqtt:matchBeginEx() .typeId(zilla:id("mqtt")) .session() - .flags("CLEAN_START") .expiry(1) .publishQosMax(2) .capabilities("REDIRECT") @@ -35,6 +34,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") .packetId(1) diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/client.rpt index 82f9e3ae6b..a2345ad25a 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/client.rpt @@ -33,6 +33,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/server.rpt index aeb5a33408..0753a37213 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2.retained/server.rpt @@ -35,6 +35,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/client.rpt index e73e50b548..eac0e14eca 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/client.rpt @@ -33,6 +33,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/server.rpt index c161fc4087..f160e4c89b 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.qos2/server.rpt @@ -35,6 +35,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/client.rpt new file mode 100644 index 0000000000..8f41d8723e --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/client.rpt @@ -0,0 +1,62 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/mqtt0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${mqtt:beginEx() + .typeId(zilla:id("mqtt")) + .session() + .flags("CLEAN_START") + .expiry(1) + .publishQosMax(2) + .capabilities("REDIRECT") + .clientId("client") + .build() + .build()} + +read zilla:begin.ext ${mqtt:matchBeginEx() + .typeId(zilla:id("mqtt")) + .session() + .expiry(1) + .subscribeQosMax(2) + .publishQosMax(1) + .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") + .clientId("client") + .build() + .build()} + +connected + +read zilla:data.empty +read notify RECEIVED_SESSION_STATE + + +connect await RECEIVED_SESSION_STATE + "zilla://streams/mqtt0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${mqtt:beginEx() + .typeId(zilla:id("mqtt")) + .publish() + .clientId("client") + .topic("sensor/one") + .qos(2) + .build() + .build()} + +connect aborted diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/server.rpt new file mode 100644 index 0000000000..9e2f4c4eb4 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.reject.qos2/server.rpt @@ -0,0 +1,52 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/mqtt0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${mqtt:matchBeginEx() + .typeId(zilla:id("mqtt")) + .session() + .flags("CLEAN_START") + .expiry(1) + .publishQosMax(2) + .capabilities("REDIRECT") + .clientId("client") + .build() + .build()} + +write zilla:begin.ext ${mqtt:beginEx() + .typeId(zilla:id("mqtt")) + .session() + .expiry(1) + .subscribeQosMax(2) + .publishQosMax(2) + .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") + .clientId("client") + .build() + .build()} + +connected + +write zilla:data.empty +write flush + + +rejected + + diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/client.rpt new file mode 100644 index 0000000000..4ba42ecf7c --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/client.rpt @@ -0,0 +1,38 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/mqtt0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${mqtt:beginEx() + .typeId(zilla:id("mqtt")) + .publish() + .clientId("client-1") + .topic("sensor/one") + .build() + .build()} + +connected + +write zilla:data.ext ${mqtt:dataEx() + .typeId(zilla:id("mqtt")) + .publish() + .format("TEXT") + .build() + .build()} + +write "Hello, world" +write flush diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/server.rpt new file mode 100644 index 0000000000..3fb7a6db17 --- /dev/null +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/publish.topic.space.with.params/server.rpt @@ -0,0 +1,39 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/mqtt0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${mqtt:matchBeginEx() + .typeId(zilla:id("mqtt")) + .publish() + .clientId("client-1") + .topic("sensor/one") + .build() + .build()} + +connected + +read zilla:data.ext ${mqtt:matchDataEx() + .typeId(zilla:id("mqtt")) + .publish() + .format("TEXT") + .build() + .build()} + +read "Hello, world" diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/client.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/client.rpt index a1d1b43209..3944516b21 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/client.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client-1") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/server.rpt b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/server.rpt index fd0f073269..94a3ce2a6c 100644 --- a/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/server.rpt +++ b/specs/binding-mqtt-kafka.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/mqtt/session.subscribe/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD") .clientId("client-1") .build() diff --git a/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/KafkaIT.java b/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/KafkaIT.java index ec7de4d86e..ad86104769 100644 --- a/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/KafkaIT.java +++ b/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/KafkaIT.java @@ -134,6 +134,15 @@ public void shouldSendOneMessageWithChangedTopicName() throws Exception k3po.finish(); } + @Test + @Specification({ + "${kafka}/publish.one.message.resolve.topic.params/client", + "${kafka}/publish.one.message.resolve.topic.params/server"}) + public void shouldSendOneMessageWithResolvingParams() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${kafka}/publish.10k/client", @@ -188,6 +197,24 @@ public void shouldSendUsingTopicSpace() throws Exception k3po.finish(); } + @Test + @Specification({ + "${kafka}/publish.topic.space.with.params/client", + "${kafka}/publish.topic.space.with.params/server"}) + public void shouldSendUsingTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + + @Test + @Specification({ + "${kafka}/publish.reject.qos2/client", + "${kafka}/publish.reject.qos2/server"}) + public void shouldRejectPublishWhenTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${kafka}/publish.client.topic.space/client", @@ -359,6 +386,15 @@ public void shouldReceiveOneMessageWithChangedTopicName() throws Exception k3po.finish(); } + @Test + @Specification({ + "${kafka}/subscribe.one.message.resolve.topic.params/client", + "${kafka}/subscribe.one.message.resolve.topic.params/server"}) + public void shouldReceiveOneMessageWithResolvingParams() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${kafka}/subscribe.one.message.receive.response.topic.and.correlation.data/client", diff --git a/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/MqttIT.java b/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/MqttIT.java index 973a4d0661..15cfc5bd6b 100644 --- a/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/MqttIT.java +++ b/specs/binding-mqtt-kafka.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/kafka/streams/MqttIT.java @@ -143,6 +143,24 @@ public void shouldSendUsingTopicSpace() throws Exception k3po.finish(); } + @Test + @Specification({ + "${mqtt}/publish.topic.space.with.params/client", + "${mqtt}/publish.topic.space.with.params/server"}) + public void shouldSendUsingTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + + @Test + @Specification({ + "${mqtt}/publish.reject.qos2/client", + "${mqtt}/publish.reject.qos2/server"}) + public void shouldRejectPublishWhenTopicSpaceWithParams() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${mqtt}/publish.client.topic.space/client", diff --git a/specs/binding-mqtt.spec/pom.xml b/specs/binding-mqtt.spec/pom.xml index f95f2d4ea5..c237e2c97a 100644 --- a/specs/binding-mqtt.spec/pom.xml +++ b/specs/binding-mqtt.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-mqtt.spec/src/main/resources/META-INF/zilla/mqtt.idl b/specs/binding-mqtt.spec/src/main/resources/META-INF/zilla/mqtt.idl index 9431a6b159..b9889d621d 100644 --- a/specs/binding-mqtt.spec/src/main/resources/META-INF/zilla/mqtt.idl +++ b/specs/binding-mqtt.spec/src/main/resources/META-INF/zilla/mqtt.idl @@ -261,4 +261,23 @@ scope mqtt INCOMPLETE(1) } } + + scope event + { + enum MqttEventType (uint8) + { + CLIENT_CONNECTED (1) + } + + struct MqttClientConnectedEx extends core::stream::Extension + { + string8 identity; + string8 clientId; + } + + union MqttEventEx switch (MqttEventType) + { + case CLIENT_CONNECTED: MqttClientConnectedEx clientConnected; + } + } } diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.password.yaml b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.password.yaml new file mode 100644 index 0000000000..d77b729782 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.password.yaml @@ -0,0 +1,37 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +guards: + test0: + type: test + options: + credentials: TOKEN + lifetime: PT5S + challenge: PT5S +bindings: + app0: + type: mqtt + kind: client + options: + authorization: + test0: + credentials: + connect: + password: Bearer {credentials} + routes: + - exit: net0 diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.username.yaml b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.username.yaml new file mode 100644 index 0000000000..0fca965ec4 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/client.credentials.username.yaml @@ -0,0 +1,37 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +guards: + test0: + type: test + options: + credentials: TOKEN + lifetime: PT5S + challenge: PT5S +bindings: + app0: + type: mqtt + kind: client + options: + authorization: + test0: + credentials: + connect: + username: Bearer {credentials} + routes: + - exit: net0 diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/server.log.event.yaml b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/server.log.event.yaml new file mode 100644 index 0000000000..53d5edc154 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/config/server.log.event.yaml @@ -0,0 +1,33 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.net0 + id: binding.mqtt.client.connected + message: CLIENT_CONNECTED - client +bindings: + net0: + type: mqtt + kind: server + routes: + - exit: app0 diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/schema/mqtt.schema.patch.json b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/schema/mqtt.schema.patch.json index df0013a37c..eef119faf1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/schema/mqtt.schema.patch.json +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/schema/mqtt.schema.patch.json @@ -32,59 +32,6 @@ "enum": [ "server", "client" ] }, "vault": false, - "options": - { - "properties": - { - "versions": - { - "title": "Versions", - "type": "array", - "items": - { - "type": "string", - "enum": [ "v3.1.1", "v5" ] - } - }, - "authorization": - { - "$ref": "#/$defs/options/binding/mqtt/authorization" - }, - "topics": - { - "title": "Topics", - "type": "array", - "items": - { - "type": "object", - "additionalProperties": false, - "properties": - { - "name": - { - "type": "string" - }, - "content": - { - "$ref": "#/$defs/validator" - }, - "user-properties": - { - "type": "object", - "patternProperties": - { - "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$": - { - "$ref": "#/$defs/validator" - } - } - } - } - } - } - }, - "additionalProperties": false - }, "routes": { "items": @@ -159,6 +106,91 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "server" + }, + "options": + { + "properties": + { + "versions": + { + "title": "Versions", + "type": "array", + "items": + { + "type": "string", + "enum": [ "v3.1.1", "v5" ] + } + }, + "authorization": + { + "$ref": "#/$defs/options/binding/mqtt/authorization" + }, + "topics": + { + "title": "Topics", + "type": "array", + "items": + { + "type": "object", + "additionalProperties": false, + "properties": + { + "name": + { + "type": "string" + }, + "content": + { + "$ref": "#/$defs/validator" + }, + "user-properties": + { + "type": "object", + "patternProperties": + { + "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$": + { + "$ref": "#/$defs/validator" + } + } + } + } + } + } + }, + "additionalProperties": false + } + } + }, + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": + { + "properties": + { + "authorization": + { + "$ref": "#/$defs/options/binding/mqtt/authorization" + } + }, + "additionalProperties": false + } + } + } ] } } diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/client.rpt index 6364266fa4..1bb250edf2 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/server.rpt index 26e83a2ab5..3cbf4033c5 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/client.sent.abort/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/client.rpt index dd1f786658..545867d707 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(50) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/server.rpt index 0ad5bd74ac..d2350e73b4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.max.packet.size.exceeded/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(50) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/client.rpt index 6d28a51db8..c898086658 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/server.rpt index 61743454bb..8478c5bb39 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.non.successful.disconnect/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/client.rpt index 0c064accae..c367b4d5f9 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/server.rpt index d5ea02814f..7dc4216edb 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.reject.will.retain.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/client.rpt index ec6e3a4ef7..cb47801fde 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/server.rpt index 417c798e8a..f2c004bb37 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/connect.retain.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/client.rpt index bff7b12332..4d84bdecae 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/server.rpt index 27c0e9894a..fb12feefb1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/disconnect.after.subscribe.and.publish/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/client.rpt index ee3aedb394..84cfad4e92 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/server.rpt index ede4b66df7..5f2df685df 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.10k/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/client.rpt index e4095349c7..30a1a2c33d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/server.rpt index b2aa6b4baa..db848e118a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/client.rpt index 135c2b1627..159a0e8ed0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/server.rpt index 3fe24c4d94..cb2be69881 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.empty.retained.message/server.rpt @@ -34,6 +34,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/client.rpt index 3e0da6e53e..7673cb556a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/server.rpt index 43a600bab2..6ba09a9b87 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.message.with.topic.alias/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/client.rpt index e01510fff9..9bf42c5416 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/server.rpt index a978b46735..d784aa9c54 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.distinct/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/client.rpt index d75da00da8..0a508fa66d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/server.rpt index 8e3d8d2955..4983114dd1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.invalid.scope/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -88,6 +89,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/client.rpt index 0b815f902c..535ffbb22f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/server.rpt index 2c6bdfc015..2d008c95a4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.repeated/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/client.rpt index c8da04d36f..6bc8fd288b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/server.rpt index d7021f1b9d..db9e3ffecc 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.messages.with.topic.alias.replaced/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/client.rpt index 61890af08e..e1b997414a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/server.rpt index fb46b4ceb8..13b9b4905c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.mixture.qos/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/client.rpt index 8aa78bb727..433ec39316 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") @@ -90,6 +91,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/server.rpt index 7f30cac1d1..1c1817bd1e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.clients/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") @@ -60,6 +61,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/client.rpt index 1ebe11fb55..26fb587d08 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/server.rpt index cf35fd4e73..8ead144da4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages.timeout/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/client.rpt index 4ce978cd51..4e5adc2881 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/server.rpt index 0f5527bd63..73a9f59565 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.multiple.messages/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/client.rpt index 3e3389fa33..66df3767c3 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/server.rpt index 4ee206b05f..f71a7c13c8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.one.message.properties/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/client.rpt index fc1613e1fc..3b22506115 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/server.rpt index 951caddb35..e901751568 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos1.dup.after.puback/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/client.rpt index 7c5d6cf006..22a93ea6d7 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/server.rpt index d45a074fbc..b3d89fd693 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.ack.with.reasoncode/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/client.rpt index 7c5d6cf006..22a93ea6d7 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/server.rpt index 474b3e7e64..a4ead661cd 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.no.dupicate.before.pubrel/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/client.rpt index bdeea89b10..32681d0f34 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "WILDCARD", "SHARED_SUBSCRIPTIONS") .clientId("client") .packetId(1) diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/server.rpt index 754c2746d2..f7f2696549 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.qos2.recovery/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") .packetId(1) diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/client.rpt index 0f2c175c72..5cc957e5c0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/server.rpt index afb88e0716..31d8556893 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.large.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/client.rpt index 57aa676b9d..a004870261 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(0) + .publishQosMax(0) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -40,20 +41,3 @@ read zilla:begin.ext ${mqtt:matchBeginEx() connected read zilla:data.empty -read notify RECEIVED_SESSION_STATE - - -connect await RECEIVED_SESSION_STATE - "zilla://streams/app0" - option zilla:window 8192 - option zilla:transmission "duplex" - -write zilla:begin.ext ${mqtt:beginEx() - .typeId(zilla:id("mqtt")) - .publish() - .clientId("client") - .topic("sensor/one") - .build() - .build()} - -connected diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/server.rpt index 544de8fc3b..de81a75720 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.qos.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(0) + .publishQosMax(0) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -45,18 +46,3 @@ write zilla:data.empty write flush read aborted - - -accepted - -read zilla:begin.ext ${mqtt:matchBeginEx() - .typeId(zilla:id("mqtt")) - .publish() - .clientId("client") - .topic("sensor/one") - .build() - .build()} - -connected - -read aborted diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/client.rpt index e91bb67055..5626ef80fa 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities(WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/server.rpt index 75b2922373..d2c6545fd9 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.reject.retain.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/client.rpt index af4572e6ae..1e3d6629ae 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/server.rpt index 4e9f74acdb..df4ab1e2d8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.retained/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/client.rpt index 174476d2d5..97b39b53fa 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/server.rpt index 53f718055e..a0e9b6cfcb 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.subscribe.batched/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/client.rpt index c320d8da63..911ee17a1e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/server.rpt index 7da3fc82e9..de80575ccf 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.unroutable/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/client.rpt index ee091b154c..29360302d1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/server.rpt index 5d56222518..2ffe211cfa 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/client.rpt index 1881a02477..5f09176c12 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/server.rpt index 3223d047c9..2577a4e7eb 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.valid.user.property/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/client.rpt index 1ec36e0807..9ede487274 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/server.rpt index c4c13f0315..5a53f8712e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.distinct/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/client.rpt index 1b08738955..4565948717 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/server.rpt index e53051d4bb..8ee4a913cc 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.properties.repeated/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/client.rpt index 6965c126ab..c1023f70df 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/server.rpt index c7581f5668..6670431a89 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/publish.with.user.property/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("755452d5-e2ef-4113-b9c6-2f53de96fd76") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/client.rpt index 12238e3d1e..d470faa965 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -95,6 +96,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/server.rpt index 0e92c5b8aa..68cc5c04f9 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.abort.reconnect.non.clean.start/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -90,6 +91,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/client.rpt index 5510810418..d0819d9f5c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -96,6 +97,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/server.rpt index 3c74c7e45b..40cfde955b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.client.takeover/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -94,6 +95,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/client.rpt index 706fe66a81..0b16c5683b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/server.rpt index 76ca3601f9..e846357923 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.abort/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/client.rpt index 4a9638e8da..5127d7b116 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/client.rpt @@ -32,6 +32,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/server.rpt index 5dd753719d..cf0c3d29be 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.authorization/server.rpt @@ -34,6 +34,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/client.rpt index 1d9ca21058..61e9c6c237 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/client.rpt @@ -32,6 +32,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .flags("CLEAN_START") .expiry(30) .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/server.rpt index 5596eb6ee0..142c8ddaf3 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.override.session.expiry/server.rpt @@ -34,6 +34,7 @@ write zilla:begin.ext ${mqtt:beginEx() .flags("CLEAN_START") .expiry(30) .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/client.rpt index 346b2b59d3..58dce8eab4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS", "REDIRECT") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/server.rpt index f34fba7b7f..86e52fd69d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.redirect.support/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS", "REDIRECT") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/client.rpt index b515e8cc74..312c962a6f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/server.rpt index 447a459379..fbc9ae5dec 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect.with.session.expiry/server.rpt @@ -34,6 +34,7 @@ write zilla:begin.ext ${mqtt:beginEx() .flags("CLEAN_START") .expiry(1) .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/client.rpt index d4e95f8d07..c95f52e672 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/server.rpt index 76ca3601f9..e846357923 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.connect/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/client.rpt index a084768629..2582a7c0d6 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -100,6 +101,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/server.rpt index 7d5cd23034..b952361a61 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.exists.clean.start/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -94,6 +95,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/client.rpt index d758fcb964..e6ae1c6c22 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/server.rpt index 98bb0363f3..6091739264 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.after.connack/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/client.rpt index 738bd0d94d..323f9d8890 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/server.rpt index 36f807ed77..e30e6a4efa 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.invalid.session.timeout.before.connack/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/client.rpt index 3763d572a6..ccf21a8555 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/server.rpt index 73b79fb79b..388144fa68 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.publish/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/client.rpt index e96d972a90..675b296f2b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/server.rpt index 38607b3e67..6557b682c1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.after.connack/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/client.rpt index 9819844bca..6f2326a435 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/server.rpt index 517aedb68e..a162988cf0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.redirect.before.connack/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/client.rpt index ff262c1ac9..7183ba3bc5 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/server.rpt index 5e795bd2bb..c5683422be 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.server.sent.abort/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/client.rpt index 05fbfda3d0..4a1fcb62dd 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/server.rpt index 1d03c4dbbd..23e62399a1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.multiple.isolated/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/client.rpt index b29fabab6b..1d817babcc 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/server.rpt index 57f1238b19..b459d1d18a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.publish.routing/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/client.rpt index d937db9857..8862a11f7f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/server.rpt index 2784d15424..ddf94f6847 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe.via.session.state/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/client.rpt index bfe3e5967c..b1e9372b8c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/server.rpt index 614473660a..5ed49b8910 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.subscribe/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/client.rpt index 1d2eeb3cc2..8bf038b254 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/server.rpt index f8a2ed3549..9e7da49eb1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe.deferred/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/client.rpt index 47f831e755..b7ed47d095 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/server.rpt index 2f7e60007a..0f7a72004f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.after.subscribe/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/client.rpt index c2a4f7ec48..52b7e3fc13 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/server.rpt index 68d9488e9e..0cab072d74 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.unsubscribe.via.session.state/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/client.rpt index 45dd0d19f3..9b5b6ab25d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/server.rpt index 5a880179c4..5cfe6ebc8b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.10k/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/client.rpt index a9abc78bf6..20bf586fb9 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/server.rpt index 5e421d77c5..91f72b5847 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.abort/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/client.rpt index 2fc07513ff..7cd4564a1c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/server.rpt index 3f2a2bc32b..e36825fd78 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/session.will.message.normal.disconnect/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("WILL", "CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("one") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/client.rpt index 872fca805e..fa5fcad128 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/server.rpt index 9052346f06..8684d4ebd8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.get.retained.as.published/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/client.rpt index feb314aed0..d3cb773dad 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/server.rpt index 7b1d2cb205..c68076153b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.receive.response.topic.and.correlation.data/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/client.rpt index b65ba0d319..07966a4a56 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/server.rpt index 36eb537daf..c63886050f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message.user.properties.unaltered/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/client.rpt index d0b232f0e6..ba5b93f4b0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/server.rpt index c71a476fe2..9c12d48bef 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.one.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/client.rpt index cb77b476c5..9629dfad00 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/server.rpt index 160afffa8a..34cde1a34a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.publish.no.local/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/client.rpt index 5d57863666..660dd1aa16 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/client.rpt @@ -32,6 +32,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") @@ -92,6 +93,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/server.rpt index f7e3a2ac38..f84f09e815 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.publish.retained.no.replay/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-1") @@ -83,6 +84,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client-2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/client.rpt index 9c0502ce98..36f8450ae0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/client.rpt @@ -32,6 +32,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client1") @@ -92,6 +93,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/server.rpt index 4020f80cfc..0522027f36 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.qos0.replay.retained.no.packet.id/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client1") @@ -83,6 +84,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client2") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/client.rpt index 800eb6a018..3f076aa226 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/server.rpt index ce3e3fbb98..99ee47dbde 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard.mixed.qos/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/client.rpt index c7b6da24a5..0c5bbd5054 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/server.rpt index f29007652c..350767fbb7 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.overlapping.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/client.rpt index 0aa2419763..5c5c372e9a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/server.rpt index f61539f25a..1a80d66bfb 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos1/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/client.rpt index 2b3db0347b..a830e12546 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/server.rpt index 30597f6e5d..0eeeb3822e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos0.published.qos2/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/client.rpt index b595b01da0..cfff76f83c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/server.rpt index 9d2e1f587e..e7e3d2a4f0 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1.published.qos2/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/client.rpt index bffd7e51f4..6e5621aaba 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/server.rpt index 689832c23c..861591d455 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos1/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/client.rpt index 5948168442..bed245ef8a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/server.rpt index 84124b3024..b642684879 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.qos2/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/client.rpt index 787b2fb4a8..74783de2f3 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/server.rpt index 6f716cf77c..16f9fc5247 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/client.rpt index faea365a10..e3b98440ce 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/server.rpt index 7739bfae9d..1c5afa4ac8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/client.rpt index 46afb2d16c..428e0e90d7 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/server.rpt index 15205cf5ed..79da81bc0a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.mixture.qos/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/client.rpt index 7ef648bd5f..133c660a7e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/server.rpt index a0f6aa0b3e..fa7a6cd7ea 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.receive.messages.topic.alias.repeated/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/client.rpt index 403a6e7a25..809217c893 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/server.rpt index cd91e9b8aa..08ef9f074d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.publish.no.subscription/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/client.rpt index 5b9ad149cc..ab07cb36ca 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -128,6 +129,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/server.rpt index 651f17b6c6..c2696ed29a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos1.unacked.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -119,6 +120,7 @@ write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/client.rpt index f31fe43584..0c7c2a452f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -156,6 +157,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/server.rpt index 26780e4619..c2dfdc978c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.incomplete.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -144,6 +145,7 @@ write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/client.rpt index dcecdc7da5..6ef3b22416 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -147,6 +148,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/server.rpt index 8f812311d1..459e00ce40 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reconnect.replay.qos2.unreceived.message/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") @@ -135,6 +136,7 @@ write zilla:begin.ext ${mqtt:beginEx() .typeId(zilla:id("mqtt")) .session() .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/client.rpt index 502e0151bf..e47a3654a4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/server.rpt index bc9e682451..138f471517 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.shared.subscriptions.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/client.rpt index 707ad620fb..29430d97e2 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/server.rpt index 52b3a8ace6..b86f01d86b 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.subscription.ids.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/client.rpt index d9cee97b78..fb354c7e23 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/server.rpt index b5d041e6a6..6205da64eb 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.reject.wildcard.subscriptions.not.supported/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/client.rpt index 1aacd9180b..961ef27d9f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/server.rpt index ce5d89ac72..00b05f20ae 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1.v4/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/client.rpt index 78c5e58c4f..01cbdfc94d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/server.rpt index 21dafd084b..8baac6f51d 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos1/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/client.rpt index ac1479c5ca..836cf71425 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/server.rpt index e39b71bfb4..2f28166dad 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2.v4/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/client.rpt index f36bbedf63..ffb06fe6c8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/server.rpt index a96406d0c2..4ba086441c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.replay.retained.message.qos2/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/client.rpt index 5b18f30548..6e3c78f3e4 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/server.rpt index 93abfceef8..0aa8856841 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.retain.as.published/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/client.rpt index 6c12edcbba..4d953b91d2 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/server.rpt index c1d3e835c9..3886ba3aed 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.multi.level.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/client.rpt index c15989b169..decf5ee1c2 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/server.rpt index b46a12553f..1e1057d1e9 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.and.multi.level.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/client.rpt index 03c0811b59..4214599d29 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/server.rpt index 4ac4e900e5..34b4c70d10 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.exact/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/client.rpt index ee7d7777ca..73ac84eb93 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/server.rpt index ed5194aaa6..68d247a758 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.single.level.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/client.rpt index 6f704f0c80..eeaa633ace 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/server.rpt index 7077b12957..f92597f50c 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filter.two.single.level.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/client.rpt index afd5bd3a8c..ed518a85be 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/server.rpt index c4e4b38be2..2850d6ecc1 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.both.exact/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/client.rpt index 50fc6e9339..b677b7f00a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/server.rpt index 7f0628afb0..e731bf786e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.aggregated.exact.and.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/client.rpt index 8c5f5a7a3a..45ef3e0578 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/server.rpt index a5462a8520..9675d5dc18 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.disjoint.wildcards/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/client.rpt index a0a9bba262..7e6ddea063 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/server.rpt index 464d8e3a18..7ee75f9a13 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.exact/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/client.rpt index 3e6743dbc4..aae004b662 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/server.rpt index 44a700fe23..a52356ad57 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.both.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/client.rpt index 05484623c7..d0b472e467 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/server.rpt index cf1f5a0200..614be7f343 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.isolated.exact.and.wildcard/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/client.rpt index 08f2000cc3..7e58dc401f 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/server.rpt index 83c2080681..808cb3da98 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.non.successful/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/client.rpt index bed9a5becb..63170717fe 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/server.rpt index 048aedf5e3..db34e6a92e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.topic.filters.overlapping.wildcards/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/client.rpt index b55f589b79..bbf36dd381 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/client.rpt @@ -30,6 +30,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/server.rpt index b5ba625e7e..594ca4c7cd 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/subscribe.unroutable/server.rpt @@ -32,6 +32,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/client.rpt index 7a56c44233..2cd515579e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/server.rpt index bbce97e4c3..297121d622 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.after.subscribe/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/client.rpt index ab43377785..9389c7c71a 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/server.rpt index 8417c7e658..6d37fdf026 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.aggregated.topic.filters.both.exact/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/client.rpt index 42b63bb4bb..a52d894bea 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/server.rpt index 07399f3a0e..7382c85116 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.publish.unfragmented/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/client.rpt index 6ba9da3bb0..5387b5f663 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/server.rpt index b94f10e6b6..9a7406276e 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filter.single/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/client.rpt index 1e0bc70078..a3492fa306 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/client.rpt @@ -31,6 +31,7 @@ read zilla:begin.ext ${mqtt:matchBeginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/server.rpt index 8623dc2504..dec8559eb6 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/application/unsubscribe.topic.filters.non.successful/server.rpt @@ -33,6 +33,7 @@ write zilla:begin.ext ${mqtt:beginEx() .session() .flags("CLEAN_START") .subscribeQosMax(2) + .publishQosMax(2) .packetSizeMax(66560) .capabilities("RETAIN", "WILDCARD", "SUBSCRIPTION_IDS", "SHARED_SUBSCRIPTIONS") .clientId("client") diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/client.rpt new file mode 100644 index 0000000000..aeac4f8774 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/client.rpt @@ -0,0 +1,33 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property clientId "gnybrelierkwcjyozqfhuitsibaetvbphfoewzaongylsrluxbcwjtgqkixfcdxvgyerkjifnzsflkbgumlzbgrqjgjnjkpxsfntbewlsjliookwmbwucllvvnuychrnyvktsxdwmggsljcljzomkxyiquzjsljtdgfbbnsntxghgbjjfedtruedlqkzmoxnapgmxqlafwzgrxuqscznhlvzdlxhkezkmthwobmppnzjecbbodtsdzvxwlkyfpvwq" + +connect "zilla://streams/net0" + option zilla:window 8192 + option zilla:transmission "duplex" + option zilla:byteorder "network" + +connected + +write [0x10 0x8d 0x02] # CONNECT + [0x00 0x04] "MQTT" # protocol name + [0x04] # protocol version + [0x02] # flags = clean start + [0x00 0x3c] # keep alive = 60s + [0x01 0x01] ${clientId} # client id + +read closed diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/server.rpt new file mode 100644 index 0000000000..6be455ea36 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/connect.reject.exceeding.max.client.id/server.rpt @@ -0,0 +1,34 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property clientId "gnybrelierkwcjyozqfhuitsibaetvbphfoewzaongylsrluxbcwjtgqkixfcdxvgyerkjifnzsflkbgumlzbgrqjgjnjkpxsfntbewlsjliookwmbwucllvvnuychrnyvktsxdwmggsljcljzomkxyiquzjsljtdgfbbnsntxghgbjjfedtruedlqkzmoxnapgmxqlafwzgrxuqscznhlvzdlxhkezkmthwobmppnzjecbbodtsdzvxwlkyfpvwq" + +accept "zilla://streams/net0" + option zilla:window 8192 + option zilla:transmission "duplex" + option zilla:byteorder "network" + +accepted +connected + +read [0x10 0x8d 0x02] # CONNECT + [0x00 0x04] "MQTT" # protocol name + [0x04] # protocol version + [0x02] # flags = clean start + [0x00 0x3c] # keep alive = 60s + [0x01 0x01] ${clientId} # client id + +write close diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/client.rpt index 51e3372827..c7d23e8793 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/client.rpt @@ -14,19 +14,23 @@ # under the License. # +property authorization 1L + connect "zilla://streams/net0" option zilla:window 8192 + option zilla:authorization ${authorization} option zilla:transmission "duplex" option zilla:byteorder "network" connected -write [0x10 0x21] # CONNECT +write [0x10 0x26] # CONNECT [0x00 0x04] "MQTT" # protocol name [0x05] # protocol version [0x42] # flags = password, clean start [0x00 0x3c] # keep alive = 60s - [0x00] # properties = none + [0x05] # properties + [0x27] 66560 # maximum packet size = 66560 [0x00 0x06] "client" # client id [0x00 0x0c] "Bearer TOKEN" # password diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/server.rpt index 746dbc8a1b..1988c16ad8 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.password.authentication.successful/server.rpt @@ -14,20 +14,24 @@ # under the License. # +property authorization 1L + accept "zilla://streams/net0" option zilla:window 8192 + option zilla:authorization ${authorization} option zilla:transmission "duplex" option zilla:byteorder "network" accepted connected -read [0x10 0x21] # CONNECT +read [0x10 0x26] # CONNECT [0x00 0x04] "MQTT" # protocol name [0x05] # protocol version [0x42] # flags = password, clean start [0x00 0x3c] # keep alive = 60s - [0x00] # properties = none + [0x05] # properties + [0x27] 66560 # maximum packet size = 66560 [0x00 0x06] "client" # client id [0x00 0x0c] "Bearer TOKEN" # password diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/client.rpt new file mode 100644 index 0000000000..6004595477 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/client.rpt @@ -0,0 +1,39 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property clientId "gnybrelierkwcjyozqfhuitsibaetvbphfoewzaongylsrluxbcwjtgqkixfcdxvgyerkjifnzsflkbgumlzbgrqjgjnjkpxsfntbewlsjliookwmbwucllvvnuychrnyvktsxdwmggsljcljzomkxyiquzjsljtdgfbbnsntxghgbjjfedtruedlqkzmoxnapgmxqlafwzgrxuqscznhlvzdlxhkezkmthwobmppnzjecbbodtsdzvxwlkyfpvwq" + +connect "zilla://streams/net0" + option zilla:window 8192 + option zilla:transmission "duplex" + option zilla:byteorder "network" + +connected + +write [0x10 0x8e 0x02] # CONNECT + [0x00 0x04] "MQTT" # protocol name + [0x05] # protocol version + [0x02] # flags = clean start + [0x00 0x3c] # keep alive = 60s + [0x00] # properties = none + [0x01 0x01] ${clientId} # client id + +read [0x20 0x03] # CONNACK + [0x00] # flags = none + [0x85] # reason = Client Identifier not valid + [0x00] # properties = none + +read closed diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/server.rpt new file mode 100644 index 0000000000..d5694e2552 --- /dev/null +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.reject.exceeding.max.client.id/server.rpt @@ -0,0 +1,40 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property clientId "gnybrelierkwcjyozqfhuitsibaetvbphfoewzaongylsrluxbcwjtgqkixfcdxvgyerkjifnzsflkbgumlzbgrqjgjnjkpxsfntbewlsjliookwmbwucllvvnuychrnyvktsxdwmggsljcljzomkxyiquzjsljtdgfbbnsntxghgbjjfedtruedlqkzmoxnapgmxqlafwzgrxuqscznhlvzdlxhkezkmthwobmppnzjecbbodtsdzvxwlkyfpvwq" + +accept "zilla://streams/net0" + option zilla:window 8192 + option zilla:transmission "duplex" + option zilla:byteorder "network" + +accepted +connected + +read [0x10 0x8e 0x02] # CONNECT + [0x00 0x04] "MQTT" # protocol name + [0x05] # protocol version + [0x02] # flags = clean start + [0x00 0x3c] # keep alive = 60s + [0x00] # properties = none + [0x01 0x01] ${clientId} # client id + +write [0x20 0x03] # CONNACK + [0x00] # flags = none + [0x85] # reason = Client Identifier not valid + [0x00] # properties = none + +write close diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/client.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/client.rpt index 3b77b38854..1db222a1fd 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/client.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/client.rpt @@ -14,19 +14,23 @@ # under the License. # +property authorization 1L + connect "zilla://streams/net0" option zilla:window 8192 + option zilla:authorization ${authorization} option zilla:transmission "duplex" option zilla:byteorder "network" connected -write [0x10 0x21] # CONNECT +write [0x10 0x26] # CONNECT [0x00 0x04] "MQTT" # protocol name [0x05] # protocol version [0x82] # flags = username, clean start [0x00 0x3c] # keep alive = 60s - [0x00] # properties = none + [0x05] # properties + [0x27] 66560 # maximum packet size = 66560 [0x00 0x06] "client" # client id [0x00 0x0c] "Bearer TOKEN" # username diff --git a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/server.rpt b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/server.rpt index 9fa7d53e34..260d102228 100644 --- a/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/server.rpt +++ b/specs/binding-mqtt.spec/src/main/scripts/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/connect.username.authentication.successful/server.rpt @@ -14,20 +14,24 @@ # under the License. # +property authorization 1L + accept "zilla://streams/net0" option zilla:window 8192 + option zilla:authorization ${authorization} option zilla:transmission "duplex" option zilla:byteorder "network" accepted connected -read [0x10 0x21] # CONNECT +read [0x10 0x26] # CONNECT [0x00 0x04] "MQTT" # protocol name [0x05] # protocol version [0x82] # flags = username, clean start [0x00 0x3c] # keep alive = 60s - [0x00] # properties = none + [0x05] # properties + [0x27] 66560 # maximum packet size = 66560 [0x00 0x06] "client" # client id [0x00 0x0c] "Bearer TOKEN" # username diff --git a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/config/SchemaTest.java b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/config/SchemaTest.java index f68915be88..f7a5c71950 100644 --- a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/config/SchemaTest.java +++ b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/config/SchemaTest.java @@ -37,7 +37,6 @@ public class SchemaTest .schemaPatch("io/aklivity/zilla/specs/engine/schema/model/test.schema.patch.json") .configurationRoot("io/aklivity/zilla/specs/binding/mqtt/config"); - @Ignore("TODO") @Test public void shouldValidateClient() { @@ -46,6 +45,22 @@ public void shouldValidateClient() assertThat(config, not(nullValue())); } + @Test + public void shouldValidateClientWithUsernameAuthorization() + { + JsonObject config = schema.validate("client.credentials.username.yaml"); + + assertThat(config, not(nullValue())); + } + + @Test + public void shouldValidateClientWithPasswordAuthorization() + { + JsonObject config = schema.validate("client.credentials.password.yaml"); + + assertThat(config, not(nullValue())); + } + @Ignore("TODO") @Test public void shouldValidateClientWhenTopic() diff --git a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/ConnectionIT.java b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/ConnectionIT.java index 1c7744fbdb..ec484b0058 100644 --- a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/ConnectionIT.java +++ b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v4/ConnectionIT.java @@ -108,6 +108,15 @@ public void shouldRejectMissingClientId() throws Exception k3po.finish(); } + @Test + @Specification({ + "${net}/connect.reject.exceeding.max.client.id/client", + "${net}/connect.reject.exceeding.max.client.id/server"}) + public void shouldRejectExceedingClientIdMax() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${net}/connect.reject.no.client.id.no.clean.session/client", diff --git a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/ConnectionIT.java b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/ConnectionIT.java index 7f74cfcbcd..9e01f02441 100644 --- a/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/ConnectionIT.java +++ b/specs/binding-mqtt.spec/src/test/java/io/aklivity/zilla/specs/binding/mqtt/streams/network/v5/ConnectionIT.java @@ -100,6 +100,15 @@ public void shouldRejectMissingClientId() throws Exception k3po.finish(); } + @Test + @Specification({ + "${net}/connect.reject.exceeding.max.client.id/client", + "${net}/connect.reject.exceeding.max.client.id/server"}) + public void shouldRejectExceedingClientIdMax() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${net}/disconnect/client", diff --git a/specs/binding-openapi-asyncapi.spec/pom.xml b/specs/binding-openapi-asyncapi.spec/pom.xml index 365cc8b344..0c46ca21d8 100644 --- a/specs/binding-openapi-asyncapi.spec/pom.xml +++ b/specs/binding-openapi-asyncapi.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/config/proxy-async.yaml b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/config/proxy-async.yaml new file mode 100644 index 0000000000..aa9c76928c --- /dev/null +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/config/proxy-async.yaml @@ -0,0 +1,275 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: test + options: + subject: petstore + schema: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT + servers: + - url: http://localhost:8080 + paths: + /customer: + post: + tags: + - customer + summary: Create unverified customer + description: Create a new customer and start a verification process + operationId: createCustomer + parameters: + - in: header + name: Prefer + required: true + schema: + type: string + enum: + - respond-async + requestBody: + description: Created customer object + content: + application/json: + schema: + $ref: "#/components/schemas/Customer" + responses: + "202": + description: successful operation + headers: + Location: + schema: + type: string + format: /customer;cid={correlationId} + description: Customer verification result location URL + security: + - petstore_auth: + - write:all + /customer;cid={correlationId}: + get: + tags: + - customer + summary: Verify customer details + description: Fetch and wait the verification status change + operationId: getVerifiedCustomer + parameters: + - name: correlationId + in: path + description: Correlation ID of the verification request + required: true + schema: + type: string + format: uuid + - in: header + name: Prefer + schema: + type: string + pattern: '^wait=\d+$' + responses: + default: + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/Customer" + "202": + description: successful operation + headers: + Location: + schema: + type: string + format: /customer;cid={correlationId} + description: Customer verification result location URL + security: + - petstore_auth: + - read:all + components: + schemas: + Customer: + type: object + properties: + id: + type: integer + format: int64 + example: 100000 + username: + type: string + example: fehguy + status: + type: string + description: Verification Status + example: approved + enum: + - pending + - approved + - denied + address: + type: array + items: + $ref: "#/components/schemas/Address" + Address: + type: object + properties: + street: + type: string + example: 437 Lytton + city: + type: string + example: Palo Alto + state: + type: string + example: CA + zip: + type: string + example: "94301" + catalog1: + type: test + options: + subject: petstore + schema: | + asyncapi: 3.0.0 + info: + title: Petstore Kafka API + version: 1.0.0 + defaultContentType: application/json + servers: + host-connections: + host: 'localhost:9092' + protocol: kafka-secure + description: Test broker + tags: + - 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. + channels: + customers: + address: "petstore-customers" + messages: + customer: + $ref: "#/components/messages/customer" + empty: + $ref: "#/components/messages/empty" + description: The topic on which pet values may be produced and consumed. + verifiedCustomers: + address: "petstore-verified-customers" + messages: + customer: + $ref: "#/components/messages/customer" + empty: + $ref: "#/components/messages/empty" + description: The topic on which pet values may be produced and consumed. + operations: + createCustomer: + action: send + channel: + $ref: "#/channels/customers" + reply: + channel: + $ref: "#/channels/verifiedCustomers" + summary: >- + Add a pet. + messages: + - $ref: "#/channels/customers/messages/customer" + components: + correlationIds: + customerVerifyCorrelationId: + description: > + This correlation ID is used for message tracing and messages + correlation. This correlation ID is generated at runtime based on the + `VERIFY_ID` and sent to the RESPONSE message. + location: $message.header#/VERIFY_ID + messages: + empty: + name: EmptyMessage + payload: + type: "null" + customer: + name: Customer + title: Customer + summary: Information about a Customer. + contentType: application/json + payload: + $ref: "#/components/schemas/Customer" + schemas: + Customer: + type: object + properties: + id: + type: integer + format: int64 + example: 100000 + username: + type: string + example: fehguy + status: + type: string + description: Verification Status + example: approved + enum: + - pending + - approved + - denied + address: + type: array + items: + $ref: "#/components/schemas/Address" + Address: + type: object + properties: + street: + type: string + example: 437 Lytton + city: + type: string + example: Palo Alto + state: + type: string + example: CA + zip: + type: string + example: "94301" + + +bindings: + composite0: + type: openapi-asyncapi + kind: proxy + options: + specs: + openapi: + openapi-id: + catalog: + catalog0: + subject: petstore + version: latest + asyncapi: + asyncapi-id: + catalog: + catalog1: + subject: petstore + version: latest + routes: + - when: + - api-id: openapi-id + exit: asyncapi_client0 + with: + api-id: asyncapi-id diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/schema/openapi.asyncapi.schema.patch.json b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/schema/openapi.asyncapi.schema.patch.json index 77ce779ee8..094be48fe8 100644 --- a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/schema/openapi.asyncapi.schema.patch.json +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/schema/openapi.asyncapi.schema.patch.json @@ -85,8 +85,7 @@ }, "additionalProperties": false } - }, - "maxProperties": 1 + } }, "asyncapi": { @@ -131,8 +130,7 @@ }, "additionalProperties": false } - }, - "maxProperties": 1 + } } }, "required": [ "openapi", "asyncapi" ] diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/client.rpt b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/client.rpt new file mode 100644 index 0000000000..88ae700d41 --- /dev/null +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/client.rpt @@ -0,0 +1,134 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +property deltaMillis 0L +property newTimestamp ${kafka:timestamp() + deltaMillis} + +connect "zilla://streams/asyncapi_client0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${asyncapi:beginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("petstore-customers") + .partition(-1, -2) + .ackMode("IN_SYNC_REPLICAS") + .build() + .build()) + .build()} + +connected + +write option zilla:flags "init" +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .timestamp(newTimestamp) + .partition(-1, -1) + .build() + .build()} +write zilla:data.empty +write flush + +write option zilla:flags "none" +write "{ \"id\": 100000, \"username\": \"fehguy\", \"status\": \"approved\", \"address\": [ { \"street\": \"437 Lytton\", \"city\": \"Palo Alto\", \"state\": \"CA\", \"zip\": \"94301\" } ] }" +write flush + +write notify SEND_ASYNC_REQUEST + +write option zilla:flags "fin" +write zilla:data.empty +write flush + +write close +read closed + +write notify SENT_ASYNC_REQUEST + +connect await SENT_ASYNC_REQUEST + "zilla://streams/asyncapi_client0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${asyncapi:beginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("petstore-verified-customers") + .partition(-1, -2) + .filter() + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build() + .build()) + .build()} + +connected + +read advised zilla:flush + +read notify RECEIVED_ASYNC_FLUSH + +read closed +write close + +connect await RECEIVED_ASYNC_FLUSH + "zilla://streams/asyncapi_client0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${asyncapi:beginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("petstore-verified-customers") + .partition(-1, -2) + .filter() + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build() + .build()) + .build()} + +connected + +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .fetch() + .partition(0, 1, 2) + .progress(0, 2) + .progress(1, 1) + .key("92d0bf92-63e0-4cfc-ae73-71dee92d1544") + .header(":status", "204") + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build()} +read zilla:data.null + +read closed +write close diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/server.rpt b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/server.rpt new file mode 100644 index 0000000000..efc416e507 --- /dev/null +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/asyncapi/async.verify.customer/server.rpt @@ -0,0 +1,121 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/asyncapi_client0" + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${asyncapi:matchBeginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("PRODUCE_ONLY") + .topic("petstore-customers") + .partition(-1, -2) + .ackMode("IN_SYNC_REPLICAS") + .build() + .build()) + .build()} + +connected + +read option zilla:flags "init" +read zilla:data.ext ${kafka:matchDataEx() + .typeId(zilla:id("kafka")) + .merged() + .produce() + .partition(-1, -1) + .build() + .build()} +read zilla:data.empty + +read option zilla:flags "none" +read "{ \"id\": 100000, \"username\": \"fehguy\", \"status\": \"approved\", \"address\": [ { \"street\": \"437 Lytton\", \"city\": \"Palo Alto\", \"state\": \"CA\", \"zip\": \"94301\" } ] }" + +read await SEND_ASYNC_REQUEST + +read option zilla:flags "fin" +read zilla:data.empty + +read closed +write close + +accepted + +read zilla:begin.ext ${asyncapi:matchBeginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("petstore-verified-customers") + .partition(-1, -2) + .filter() + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build() + .build()) + .build()} + +connected + +write advise zilla:flush + +write notify SEND_ASYNC_REQUEST + +write close +read closed + +accepted + +read zilla:begin.ext ${asyncapi:matchBeginEx() + .typeId(zilla:id("asyncapi")) + .apiId(0) + .extension(kafka:beginEx() + .typeId(zilla:id("kafka")) + .merged() + .capabilities("FETCH_ONLY") + .topic("petstore-verified-customers") + .partition(-1, -2) + .filter() + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build() + .build()) + .build()} + +connected + +write zilla:data.ext ${kafka:dataEx() + .typeId(zilla:id("kafka")) + .merged() + .fetch() + .partition(0, 1, 2) + .progress(0, 2) + .progress(1, 1) + .key("92d0bf92-63e0-4cfc-ae73-71dee92d1544") + .header(":status", "204") + .header("zilla:correlation-id", "3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build() + .build()} +write flush + +write close +read closed diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/client.rpt b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/client.rpt new file mode 100644 index 0000000000..323f27ab0a --- /dev/null +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/client.rpt @@ -0,0 +1,90 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/composite0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("createCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/customer") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "155") + .header("prefer", "respond-async") + .header("idempotency-key", "3f96592e-c8f1-4167-8c46-85f2aabb70a5") + .build()) + .build()} +connected + +write "{ \"id\": 100000, \"username\": \"fehguy\", \"status\": \"approved\", \"address\": [ { \"street\": \"437 Lytton\", \"city\": \"Palo Alto\", \"state\": \"CA\", \"zip\": \"94301\" } ] }" +write close + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("createCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "202") + .header("content-length", "0") + .header("Location", "/customer;cid=3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build()) + .build()} + +read closed + +read notify RECEIVED_ASYNC_RESPONSE + +connect await RECEIVED_ASYNC_RESPONSE + "zilla://streams/composite0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("getVerifiedCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "GET") + .header(":scheme", "http") + .header(":authority", "localhost:8080") + .header(":path", "/customer;cid=3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .header("prefer", "respond-async") + .build()) + .build()} +connected + +write close + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("getVerifiedCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "204") + .build()) + .build()} + +read closed diff --git a/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/server.rpt b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/server.rpt new file mode 100644 index 0000000000..18993155b1 --- /dev/null +++ b/specs/binding-openapi-asyncapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/openapi/async.verify.customer/server.rpt @@ -0,0 +1,87 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +accept "zilla://streams/composite0" + option zilla:window 8192 + option zilla:transmission "half-duplex" +accepted + +read zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("createCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/customer") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "155") + .header("prefer", "respond-async") + .header("idempotency-key", "3f96592e-c8f1-4167-8c46-85f2aabb70a5") + .build()) + .build()} +connected + +read "{ \"id\": 100000, \"username\": \"fehguy\", \"status\": \"approved\", \"address\": [ { \"street\": \"437 Lytton\", \"city\": \"Palo Alto\", \"state\": \"CA\", \"zip\": \"94301\" } ] }" +read closed + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("createCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "202") + .header("content-length", "0") + .header("Location", "/customer;cid=3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .build()) + .build()} +write flush + +write close + +accepted + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("getVerifiedCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "GET") + .header(":scheme", "http") + .header(":authority", "localhost:8080") + .header(":path", "/customer;cid=3f96592e-c8f1-4167-8c46-85f2aabb70a5-966ecfabf0fe9086ce63f615b87a6bed") + .header("prefer", "respond-async") + .build()) + .build()} +connected + +read closed + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .apiId(0) + .operationId("getVerifiedCustomer") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "204") + .build()) + .build()} + +write flush +write close diff --git a/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/AsyncapiIT.java b/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/AsyncapiIT.java index a4c5f29642..d24c884e9c 100644 --- a/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/AsyncapiIT.java +++ b/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/AsyncapiIT.java @@ -45,4 +45,14 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Specification({ + "${asyncapi}/async.verify.customer/client", + "${asyncapi}/async.verify.customer/server" + }) + public void shouldVerifyCustomerAsync() throws Exception + { + k3po.finish(); + } + } diff --git a/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/OpenapiIT.java b/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/OpenapiIT.java index a655b0dcfa..44743959bc 100644 --- a/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/OpenapiIT.java +++ b/specs/binding-openapi-asyncapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/asyncapi/streams/OpenapiIT.java @@ -45,4 +45,14 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Specification({ + "${openapi}/async.verify.customer/client", + "${openapi}/async.verify.customer/server" + }) + public void shouldVerifyCustomerAsync() throws Exception + { + k3po.finish(); + } + } diff --git a/specs/binding-openapi.spec/pom.xml b/specs/binding-openapi.spec/pom.xml index 194a1912d2..1379c6b92d 100644 --- a/specs/binding-openapi.spec/pom.xml +++ b/specs/binding-openapi.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/client.multiple.specs.yaml b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/client.multiple.specs.yaml new file mode 100644 index 0000000000..2ad78e07d9 --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/client.multiple.specs.yaml @@ -0,0 +1,281 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +catalogs: + catalog0: + type: test + options: + subject: petstore + schema: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT + servers: + - url: http://localhost:8080 + paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + maximum: 100 + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{id}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: id + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + maxItems: 100 + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string + catalog1: + type: test + options: + id: 1 + subject: itemstore + schema: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Itemstore + servers: + - url: http://localhost:8081 + paths: + /items: + get: + summary: List all items + operationId: listItems + tags: + - items + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + maximum: 100 + format: int32 + responses: + '200': + description: A paged array of items + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Items" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create an item + operationId: createItems + tags: + - items + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + required: true + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /items/{id}: + get: + summary: Info for a specific item + operationId: showItemById + tags: + - items + parameters: + - name: id + in: path + required: true + description: The id of the item to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Item" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + components: + schemas: + Item: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + Items: + type: array + maxItems: 100 + items: + $ref: "#/components/schemas/Item" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string +bindings: + openapi0: + type: openapi + kind: client + options: + specs: + petstore: + catalog: + catalog0: + subject: petstore + version: latest + itemstore: + catalog: + catalog1: + subject: itemstore + version: latest + diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/server.multiple.specs.yaml b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/server.multiple.specs.yaml new file mode 100644 index 0000000000..a8757e3751 --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/config/server.multiple.specs.yaml @@ -0,0 +1,283 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +catalogs: + catalog0: + type: test + options: + id: 0 + subject: petstore + schema: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT + servers: + - url: http://localhost:8080 + paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + maximum: 100 + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{id}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: id + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + maxItems: 100 + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string + + catalog1: + type: test + options: + id: 1 + subject: itemstore + schema: | + openapi: "3.0.0" + info: + version: 1.0.0 + title: Swagger Itemstore + servers: + - url: http://localhost:8081 + paths: + /items: + get: + summary: List all items + operationId: listItems + tags: + - items + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + maximum: 100 + format: int32 + responses: + '200': + description: A paged array of items + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Items" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create an item + operationId: createItems + tags: + - items + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Item' + required: true + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /items/{id}: + get: + summary: Info for a specific item + operationId: showItemById + tags: + - items + parameters: + - name: id + in: path + required: true + description: The id of the item to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Item" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + components: + schemas: + Item: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + Items: + type: array + maxItems: 100 + items: + $ref: "#/components/schemas/Item" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string +bindings: + composite0: + type: openapi + kind: server + options: + specs: + petstore: + catalog: + catalog0: + subject: petstore + version: latest + itemstore: + catalog: + catalog1: + subject: itemstore + version: latest + exit: openapi0 diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/schema/openapi.schema.patch.json b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/schema/openapi.schema.patch.json index 9e8cbda3b0..04edd0d5aa 100644 --- a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/schema/openapi.schema.patch.json +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/schema/openapi.schema.patch.json @@ -118,8 +118,7 @@ }, "additionalProperties": false } - }, - "maxProperties": 1 + } } }, "additionalProperties": false diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/client.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/client.rpt new file mode 100644 index 0000000000..3b41f7f114 --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/client.rpt @@ -0,0 +1,72 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/composite0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + option zilla:ephemeral "test:composite0/petstore" + +write zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/pets") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "39") + .build()} +connected + +write "{\"id\": 1, \"name\": \"rocky \"tag\": \"test\"}" +write close + +read zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()} + +read "{\"code\": 0,\"message\": \"string\"}" + + +connect "zilla://streams/composite0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + option zilla:ephemeral "test:composite0/itemstore" + +write zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/items") + .header(":authority", "localhost:8081") + .header("content-type", "application/json") + .header("content-length", "26") + .build()} +connected + +write "{\"id\": 1, \"name\": \"table\"}" +write close + +read zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()} + +read "{\"code\": 0,\"message\": \"string\"}" diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/server.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/server.rpt new file mode 100644 index 0000000000..5b3233cdcf --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.and.item/server.rpt @@ -0,0 +1,74 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +property serverAddress "zilla://streams/composite0" + +accept ${serverAddress} + option zilla:window 8192 + option zilla:transmission "half-duplex" +accepted + +read zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/pets") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "39") + .build()} + +connected + +read "{\"id\": 1, \"name\": \"rocky \"tag\": \"test\"}" +read closed + +write zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()} + +write "{\"code\": 0,\"message\": \"string\"}" +write flush + + +accepted + +read zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/items") + .header(":authority", "localhost:8081") + .header("content-type", "application/json") + .header("content-length", "26") + .build()} +connected + +read "{\"id\": 1, \"name\": \"table\"}" +read closed + +write zilla:begin.ext ${http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()} + +write "{\"code\": 0,\"message\": \"string\"}" +write flush diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.prod/client.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.prod/client.rpt index f997b09032..5d307a3bee 100644 --- a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.prod/client.rpt +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet.prod/client.rpt @@ -17,7 +17,7 @@ connect "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:ephemeral "test:composite0/http" + option zilla:ephemeral "test:composite0/petstore" write zilla:begin.ext ${http:beginEx() .typeId(zilla:id("http")) diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet/client.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet/client.rpt index 8e97310066..6ea9193f3a 100644 --- a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet/client.rpt +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/http/create.pet/client.rpt @@ -17,7 +17,7 @@ connect "zilla://streams/composite0" option zilla:window 8192 option zilla:transmission "half-duplex" - option zilla:ephemeral "test:composite0/http" + option zilla:ephemeral "test:composite0/petstore" write zilla:begin.ext ${http:beginEx() .typeId(zilla:id("http")) diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/client.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/client.rpt new file mode 100644 index 0000000000..975fd3a37f --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/client.rpt @@ -0,0 +1,86 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +connect "zilla://streams/openapi0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .operationId("createPets") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/pets") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "39") + .build()) + .build()} +connected + +write "{\"id\": 1, \"name\": \"rocky \"tag\": \"test\"}" +write close + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .operationId("createPets") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()) + .build()} + +read "{\"code\": 0,\"message\": \"string\"}" + + +connect "zilla://streams/openapi0" + option zilla:window 8192 + option zilla:transmission "half-duplex" + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .operationId("createItems") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/items") + .header(":authority", "localhost:8081") + .header("content-type", "application/json") + .header("content-length", "26") + .build()) + .build()} +connected + +write "{\"id\": 1, \"name\": \"table\"}" +write close + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .operationId("createItems") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()) + .build()} + +read "{\"code\": 0,\"message\": \"string\"}" diff --git a/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/server.rpt b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/server.rpt new file mode 100644 index 0000000000..b319e7b439 --- /dev/null +++ b/specs/binding-openapi.spec/src/main/scripts/io/aklivity/zilla/specs/binding/openapi/streams/openapi/create.pet.and.item/server.rpt @@ -0,0 +1,91 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +accept "zilla://streams/openapi0" + option zilla:window 8192 + option zilla:transmission "half-duplex" +accepted + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .operationId("createPets") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/pets") + .header(":authority", "localhost:8080") + .header("content-type", "application/json") + .header("content-length", "39") + .build()) + .build()} + +connected + +read "{\"id\": 1, \"name\": \"rocky \"tag\": \"test\"}" +read closed + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .operationId("createPets") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()) + .build()} +write flush + +write "{\"code\": 0,\"message\": \"string\"}" +write flush + + +accepted + +read zilla:begin.ext ${openapi:matchBeginEx() + .typeId(zilla:id("openapi")) + .operationId("createItems") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":method", "POST") + .header(":scheme", "http") + .header(":path", "/items") + .header(":authority", "localhost:8081") + .header("content-type", "application/json") + .header("content-length", "26") + .build()) + .build()} + +connected + +read "{\"id\": 1, \"name\": \"table\"}" +read closed + +write zilla:begin.ext ${openapi:beginEx() + .typeId(zilla:id("openapi")) + .operationId("createItems") + .extension(http:beginEx() + .typeId(zilla:id("http")) + .header(":status", "200") + .header("content-type", "application/json") + .header("content-length", "34") + .build()) + .build()} +write flush + +write "{\"code\": 0,\"message\": \"string\"}" +write flush diff --git a/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/HttpIT.java b/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/HttpIT.java index 2595d2c2ca..d1168fd2fd 100644 --- a/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/HttpIT.java +++ b/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/HttpIT.java @@ -46,6 +46,16 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Specification({ + "${http}/create.pet.and.item/client", + "${http}/create.pet.and.item/server" + }) + public void shouldCreatePetAndItem() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${http}/reject.non.composite.origin/client", diff --git a/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/OpenapiIT.java b/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/OpenapiIT.java index 66b019bc53..bc90e1c7b6 100644 --- a/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/OpenapiIT.java +++ b/specs/binding-openapi.spec/src/test/java/io/aklivity/zilla/specs/binding/openapi/streams/OpenapiIT.java @@ -46,4 +46,13 @@ public void shouldCreatePet() throws Exception k3po.finish(); } + @Test + @Specification({ + "${openapi}/create.pet.and.item/client", + "${openapi}/create.pet.and.item/server" + }) + public void shouldCreatePetAndItem() throws Exception + { + k3po.finish(); + } } diff --git a/specs/binding-proxy.spec/pom.xml b/specs/binding-proxy.spec/pom.xml index 2ffaf85ef3..3f90791a5c 100644 --- a/specs/binding-proxy.spec/pom.xml +++ b/specs/binding-proxy.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-sse-kafka.spec/pom.xml b/specs/binding-sse-kafka.spec/pom.xml index a240c25d38..219f49985d 100644 --- a/specs/binding-sse-kafka.spec/pom.xml +++ b/specs/binding-sse-kafka.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-sse.spec/pom.xml b/specs/binding-sse.spec/pom.xml index f44e0c38cd..6ab6465859 100644 --- a/specs/binding-sse.spec/pom.xml +++ b/specs/binding-sse.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-tcp.spec/pom.xml b/specs/binding-tcp.spec/pom.xml index f653f1f395..7e71875e75 100644 --- a/specs/binding-tcp.spec/pom.xml +++ b/specs/binding-tcp.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-tls.spec/pom.xml b/specs/binding-tls.spec/pom.xml index d872fb25cf..539cc200a2 100644 --- a/specs/binding-tls.spec/pom.xml +++ b/specs/binding-tls.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/schema/tls.schema.patch.json b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/schema/tls.schema.patch.json index eb039e3ffa..97e4315d55 100644 --- a/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/schema/tls.schema.patch.json +++ b/specs/binding-tls.spec/src/main/scripts/io/aklivity/zilla/specs/binding/tls/schema/tls.schema.patch.json @@ -31,10 +31,6 @@ { "enum": [ "client", "server", "proxy" ] }, - "options": - { - "$ref": "#/$defs/options/binding/tls" - }, "routes": { "items": @@ -110,6 +106,45 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": + { + "$ref": "#/$defs/options/binding/tls" + } + } + }, + { + "properties": + { + "kind": + { + "const": "server" + }, + "options": + { + "$ref": "#/$defs/options/binding/tls" + } + } + }, + { + "properties": + { + "kind": + { + "const": "proxy" + }, + "options": false + } + } ] } } diff --git a/specs/binding-ws.spec/pom.xml b/specs/binding-ws.spec/pom.xml index 6b4f7a34f7..7126ac81c1 100644 --- a/specs/binding-ws.spec/pom.xml +++ b/specs/binding-ws.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/binding-ws.spec/src/main/scripts/io/aklivity/zilla/specs/binding/ws/schema/ws.schema.patch.json b/specs/binding-ws.spec/src/main/scripts/io/aklivity/zilla/specs/binding/ws/schema/ws.schema.patch.json index 2b275e1775..df9e2e51b9 100644 --- a/specs/binding-ws.spec/src/main/scripts/io/aklivity/zilla/specs/binding/ws/schema/ws.schema.patch.json +++ b/specs/binding-ws.spec/src/main/scripts/io/aklivity/zilla/specs/binding/ws/schema/ws.schema.patch.json @@ -32,42 +32,6 @@ "enum": [ "client", "server" ] }, "vault": false, - "options": - { - "properties": - { - "defaults": - { - "title": "Defaults", - "type": "object", - "additoinalProperties": "false", - "properties": - { - "protocol": - { - "title": "Subprotocol", - "type": "string" - }, - "scheme": - { - "title": "Scheme", - "type": "string" - }, - "authority": - { - "title": "Authority", - "type": "string" - }, - "path": - { - "title": "Path", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, "routes": { "items": @@ -101,7 +65,7 @@ "type": "string" } }, - "additoinalProperties": "false" + "additionalProperties": false } }, "with": false @@ -123,6 +87,64 @@ "routes" ] } + ], + "oneOf": + [ + { + "properties": + { + "kind": + { + "const": "client" + }, + "options": + { + "properties": + { + "defaults": + { + "title": "Defaults", + "type": "object", + "additionalProperties": false, + "properties": + { + "protocol": + { + "title": "Subprotocol", + "type": "string" + }, + "scheme": + { + "title": "Scheme", + "type": "string" + }, + "authority": + { + "title": "Authority", + "type": "string" + }, + "path": + { + "title": "Path", + "type": "string" + } + } + } + }, + "additionalProperties": false + } + } + }, + { + "properties": + { + "kind": + { + "const": "server" + }, + "options": false + } + } ] } } diff --git a/specs/catalog-apicurio.spec/pom.xml b/specs/catalog-apicurio.spec/pom.xml index b20a71c459..329bf32e03 100644 --- a/specs/catalog-apicurio.spec/pom.xml +++ b/specs/catalog-apicurio.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/catalog-apicurio.spec/src/main/resources/META-INF/zilla/apicurio.idl b/specs/catalog-apicurio.spec/src/main/resources/META-INF/zilla/apicurio.idl index 5430d506c7..2e19e88727 100644 --- a/specs/catalog-apicurio.spec/src/main/resources/META-INF/zilla/apicurio.idl +++ b/specs/catalog-apicurio.spec/src/main/resources/META-INF/zilla/apicurio.idl @@ -18,19 +18,49 @@ scope apicurio { enum ApicurioEventType (uint8) { - REMOTE_ACCESS_REJECTED (1) + UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION (1), + UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT (2), + UNRETRIEVABLE_ARTIFACT_ID (3), + RETRIEVED_ARTIFACT_SUBJECT_VERSION (4), + RETRIEVED_ARTIFACT_ID (5) + } + + struct ApicurioUnretrievableArtifactSubjectVersionEx extends core::stream::Extension + { + string8 subject; + string8 version; + } + + struct ApicurioUnretrievableArtifactSubjectVersionStaleArtifactEx extends core::stream::Extension + { + string8 subject; + string8 version; + int32 artifactId; + } + + struct ApicurioUnretrievableArtifactIdEx extends core::stream::Extension + { + int32 artifactId; + } + + struct ApicurioRetrievableArtifactSubjectVersionEx extends core::stream::Extension + { + string8 subject; + string8 version; } - struct ApicurioRemoteAccessRejectedEx extends core::stream::Extension + struct ApicurioRetrievableArtifactIdEx extends core::stream::Extension { - string8 method; - string16 url; - int16 status; + int32 artifactId; } union ApicurioEventEx switch (ApicurioEventType) { - case REMOTE_ACCESS_REJECTED: ApicurioRemoteAccessRejectedEx remoteAccessRejected; + case UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION: ApicurioUnretrievableArtifactSubjectVersionEx unretrievableArtifactSubjectVersion; + case UNRETRIEVABLE_ARTIFACT_SUBJECT_VERSION_STALE_ARTIFACT: ApicurioUnretrievableArtifactSubjectVersionStaleArtifactEx unretrievableArtifactSubjectVersionStaleArtifact; + case UNRETRIEVABLE_ARTIFACT_ID: ApicurioUnretrievableArtifactIdEx unretrievableArtifactId; + case RETRIEVED_ARTIFACT_SUBJECT_VERSION: ApicurioRetrievableArtifactSubjectVersionEx retrievableArtifactSubjectVersion; + case RETRIEVED_ARTIFACT_ID: ApicurioRetrievableArtifactIdEx retrievableArtifactId; } } } diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/cache/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/cache/zilla.yaml new file mode 100644 index 0000000000..39836a8989 --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/cache/zilla.yaml @@ -0,0 +1,59 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 1 + assertions: + catalog: + catalog0: + - schema: |- + asyncapi: 3.0.0 + info: + title: Zilla MQTT Proxy + version: 1.0.0 + license: + name: Aklivity Community License + servers: + plain: + host: mqtt://localhost:7183 + protocol: mqtt + defaultContentType: application/json + - schema: |- + asyncapi: 3.0.0 + info: + title: Zilla MQTT Proxy + version: 1.0.0 + license: + name: Aklivity Community License + servers: + plain: + host: mqtt://localhost:7183 + protocol: mqtt + defaultContentType: application/json + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/retry/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/retry/zilla.yaml new file mode 100644 index 0000000000..b4983ae5ab --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/retry/zilla.yaml @@ -0,0 +1,60 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.catalog0 + id: catalog.apicurio.unretrievable.artifact.id + message: UNRETRIEVABLE_ARTIFACT_ID 1 + - qname: test.catalog0 + id: catalog.apicurio.retrievable.artifact.id + message: RETRIEVED_ARTIFACT_ID 1 +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 1 + assertions: + catalog: + catalog0: + - schema: null + - schema: |- + asyncapi: 3.0.0 + info: + title: Zilla MQTT Proxy + version: 1.0.0 + license: + name: Aklivity Community License + servers: + plain: + host: mqtt://localhost:7183 + protocol: mqtt + defaultContentType: application/json + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/zilla.yaml new file mode 100644 index 0000000000..7c0a067d68 --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/global/id/zilla.yaml @@ -0,0 +1,47 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 1 + assertions: + catalog: + catalog0: + - schema: |- + asyncapi: 3.0.0 + info: + title: Zilla MQTT Proxy + version: 1.0.0 + license: + name: Aklivity Community License + servers: + plain: + host: mqtt://localhost:7183 + protocol: mqtt + defaultContentType: application/json + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/cache/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/cache/zilla.yaml new file mode 100644 index 0000000000..8eaa7bf0cf --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/cache/zilla.yaml @@ -0,0 +1,38 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: artifactId + version: "0" + assertions: + catalog: + catalog0: + - id: 1 + - id: 1 + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/failed/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/failed/zilla.yaml new file mode 100644 index 0000000000..2c391e7ae5 --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/failed/zilla.yaml @@ -0,0 +1,47 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.catalog0 + id: catalog.apicurio.unretrievable.artifact.subject.version + message: UNRETRIEVABLE_ARTIFACT artifactId latest +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId + max-age: 0 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: artifactId + version: "latest" + assertions: + catalog: + catalog0: + - id: 0 + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/latest/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/latest/zilla.yaml new file mode 100644 index 0000000000..d0a7f61a2e --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/latest/zilla.yaml @@ -0,0 +1,37 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: artifactId + version: "latest" + assertions: + catalog: + catalog0: + - id: 1 + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/retry/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/retry/zilla.yaml new file mode 100644 index 0000000000..a47879431e --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/retry/zilla.yaml @@ -0,0 +1,57 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.catalog0 + id: catalog.apicurio.unretrievable.artifact.subject.version + message: UNRETRIEVABLE_ARTIFACT artifactId latest + - qname: test.catalog0 + id: catalog.apicurio.unretrievable.artifact.subject.version.stale.artifact + message: UNRETRIEVABLE_ARTIFACT artifactId latest, USING_STALE_ARTIFACT 1 + - qname: test.catalog0 + id: catalog.apicurio.retrievable.artifact.subject.version + message: RETRIEVED_ARTIFACT_SUBJECT_VERSION artifactId latest +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId + max-age: 0 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: artifactId + version: "latest" + assertions: + catalog: + catalog0: + - id: 1 + - id: 1 + delay: 1000 + - id: 2 + delay: 1000 + exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/zilla.yaml b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/zilla.yaml new file mode 100644 index 0000000000..4546290e64 --- /dev/null +++ b/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/resolve/artifact/id/subject/version/zilla.yaml @@ -0,0 +1,37 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: apicurio + options: + url: http://localhost:8080 + group-id: groupId +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: artifactId + version: "0" + assertions: + catalog: + catalog0: + - id: 1 + exit: app0 diff --git a/specs/catalog-inline.spec/pom.xml b/specs/catalog-inline.spec/pom.xml index cf526db5e8..6ad4f93327 100644 --- a/specs/catalog-inline.spec/pom.xml +++ b/specs/catalog-inline.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/catalog-karapace.spec/pom.xml b/specs/catalog-karapace.spec/pom.xml index 5447eca216..9796c14798 100644 --- a/specs/catalog-karapace.spec/pom.xml +++ b/specs/catalog-karapace.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/catalog-karapace.spec/src/main/resources/META-INF/zilla/karapace.idl b/specs/catalog-karapace.spec/src/main/resources/META-INF/zilla/karapace.idl index 9661123694..e277c81e52 100644 --- a/specs/catalog-karapace.spec/src/main/resources/META-INF/zilla/karapace.idl +++ b/specs/catalog-karapace.spec/src/main/resources/META-INF/zilla/karapace.idl @@ -18,19 +18,49 @@ scope karapace { enum KarapaceEventType (uint8) { - REMOTE_ACCESS_REJECTED (1) + UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION (1), + UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA (2), + UNRETRIEVABLE_SCHEMA_ID (3), + RETRIEVED_SCHEMA_SUBJECT_VERSION (4), + RETRIEVED_SCHEMA_ID (5) } - struct KarapaceRemoteAccessRejectedEx extends core::stream::Extension + struct KarapaceUnretrievableSchemaSubjectVersionEx extends core::stream::Extension { - string8 method; - string16 url; - int16 status; + string8 subject; + string8 version; + } + + struct KarapaceUnretrievableSchemaSubjectVersionStaleSchemaEx extends core::stream::Extension + { + string8 subject; + string8 version; + int32 schemaId; + } + + struct KarapaceUnretrievableSchemaIdEx extends core::stream::Extension + { + int32 schemaId; + } + + struct KarapaceRetrievableSchemaSubjectVersionEx extends core::stream::Extension + { + string8 subject; + string8 version; + } + + struct KarapaceRetrievableSchemaIdEx extends core::stream::Extension + { + int32 schemaId; } union KarapaceEventEx switch (KarapaceEventType) { - case REMOTE_ACCESS_REJECTED: KarapaceRemoteAccessRejectedEx remoteAccessRejected; + case UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION: KarapaceUnretrievableSchemaSubjectVersionEx unretrievableSchemaSubjectVersion; + case UNRETRIEVABLE_SCHEMA_SUBJECT_VERSION_STALE_SCHEMA: KarapaceUnretrievableSchemaSubjectVersionStaleSchemaEx unretrievableSchemaSubjectVersionStaleSchema; + case UNRETRIEVABLE_SCHEMA_ID: KarapaceUnretrievableSchemaIdEx unretrievableSchemaId; + case RETRIEVED_SCHEMA_SUBJECT_VERSION: KarapaceRetrievableSchemaSubjectVersionEx retrievableSchemaSubjectVersion; + case RETRIEVED_SCHEMA_ID: KarapaceRetrievableSchemaIdEx retrievableSchemaId; } } } diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/cache/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/cache/zilla.yaml new file mode 100644 index 0000000000..306be08370 --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/cache/zilla.yaml @@ -0,0 +1,36 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 9 + assertions: + catalog: + catalog0: + - schema: '{"fields":[{"name":"id","type":"string"},{"name":"status","type":"string"}],"name":"Event","namespace":"io.aklivity.example","type":"record"}' + - schema: '{"fields":[{"name":"id","type":"string"},{"name":"status","type":"string"}],"name":"Event","namespace":"io.aklivity.example","type":"record"}' + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/retry/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/retry/zilla.yaml new file mode 100644 index 0000000000..47edd6afed --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/retry/zilla.yaml @@ -0,0 +1,48 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.catalog0 + id: catalog.karapace.unretrievable.schema.id + message: UNRETRIEVABLE_SCHEMA_ID 9 + - qname: test.catalog0 + id: catalog.karapace.retrievable.schema.id + message: RETRIEVED_SCHEMA_ID 9 +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 9 + assertions: + catalog: + catalog0: + - schema: null + - schema: '{"fields":[{"name":"id","type":"string"},{"name":"status","type":"string"}],"name":"Event","namespace":"io.aklivity.example","type":"record"}' + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/zilla.yaml new file mode 100644 index 0000000000..72f3fa866b --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/schema/id/zilla.yaml @@ -0,0 +1,35 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - id: 9 + assertions: + catalog: + catalog0: + - schema: '{"fields":[{"name":"id","type":"string"},{"name":"status","type":"string"}],"name":"Event","namespace":"io.aklivity.example","type":"record"}' + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/cache/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/cache/zilla.yaml new file mode 100644 index 0000000000..8f0c5e8065 --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/cache/zilla.yaml @@ -0,0 +1,37 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 + max-age: 5000 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: items-snapshots-value + assertions: + catalog: + catalog0: + - id: 9 + - id: 9 + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/retry/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/retry/zilla.yaml new file mode 100644 index 0000000000..cfebc5d347 --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/retry/zilla.yaml @@ -0,0 +1,55 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +telemetry: + exporters: + exporter0: + type: test + options: + events: + - qname: test.catalog0 + id: catalog.karapace.unretrievable.schema.subject.version + message: UNRETRIEVABLE_SCHEMA items-snapshots-value latest + - qname: test.catalog0 + id: catalog.karapace.unretrievable.schema.subject.version.stale.schema + message: UNRETRIEVABLE_SCHEMA items-snapshots-value latest, USING_STALE_SCHEMA 9 + - qname: test.catalog0 + id: catalog.karapace.retrievable.schema.subject.version + message: RETRIEVED_SCHEMA_SUBJECT_VERSION items-snapshots-value latest +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 + max-age: 0 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: items-snapshots-value + assertions: + catalog: + catalog0: + - id: 9 + - id: 9 + delay: 1000 + - id: 10 + delay: 1000 + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/zilla.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/zilla.yaml new file mode 100644 index 0000000000..14fd05cdf6 --- /dev/null +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/resolve/subject/version/zilla.yaml @@ -0,0 +1,35 @@ +# +# Copyright 2021-2023 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +--- +name: test +catalogs: + catalog0: + type: karapace + options: + url: http://localhost:8081 +bindings: + net0: + type: test + kind: server + options: + catalog: + catalog0: + - subject: items-snapshots-value + assertions: + catalog: + catalog0: + - id: 9 + exit: app0 diff --git a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/event.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/id/zilla.yaml similarity index 78% rename from specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/event.yaml rename to specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/id/zilla.yaml index 751c71f89e..0cdf18ac5f 100644 --- a/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/event.yaml +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/id/zilla.yaml @@ -22,8 +22,8 @@ telemetry: options: events: - qname: test.catalog0 - id: catalog.karapace.remote.access.rejected - message: REMOTE_ACCESS_REJECTED GET http://localhost:8081/schemas/ids/0 0 + id: catalog.karapace.unretrievable.schema.id + message: UNRETRIEVABLE_SCHEMA_ID 1 catalogs: catalog0: type: karapace @@ -34,6 +34,11 @@ bindings: type: test kind: server options: - catalogs: - - catalog0 + catalog: + catalog0: + - id: 1 + assertions: + catalog: + catalog0: + - schema: null exit: app0 diff --git a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/event.yaml b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/subject/version/zilla.yaml similarity index 73% rename from specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/event.yaml rename to specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/subject/version/zilla.yaml index f15a8612b0..094974fe4b 100644 --- a/specs/catalog-apicurio.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/apicurio/config/event.yaml +++ b/specs/catalog-karapace.spec/src/main/scripts/io/aklivity/zilla/specs/catalog/karapace/config/unretrievable/schema/subject/version/zilla.yaml @@ -22,11 +22,11 @@ telemetry: options: events: - qname: test.catalog0 - id: catalog.apicurio.remote.access.rejected - message: REMOTE_ACCESS_REJECTED GET http://localhost:8081/apis/registry/v2/ids/globalIds/0 0 + id: catalog.karapace.unretrievable.schema.subject.version + message: UNRETRIEVABLE_SCHEMA items-snapshots-value latest catalogs: catalog0: - type: apicurio + type: karapace options: url: http://localhost:8081 bindings: @@ -34,6 +34,11 @@ bindings: type: test kind: server options: - catalogs: - - catalog0 + catalog: + catalog0: + - subject: items-snapshots-value + assertions: + catalog: + catalog0: + - id: 0 exit: app0 diff --git a/specs/engine.spec/pom.xml b/specs/engine.spec/pom.xml index 011b6983e4..1469c9b7ad 100644 --- a/specs/engine.spec/pom.xml +++ b/specs/engine.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.binding.with.entry.yaml b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.binding.with.entry.yaml new file mode 100644 index 0000000000..13b72bc631 --- /dev/null +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.binding.with.entry.yaml @@ -0,0 +1,54 @@ +# +# Copyright 2021-2023 Aklivity Inc. +# +# Aklivity licenses this file to you under the Apache License, +# version 2.0 (the "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at: +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +--- +name: test +vaults: + test0: + type: test +guards: + test0: + type: test + options: + credentials: TOKEN + lifetime: PT30S + challenge: PT5S + roles: + - read + - write +telemetry: + attributes: + service.namespace: example + metrics: + - test.counter + - test.gauge + - test.histogram + exporters: + test0: + type: test +bindings: + net0: + type: test + kind: server + entry: entry0 + routes: + - guarded: + test0: + - read + exit: app0 + telemetry: + metrics: + - test.* diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.yaml b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.yaml index 5eb6200998..546952bfd0 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.yaml +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/config/server.yaml @@ -43,10 +43,11 @@ bindings: net0: type: test kind: server - exit: app0 - guarded: - test0: - - read + routes: + - guarded: + test0: + - read + exit: app0 telemetry: metrics: - test.* diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json index e5166b771e..dfbd5c307e 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/binding/test.schema.patch.json @@ -41,6 +41,56 @@ { "$ref": "#/$defs/converter" }, + "catalog": + { + "type": "object", + "patternProperties": + { + "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$": + { + "type": "array", + "items": + { + "$ref": "#/$defs/cataloged" + } + } + }, + "maxProperties": 1 + }, + "assertions": + { + "catalog": + { + "type": "object", + "patternProperties": + { + "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$": + { + "type": "array", + "items": + { + "type": "object", + "properties": + { + "id": + { + "type": "integer" + }, + "schema": + { + "type": ["string", "null"] + }, + "delay": + { + "type": "number" + } + } + } + } + }, + "maxProperties": 1 + } + }, "port": { "title": "Port", @@ -71,14 +121,6 @@ } ] }, - "catalogs": - { - "type": "array", - "items": - { - "type": "string" - } - }, "authorization": { "type": "object", diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/engine.schema.json b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/engine.schema.json index 855e106f1d..5d70c02c74 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/engine.schema.json +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/schema/engine.schema.json @@ -421,8 +421,14 @@ "title": "Exit", "type": "string" }, - "additionalProperties": false + "entry": + { + "title": "Entry", + "type": "string", + "pattern": "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$" + } }, + "additionalProperties": false, "required": [ "type", @@ -436,12 +442,6 @@ "kind": { "const": "remote_server" - }, - "entry": - { - "title": "Exit", - "type": "string", - "pattern": "^[a-zA-Z]+[a-zA-Z0-9\\._\\-]*$" } }, "required": @@ -458,7 +458,8 @@ { "const": "remote_server" } - } + }, + "entry": false } } ], diff --git a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/handshake/server.rpt b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/handshake/server.rpt index 5867b43b1e..35959c2703 100644 --- a/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/handshake/server.rpt +++ b/specs/engine.spec/src/main/scripts/io/aklivity/zilla/specs/engine/streams/network/handshake/server.rpt @@ -14,7 +14,9 @@ # under the License. # -accept "zilla://streams/net0" +property serverAddress "zilla://streams/net0" + +accept ${serverAddress} option zilla:transmission "duplex" option zilla:window 8192 diff --git a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/config/SchemaTest.java b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/config/SchemaTest.java index c4da35cab3..9b3cc20e04 100644 --- a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/config/SchemaTest.java +++ b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/config/SchemaTest.java @@ -46,6 +46,12 @@ public void shouldValidateServerBinding() assertThat(config, not(nullValue())); } + @Test(expected = JsonException.class) + public void shouldValidateServerBindingWithEntry() + { + schema.validate("server.binding.with.entry.yaml"); + } + @Test public void shouldValidateServerBindingWithRoutesAndNoExit() { diff --git a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java index e079e617ce..65c49ae5a6 100644 --- a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java +++ b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/ApplicationIT.java @@ -128,14 +128,4 @@ public void shouldNotReconfigureWhen500Returned() throws Exception { k3po.finish(); } - - @Test - @Specification({ - "${app}/event/server", - "${app}/event/client", - }) - public void shouldConnect() throws Exception - { - k3po.finish(); - } } diff --git a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java index 4837938048..ff59b85799 100644 --- a/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java +++ b/specs/engine.spec/src/test/java/io/aklivity/zilla/specs/engine/streams/NetworkIT.java @@ -128,14 +128,4 @@ public void shouldNotReconfigureWhen500Returned() throws Exception { k3po.finish(); } - - @Test - @Specification({ - "${net}/event/server", - "${net}/event/client" - }) - public void shouldConnect() throws Exception - { - k3po.finish(); - } } diff --git a/specs/exporter-otlp.spec/pom.xml b/specs/exporter-otlp.spec/pom.xml index 3f5135a878..3bb88b2da7 100644 --- a/specs/exporter-otlp.spec/pom.xml +++ b/specs/exporter-otlp.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/client.rpt b/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/client.rpt index 96e3592ace..ac70d76711 100644 --- a/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/client.rpt +++ b/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/client.rpt @@ -13,12 +13,6 @@ # specific language governing permissions and limitations under the License. # -connect "zilla://streams/app0" - option zilla:window 8192 - -connected - - connect "http://localhost:4318/v1/logs" connected diff --git a/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/server.rpt b/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/server.rpt index 4d3ed65ed3..8f79319539 100644 --- a/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/server.rpt +++ b/specs/exporter-otlp.spec/src/main/scripts/io/aklivity/zilla/specs/exporter/otlp/application/event/server.rpt @@ -13,12 +13,6 @@ # specific language governing permissions and limitations under the License. # -accept "zilla://streams/app0" - option zilla:window 8192 -accepted -connected - - accept "http://localhost:4318/v1/logs" accepted connected diff --git a/specs/exporter-prometheus.spec/pom.xml b/specs/exporter-prometheus.spec/pom.xml index 0220427a7c..d0d5ffc891 100644 --- a/specs/exporter-prometheus.spec/pom.xml +++ b/specs/exporter-prometheus.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/exporter-stdout.spec/pom.xml b/specs/exporter-stdout.spec/pom.xml index 42c31bf9a5..d1a52dc19f 100644 --- a/specs/exporter-stdout.spec/pom.xml +++ b/specs/exporter-stdout.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/guard-jwt.spec/pom.xml b/specs/guard-jwt.spec/pom.xml index ba82420718..f6746738d5 100644 --- a/specs/guard-jwt.spec/pom.xml +++ b/specs/guard-jwt.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/metrics-grpc.spec/pom.xml b/specs/metrics-grpc.spec/pom.xml index add4bef29e..60f973ccae 100644 --- a/specs/metrics-grpc.spec/pom.xml +++ b/specs/metrics-grpc.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/metrics-http.spec/pom.xml b/specs/metrics-http.spec/pom.xml index ec94b5f491..3bd3134a7e 100644 --- a/specs/metrics-http.spec/pom.xml +++ b/specs/metrics-http.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/metrics-stream.spec/pom.xml b/specs/metrics-stream.spec/pom.xml index c1f3f50592..01d78be57c 100644 --- a/specs/metrics-stream.spec/pom.xml +++ b/specs/metrics-stream.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/model-avro.spec/pom.xml b/specs/model-avro.spec/pom.xml index 4c46b646d3..cefd931ed4 100644 --- a/specs/model-avro.spec/pom.xml +++ b/specs/model-avro.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/model-core.spec/pom.xml b/specs/model-core.spec/pom.xml index ab2710097c..6acef73f96 100644 --- a/specs/model-core.spec/pom.xml +++ b/specs/model-core.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/model-json.spec/pom.xml b/specs/model-json.spec/pom.xml index c2a992fbee..61aa7705c5 100644 --- a/specs/model-json.spec/pom.xml +++ b/specs/model-json.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/model-protobuf.spec/pom.xml b/specs/model-protobuf.spec/pom.xml index fa0c9dfc9b..b5b3662f88 100644 --- a/specs/model-protobuf.spec/pom.xml +++ b/specs/model-protobuf.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/pom.xml b/specs/pom.xml index 35224b78ee..591a8b6268 100644 --- a/specs/pom.xml +++ b/specs/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla zilla - 0.9.79 + 0.9.80 ../pom.xml diff --git a/specs/vault-filesystem.spec/pom.xml b/specs/vault-filesystem.spec/pom.xml index a370282fd3..ec22315bad 100644 --- a/specs/vault-filesystem.spec/pom.xml +++ b/specs/vault-filesystem.spec/pom.xml @@ -8,7 +8,7 @@ io.aklivity.zilla specs - 0.9.79 + 0.9.80 ../pom.xml