diff --git a/.github/workflows/run-tck.yml b/.github/workflows/run-tck.yml new file mode 100644 index 0000000..a44c4de --- /dev/null +++ b/.github/workflows/run-tck.yml @@ -0,0 +1,80 @@ +name: Build and Run TCK + +on: + push: + branches: +# - main + pull_request: + branches: +# - main + + +env: + # Tag of the TCK + TCK_VERSION: v0.2.3 + # Tells uv to not need a venv, and instead use system + UV_SYSTEM_PYTHON: 1 + + +# Only run the latest job +concurrency: + group: '${{ github.workflow }} @ ${{ github.head_ref || github.ref }}' + cancel-in-progress: true + +jobs: + build-and-test: + name: Run TCK + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v4 + - name: Checkout a2a-java + uses: actions/checkout@v4 + with: + repository: a2aproject/a2a-java + path: a2a-java + - name: Checkout a2a-tck + uses: actions/checkout@v4 + with: + repository: a2aproject/a2a-tck + path: a2a-tck + ref: ${{ env.TCK_VERSION }} + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: maven + - name: Build a2a-java with Maven, skipping tests + run: | + mvn -B install -DskipTests + working-directory: a2a-java + - name: Get a2a-java version and save as env var + run: | + VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout) + echo "SDK_VERSION=${VERSION}" >> "$GITHUB_ENV" + working-directory: a2a-java + - name: Build the TCK server + run: | + mvn clean install -B -Dversion.sdk=${SDK_VERSION} -pl tck -am + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version-file: "a2a-tck/pyproject.toml" + - name: Install uv and Python dependencies + run: | + pip install uv + uv pip install -e . + working-directory: a2a-tck + - name: Start the WildFly SUT + run: | + mvn wildfly:start -B -pl tck -Dstartup-timeout=120 + - name: Run TCK + run: | + ./run_tck.py --sut-url http://localhost:8080 --category all --compliance-report report.json + working-directory: a2a-tck + - name: Start the WildFly SUT + run: | + mvn wildfly:shutdown + + diff --git a/pom.xml b/pom.xml index a715565..5575236 100644 --- a/pom.xml +++ b/pom.xml @@ -178,51 +178,11 @@ org.wildfly.glow wildfly-glow-arquillian-plugin 1.4.1.Final - - - - org.wildfly - wildfly-galleon-pack - ${version.wildfly} - - - standalone.xml - - - - scan - - scan - - test-compile - - org.wildfly.plugins wildfly-maven-plugin 5.1.3.Final - - ${project.build.directory}/glow-scan/provisioning.xml - ${jboss.home} - ${jboss.home} - - - - - - - - - - - test-provisioning - - package - - test-compile - - org.apache.maven.plugins @@ -286,6 +246,7 @@ impl wildfly-jar + tck tests/common tests/impl tests/wildfly-jar diff --git a/tck/pom.xml b/tck/pom.xml new file mode 100644 index 0000000..9dd0446 --- /dev/null +++ b/tck/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + + org.wildfly.extras.a2a + a2a-java-sdk-server-jakarta-parent + 0.2.3.Beta2-SNAPSHOT + + + a2a-java-sdk-server-jakarta-tck-wildfly + + war + + WildFly Extras - Java A2A SDK for Jakarta - TCK - WildFly Jar + Java SDK for the Agent2Agent Protocol (A2A) - SDK - Jakarta - TCK - WildFly Jar + + + + ${project.groupId} + a2a-java-sdk-server-jakarta-wildfly + ${project.version} + + + * + * + + + + + io.github.a2asdk + a2a-java-sdk-spec + provided + + + jakarta.annotation + jakarta.annotation-api + provided + + + jakarta.enterprise + jakarta.enterprise.cdi-api + provided + + + jakarta.ws.rs + jakarta.ws.rs-api + provided + + + + + + org.wildfly.plugins + wildfly-maven-plugin + + + + ${jboss.home} + ROOT.war + ${jboss.home} + + + + + + + + + + + provisioning + + package + + package + + + + + + \ No newline at end of file diff --git a/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentCardProducer.java b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentCardProducer.java new file mode 100644 index 0000000..48476c7 --- /dev/null +++ b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentCardProducer.java @@ -0,0 +1,46 @@ +package org.wildfly.extras.a2a.server.jakarta.tck; + +import java.util.Collections; +import java.util.List; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import io.a2a.server.PublicAgentCard; +import io.a2a.spec.AgentCapabilities; +import io.a2a.spec.AgentCard; +import io.a2a.spec.AgentSkill; + +/** + * This is a copy of the AgentCardProducer from the a2a-java SDK's tck/ module + */ +@ApplicationScoped +public class AgentCardProducer { + + @Produces + @PublicAgentCard + public AgentCard agentCard() { + return new AgentCard.Builder() + .name("Hello World Agent") + .description("Just a hello world agent") + .url("http://localhost:9999") + .version("1.0.0") + .documentationUrl("http://example.com/docs") + .capabilities(new AgentCapabilities.Builder() + .streaming(true) + .pushNotifications(true) + .stateTransitionHistory(true) + .build()) + .defaultInputModes(Collections.singletonList("text")) + .defaultOutputModes(Collections.singletonList("text")) + .skills(Collections.singletonList(new AgentSkill.Builder() + .id("hello_world") + .name("Returns hello world") + .description("just returns hello world") + .tags(Collections.singletonList("hello world")) + .examples(List.of("hi", "hello world")) + .build())) + .build(); + } +} + diff --git a/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentExecutorProducer.java b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentExecutorProducer.java new file mode 100644 index 0000000..4a2df0c --- /dev/null +++ b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/AgentExecutorProducer.java @@ -0,0 +1,94 @@ +package org.wildfly.extras.a2a.server.jakarta.tck; + +import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.inject.Produces; + +import io.a2a.server.agentexecution.AgentExecutor; +import io.a2a.server.agentexecution.RequestContext; +import io.a2a.server.events.EventQueue; +import io.a2a.server.tasks.TaskUpdater; +import io.a2a.spec.JSONRPCError; +import io.a2a.spec.Task; +import io.a2a.spec.TaskNotCancelableError; +import io.a2a.spec.TaskNotFoundError; +import io.a2a.spec.TaskState; +import io.a2a.spec.TaskStatus; +import io.a2a.spec.TaskStatusUpdateEvent; + +/** + * This is a copy of the AgentExecutorProducer from the a2a-java SDK's tck/ module + */ +@ApplicationScoped +public class AgentExecutorProducer { + + @Produces + public AgentExecutor agentExecutor() { + return new FireAndForgetAgentExecutor(); + } + + private static class FireAndForgetAgentExecutor implements AgentExecutor { + @Override + public void execute(RequestContext context, EventQueue eventQueue) throws JSONRPCError { + Task task = context.getTask(); + + if (context.getMessage().getTaskId() != null && task == null && context.getMessage().getTaskId().startsWith("non-existent")) { + throw new TaskNotFoundError(); + } + + if (task == null) { + task = new Task.Builder() + .id(context.getTaskId()) + .contextId(context.getContextId()) + .status(new TaskStatus(TaskState.SUBMITTED)) + .history(context.getMessage()) + .build(); + eventQueue.enqueueEvent(task); + } + + TaskUpdater updater = new TaskUpdater(context, eventQueue); + + // Immediately set to WORKING state + updater.startWork(); + System.out.println("====> task set to WORKING, starting background execution"); + + // Method returns immediately - task continues in background + System.out.println("====> execute() method returning immediately, task running in background"); + } + + @Override + public void cancel(RequestContext context, EventQueue eventQueue) throws JSONRPCError { + System.out.println("====> task cancel request received"); + Task task = context.getTask(); + + if (task.getStatus().state() == TaskState.CANCELED) { + System.out.println("====> task already canceled"); + throw new TaskNotCancelableError(); + } + + if (task.getStatus().state() == TaskState.COMPLETED) { + System.out.println("====> task already completed"); + throw new TaskNotCancelableError(); + } + + TaskUpdater updater = new TaskUpdater(context, eventQueue); + updater.cancel(); + eventQueue.enqueueEvent(new TaskStatusUpdateEvent.Builder() + .taskId(task.getId()) + .contextId(task.getContextId()) + .status(new TaskStatus(TaskState.CANCELED)) + .isFinal(true) + .build()); + + System.out.println("====> task canceled"); + } + + /** + * Cleanup method for proper resource management + */ + @PreDestroy + public void cleanup() { + System.out.println("====> shutting down task executor"); + } + } +} \ No newline at end of file diff --git a/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/RestApplication.java b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/RestApplication.java new file mode 100644 index 0000000..1d9ba6d --- /dev/null +++ b/tck/src/main/java/org/wildfly/extras/a2a/server/jakarta/tck/RestApplication.java @@ -0,0 +1,8 @@ +package org.wildfly.extras.a2a.server.jakarta.tck; + +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + +@ApplicationPath("/") +public class RestApplication extends Application { +} diff --git a/impl/src/main/resources/META-INF/beans.xml b/tck/src/main/resources/META-INF/beans.xml similarity index 87% rename from impl/src/main/resources/META-INF/beans.xml rename to tck/src/main/resources/META-INF/beans.xml index 9dfae34..9b2940f 100644 --- a/impl/src/main/resources/META-INF/beans.xml +++ b/tck/src/main/resources/META-INF/beans.xml @@ -2,5 +2,5 @@ + bean-discovery-mode="annotated"> \ No newline at end of file diff --git a/impl/src/main/resources/WEB-INF/web.xml b/tck/src/main/resources/WEB-INF/web.xml similarity index 100% rename from impl/src/main/resources/WEB-INF/web.xml rename to tck/src/main/resources/WEB-INF/web.xml diff --git a/tck/src/scripts/configure_logger.cli b/tck/src/scripts/configure_logger.cli new file mode 100644 index 0000000..a45fb24 --- /dev/null +++ b/tck/src/scripts/configure_logger.cli @@ -0,0 +1,2 @@ +/subsystem=logging/logger=org.jboss.weld:add(level=DEBUG) +/subsystem=logging/logger=io.a2a:add(level=DEBUG) \ No newline at end of file diff --git a/tests/common/pom.xml b/tests/common/pom.xml index 240950d..b597a95 100644 --- a/tests/common/pom.xml +++ b/tests/common/pom.xml @@ -6,9 +6,8 @@ org.wildfly.extras.a2a - a2a-java-sdk-server-jakarta-parent + a2a-java-sdk-server-jakarta-test-parent 0.2.3.Beta2-SNAPSHOT - ../../pom.xml a2a-java-sdk-server-jakarta-test-common diff --git a/tests/common/src/main/resources/META-INF/beans.xml b/tests/common/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000..9b2940f --- /dev/null +++ b/tests/common/src/main/resources/META-INF/beans.xml @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/tests/common/src/main/resources/META-INF/services/org.wildfly.extras.a2a.server.apps.jakarta.TestingHook b/tests/common/src/main/resources/META-INF/services/org.wildfly.extras.a2a.server.apps.jakarta.TestingHook deleted file mode 100644 index e69de29..0000000 diff --git a/tests/common/src/main/resources/WEB-INF/web.xml b/tests/common/src/main/resources/WEB-INF/web.xml new file mode 100644 index 0000000..4330758 --- /dev/null +++ b/tests/common/src/main/resources/WEB-INF/web.xml @@ -0,0 +1,7 @@ + + + diff --git a/tests/impl/pom.xml b/tests/impl/pom.xml index c2ba055..8051924 100644 --- a/tests/impl/pom.xml +++ b/tests/impl/pom.xml @@ -6,9 +6,8 @@ org.wildfly.extras.a2a - a2a-java-sdk-server-jakarta-parent + a2a-java-sdk-server-jakarta-test-parent 0.2.3.Beta2-SNAPSHOT - ../../pom.xml a2a-java-sdk-server-jakarta-tests diff --git a/tests/impl/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/JakartaA2AServerTest.java b/tests/impl/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/JakartaA2AServerTest.java index 7313384..d73c1ad 100644 --- a/tests/impl/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/JakartaA2AServerTest.java +++ b/tests/impl/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/JakartaA2AServerTest.java @@ -58,7 +58,6 @@ public static WebArchive createTestArchive() throws Exception { .addPackage(A2ATestResource.class.getPackage()) // Add deployment descriptors .addAsManifestResource("META-INF/beans.xml", "beans.xml") - .addAsWebInfResource("META-INF/beans.xml", "beans.xml") .addAsWebInfResource("WEB-INF/web.xml", "web.xml"); archive.toString(true); return archive; diff --git a/tests/pom.xml b/tests/pom.xml new file mode 100644 index 0000000..458e755 --- /dev/null +++ b/tests/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + + org.wildfly.extras.a2a + a2a-java-sdk-server-jakarta-parent + 0.2.3.Beta2-SNAPSHOT + + + a2a-java-sdk-server-jakarta-test-parent + + pom + + WildFly Extras - Java A2A SDK for Jakarta - Test Parent + Java SDK for the Agent2Agent Protocol (A2A) - SDK - Jakarta - Test Parent + + + + + + org.wildfly.glow + wildfly-glow-arquillian-plugin + + + + org.wildfly + wildfly-galleon-pack + ${version.wildfly} + + + standalone.xml + + + + scan + + scan + + test-compile + + + + + org.wildfly.plugins + wildfly-maven-plugin + + ${project.build.directory}/glow-scan/provisioning.xml + ${jboss.home} + ${jboss.home} + + + + + + + + + + + test-provisioning + + package + + test-compile + + + + + + + \ No newline at end of file diff --git a/tests/wildfly-jar/pom.xml b/tests/wildfly-jar/pom.xml index 8622be2..6fd6adf 100644 --- a/tests/wildfly-jar/pom.xml +++ b/tests/wildfly-jar/pom.xml @@ -6,9 +6,8 @@ org.wildfly.extras.a2a - a2a-java-sdk-server-jakarta-parent + a2a-java-sdk-server-jakarta-test-parent 0.2.3.Beta2-SNAPSHOT - ../../pom.xml a2a-java-sdk-server-jakarta-tests-wildfly diff --git a/tests/wildfly-jar/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/WildFlyJarJakartaA2AServerTest.java b/tests/wildfly-jar/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/WildFlyJarJakartaA2AServerTest.java index 42cfeed..9145413 100644 --- a/tests/wildfly-jar/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/WildFlyJarJakartaA2AServerTest.java +++ b/tests/wildfly-jar/src/test/java/org/wildfly/extras/a2a/server/apps/jakarta/WildFlyJarJakartaA2AServerTest.java @@ -43,7 +43,6 @@ public static WebArchive createTestArchive() throws Exception { .addPackage(A2ATestResource.class.getPackage()) // Add deployment descriptors .addAsManifestResource("META-INF/beans.xml", "beans.xml") - .addAsWebInfResource("META-INF/beans.xml", "beans.xml") .addAsWebInfResource("WEB-INF/web.xml", "web.xml"); archive.toString(true); return archive;