From c24c3b77abcaa5b151d72f8bfe6544ba9afb457b Mon Sep 17 00:00:00 2001 From: pkarmarkar Date: Mon, 5 Jan 2026 16:43:59 -0800 Subject: [PATCH] fix: enable service injection in A2ASendMessageExecutor Updated A2ASendMessageExecutor and A2ARemoteConfiguration to support dependency injection of session, artifact, and memory services. This allows persistent service implementations to replace hard-coded in-memory versions. Changes: - Modified A2ASendMessageExecutor constructor to accept BaseSessionService, BaseArtifactService, and BaseMemoryService parameters - Updated A2ARemoteConfiguration to autowire service beans with fallback to in-memory defaults when custom beans are not provided - Added comprehensive test coverage for service injection scenarios Tasks: [x] Update A2ASendMessageExecutor to accept injected services [x] Modify A2ARemoteConfiguration to autowire service beans [x] Add unit tests for A2ASendMessageExecutor [x] Add integration tests for service injection [x] Add Spring configuration tests for custom services --- .../adk/a2a/A2ASendMessageExecutor.java | 60 ++++- .../A2ASendMessageExecutorAdvancedTest.java | 230 ++++++++++++++++++ ...A2ASendMessageExecutorIntegrationTest.java | 103 ++++++++ .../adk/a2a/A2ASendMessageExecutorTest.java | 62 +++++ a2a/webservice/pom.xml | 23 ++ .../webservice/A2ARemoteConfiguration.java | 45 +++- ...RemoteConfigurationCustomServicesTest.java | 65 +++++ .../A2ARemoteConfigurationTest.java | 35 +++ .../adk/webservice/TestAgentConfig.java | 27 ++ 9 files changed, 635 insertions(+), 15 deletions(-) create mode 100644 a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorAdvancedTest.java create mode 100644 a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorIntegrationTest.java create mode 100644 a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorTest.java create mode 100644 a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationCustomServicesTest.java create mode 100644 a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationTest.java create mode 100644 a2a/webservice/src/test/java/com/google/adk/webservice/TestAgentConfig.java diff --git a/a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java b/a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java index 47d3e402c..1ab832c7b 100644 --- a/a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java +++ b/a2a/src/main/java/com/google/adk/a2a/A2ASendMessageExecutor.java @@ -8,11 +8,11 @@ import com.google.adk.a2a.converters.ResponseConverter; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.RunConfig; -import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.artifacts.BaseArtifactService; import com.google.adk.events.Event; -import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.memory.BaseMemoryService; import com.google.adk.runner.Runner; -import com.google.adk.sessions.InMemorySessionService; +import com.google.adk.sessions.BaseSessionService; import com.google.adk.sessions.Session; import com.google.common.collect.ImmutableList; import com.google.genai.types.Content; @@ -51,29 +51,63 @@ Single> execute( String invocationId); } - private final InMemorySessionService sessionService; + private final BaseSessionService sessionService; private final String appName; @Nullable private final Runner runner; @Nullable private final Duration agentTimeout; private static final RunConfig DEFAULT_RUN_CONFIG = RunConfig.builder().setStreamingMode(RunConfig.StreamingMode.NONE).setMaxLlmCalls(20).build(); - public A2ASendMessageExecutor(InMemorySessionService sessionService, String appName) { + public A2ASendMessageExecutor(BaseSessionService sessionService, String appName) { this.sessionService = sessionService; this.appName = appName; this.runner = null; this.agentTimeout = null; } - public A2ASendMessageExecutor(BaseAgent agent, String appName, Duration agentTimeout) { - InMemorySessionService sessionService = new InMemorySessionService(); + /** + * Creates an A2A send message executor with explicit service dependencies. + * + *

This constructor requires all service implementations to be provided explicitly, enabling + * flexible deployment configurations (e.g., persistent sessions, distributed artifacts). + * + *

Note: In version 0.5.1, the constructor signature changed to require + * explicit service injection. Previously, services were created internally as in-memory + * implementations. + * + *

For Spring Boot applications: Use {@link + * com.google.adk.webservice.A2ARemoteConfiguration} which automatically provides service beans + * with sensible defaults. Direct instantiation is typically only needed for custom frameworks or + * testing. + * + *

Example usage: + * + *

{@code
+   * A2ASendMessageExecutor executor = new A2ASendMessageExecutor(
+   *     myAgent,
+   *     "my-app",
+   *     Duration.ofSeconds(30),
+   *     new InMemorySessionService(),    // or DatabaseSessionService for persistence
+   *     new InMemoryArtifactService(),   // or S3ArtifactService for distributed storage
+   *     new InMemoryMemoryService());    // or RedisMemoryService for shared state
+   * }
+ * + * @param agent the agent to execute when processing messages + * @param appName the application name used for session identification + * @param agentTimeout maximum duration to wait for agent execution before timing out + * @param sessionService service for managing conversation sessions (required, non-null) + * @param artifactService service for storing and retrieving artifacts (required, non-null) + * @param memoryService service for managing agent memory/state (required, non-null) + */ + public A2ASendMessageExecutor( + BaseAgent agent, + String appName, + Duration agentTimeout, + BaseSessionService sessionService, + BaseArtifactService artifactService, + BaseMemoryService memoryService) { Runner runnerInstance = - new Runner( - agent, - appName, - new InMemoryArtifactService(), - sessionService, - new InMemoryMemoryService()); + new Runner(agent, appName, artifactService, sessionService, memoryService); this.sessionService = sessionService; this.appName = appName; this.runner = runnerInstance; diff --git a/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorAdvancedTest.java b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorAdvancedTest.java new file mode 100644 index 000000000..f26acc94d --- /dev/null +++ b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorAdvancedTest.java @@ -0,0 +1,230 @@ +package com.google.adk.a2a; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.InvocationContext; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.events.Event; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.InMemorySessionService; +import com.google.common.collect.ImmutableList; +import com.google.genai.types.Content; +import com.google.genai.types.Part; +import io.a2a.spec.Message; +import io.a2a.spec.TextPart; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.Single; +import java.time.Duration; +import java.util.List; +import java.util.UUID; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class A2ASendMessageExecutorAdvancedTest { + + private InMemorySessionService sessionService; + + @Test + public void execute_withCustomStrategy_usesStrategy() { + InMemorySessionService sessionService = new InMemorySessionService(); + + A2ASendMessageExecutor executor = new A2ASendMessageExecutor(sessionService, "test-app"); + + A2ASendMessageExecutor.AgentExecutionStrategy customStrategy = + (userId, sessionId, userContent, runConfig, invocationId) -> { + Event customEvent = + Event.builder() + .id(UUID.randomUUID().toString()) + .invocationId(invocationId) + .author("agent") + .content( + Content.builder() + .role("model") + .parts( + ImmutableList.of( + Part.builder().text("Custom strategy response").build())) + .build()) + .build(); + return Single.just(ImmutableList.of(customEvent)); + }; + + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId("ctx-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test"))) + .build(); + + Message response = executor.execute(request, customStrategy).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getParts()).isNotEmpty(); + assertThat(((TextPart) response.getParts().get(0)).getText()) + .contains("Custom strategy response"); + } + + private A2ASendMessageExecutor createExecutorWithAgent() { + BaseAgent agent = createSimpleAgent(); + sessionService = new InMemorySessionService(); + return new A2ASendMessageExecutor( + agent, + "test-app", + Duration.ofSeconds(30), + sessionService, + new InMemoryArtifactService(), + new InMemoryMemoryService()); + } + + @Test + public void execute_withNullMessage_generatesDefaultContext() { + A2ASendMessageExecutor executor = createExecutorWithAgent(); + + Message response = executor.execute(null).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getContextId()).isNotNull(); + assertThat(response.getContextId()).isNotEmpty(); + } + + @Test + public void execute_withEmptyContextId_generatesNewContext() { + A2ASendMessageExecutor executor = createExecutorWithAgent(); + + Message request = + new Message.Builder() + .messageId("msg-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test"))) + .build(); + + Message response = executor.execute(request).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getContextId()).isNotNull(); + assertThat(response.getContextId()).isNotEmpty(); + } + + @Test + public void execute_withProvidedContextId_preservesContext() { + A2ASendMessageExecutor executor = createExecutorWithAgent(); + + String contextId = "my-custom-context"; + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId(contextId) + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test"))) + .build(); + + Message response = executor.execute(request).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getContextId()).isEqualTo(contextId); + } + + @Test + public void execute_multipleRequests_maintainsSession() { + A2ASendMessageExecutor executor = createExecutorWithAgent(); + + String contextId = "persistent-context"; + + Message request1 = + new Message.Builder() + .messageId("msg-1") + .contextId(contextId) + .role(Message.Role.USER) + .parts(List.of(new TextPart("First message"))) + .build(); + + Message response1 = executor.execute(request1).blockingGet(); + assertThat(response1.getContextId()).isEqualTo(contextId); + + Message request2 = + new Message.Builder() + .messageId("msg-2") + .contextId(contextId) + .role(Message.Role.USER) + .parts(List.of(new TextPart("Second message"))) + .build(); + + Message response2 = executor.execute(request2).blockingGet(); + assertThat(response2.getContextId()).isEqualTo(contextId); + } + + @Test + public void execute_withoutRunnerConfig_throwsException() { + InMemorySessionService sessionService = new InMemorySessionService(); + + A2ASendMessageExecutor executor = new A2ASendMessageExecutor(sessionService, "test-app"); + + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId("ctx-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test"))) + .build(); + + try { + executor.execute(request).blockingGet(); + assertThat(false).isTrue(); + } catch (IllegalStateException e) { + assertThat(e.getMessage()).contains("Runner-based handle invoked without configured runner"); + } + } + + @Test + public void execute_errorInStrategy_returnsErrorResponse() { + InMemorySessionService sessionService = new InMemorySessionService(); + + A2ASendMessageExecutor executor = new A2ASendMessageExecutor(sessionService, "test-app"); + + A2ASendMessageExecutor.AgentExecutionStrategy failingStrategy = + (userId, sessionId, userContent, runConfig, invocationId) -> { + return Single.error(new RuntimeException("Strategy failed")); + }; + + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId("ctx-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test"))) + .build(); + + Message response = executor.execute(request, failingStrategy).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getParts()).isNotEmpty(); + assertThat(((TextPart) response.getParts().get(0)).getText()).contains("Error:"); + assertThat(((TextPart) response.getParts().get(0)).getText()).contains("Strategy failed"); + } + + private BaseAgent createSimpleAgent() { + return new BaseAgent("test", "test agent", ImmutableList.of(), null, null) { + @Override + protected Flowable runAsyncImpl(InvocationContext ctx) { + return Flowable.just( + Event.builder() + .content( + Content.builder() + .role("model") + .parts( + ImmutableList.of( + com.google.genai.types.Part.builder().text("Response").build())) + .build()) + .build()); + } + + @Override + protected Flowable runLiveImpl(InvocationContext ctx) { + return Flowable.empty(); + } + }; + } +} diff --git a/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorIntegrationTest.java b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorIntegrationTest.java new file mode 100644 index 000000000..20fff9898 --- /dev/null +++ b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorIntegrationTest.java @@ -0,0 +1,103 @@ +package com.google.adk.a2a; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.InvocationContext; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.events.Event; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.InMemorySessionService; +import com.google.common.collect.ImmutableList; +import com.google.genai.types.Content; +import io.a2a.spec.Message; +import io.a2a.spec.TextPart; +import io.reactivex.rxjava3.core.Flowable; +import java.time.Duration; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class A2ASendMessageExecutorIntegrationTest { + + @Test + public void execute_withInMemoryServices_succeeds() { + InMemorySessionService sessionService = new InMemorySessionService(); + BaseAgent agent = createSimpleAgent(); + + A2ASendMessageExecutor executor = + new A2ASendMessageExecutor( + agent, + "test-app", + Duration.ofSeconds(30), + sessionService, + new InMemoryArtifactService(), + new InMemoryMemoryService()); + + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId("ctx-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Hello"))) + .build(); + + Message response = executor.execute(request).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getContextId()).isEqualTo("ctx-1"); + } + + @Test + public void execute_createsSessionAndProcessesRequest() { + InMemorySessionService sessionService = new InMemorySessionService(); + BaseAgent agent = createSimpleAgent(); + + A2ASendMessageExecutor executor = + new A2ASendMessageExecutor( + agent, + "test-app", + Duration.ofSeconds(30), + sessionService, + new InMemoryArtifactService(), + new InMemoryMemoryService()); + + Message request = + new Message.Builder() + .messageId("msg-1") + .contextId("ctx-1") + .role(Message.Role.USER) + .parts(List.of(new TextPart("Test message"))) + .build(); + + Message response = executor.execute(request).blockingGet(); + + assertThat(response).isNotNull(); + assertThat(response.getParts()).isNotEmpty(); + } + + private BaseAgent createSimpleAgent() { + return new BaseAgent("test", "test agent", ImmutableList.of(), null, null) { + @Override + protected Flowable runAsyncImpl(InvocationContext ctx) { + return Flowable.just( + Event.builder() + .content( + Content.builder() + .role("model") + .parts( + ImmutableList.of( + com.google.genai.types.Part.builder().text("Response").build())) + .build()) + .build()); + } + + @Override + protected Flowable runLiveImpl(InvocationContext ctx) { + return Flowable.empty(); + } + }; + } +} diff --git a/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorTest.java b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorTest.java new file mode 100644 index 000000000..7091ce380 --- /dev/null +++ b/a2a/src/test/java/com/google/adk/a2a/A2ASendMessageExecutorTest.java @@ -0,0 +1,62 @@ +package com.google.adk.a2a; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.InvocationContext; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.events.Event; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.InMemorySessionService; +import com.google.common.collect.ImmutableList; +import io.reactivex.rxjava3.core.Flowable; +import java.time.Duration; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class A2ASendMessageExecutorTest { + + @Test + public void constructor_simple_acceptsSessionService() { + InMemorySessionService sessionService = new InMemorySessionService(); + + A2ASendMessageExecutor executor = new A2ASendMessageExecutor(sessionService, "test-app"); + + assertThat(executor).isNotNull(); + } + + @Test + public void constructor_withAgent_acceptsAllServices() { + BaseAgent agent = createSimpleAgent(); + InMemorySessionService sessionService = new InMemorySessionService(); + InMemoryArtifactService artifactService = new InMemoryArtifactService(); + InMemoryMemoryService memoryService = new InMemoryMemoryService(); + + A2ASendMessageExecutor executor = + new A2ASendMessageExecutor( + agent, + "test-app", + Duration.ofSeconds(30), + sessionService, + artifactService, + memoryService); + + assertThat(executor).isNotNull(); + } + + private BaseAgent createSimpleAgent() { + return new BaseAgent("test", "test agent", ImmutableList.of(), null, null) { + @Override + protected Flowable runAsyncImpl(InvocationContext ctx) { + return Flowable.empty(); + } + + @Override + protected Flowable runLiveImpl(InvocationContext ctx) { + return Flowable.empty(); + } + }; + } +} diff --git a/a2a/webservice/pom.xml b/a2a/webservice/pom.xml index deb03fd27..3d3c92e64 100644 --- a/a2a/webservice/pom.xml +++ b/a2a/webservice/pom.xml @@ -35,6 +35,17 @@ org.slf4j slf4j-api + + org.springframework.boot + spring-boot-starter-test + test + + + junit + junit + 4.13.2 + test + @@ -47,6 +58,18 @@ ${java.version} + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + + org.apache.maven.surefire + surefire-junit47 + 3.5.2 + + + org.springframework.boot spring-boot-maven-plugin diff --git a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java b/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java index a3f9b48ac..b2b6916d9 100644 --- a/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java +++ b/a2a/webservice/src/main/java/com/google/adk/webservice/A2ARemoteConfiguration.java @@ -2,10 +2,17 @@ import com.google.adk.a2a.A2ASendMessageExecutor; import com.google.adk.agents.BaseAgent; +import com.google.adk.artifacts.BaseArtifactService; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.memory.BaseMemoryService; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.BaseSessionService; +import com.google.adk.sessions.InMemorySessionService; import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -35,15 +42,49 @@ public class A2ARemoteConfiguration { private static final String DEFAULT_APP_NAME = "a2a-remote-service"; private static final long DEFAULT_TIMEOUT_SECONDS = 15L; + @Bean + @ConditionalOnMissingBean + public BaseSessionService sessionService() { + return new InMemorySessionService(); + } + + @Bean + @ConditionalOnMissingBean + public BaseArtifactService artifactService() { + return new InMemoryArtifactService(); + } + + @Bean + @ConditionalOnMissingBean + public BaseMemoryService memoryService() { + return new InMemoryMemoryService(); + } + @Bean public A2ASendMessageExecutor a2aSendMessageExecutor( BaseAgent agent, @Value("${a2a.remote.appName:" + DEFAULT_APP_NAME + "}") String appName, - @Value("${a2a.remote.timeoutSeconds:" + DEFAULT_TIMEOUT_SECONDS + "}") long timeoutSeconds) { + @Value("${a2a.remote.timeoutSeconds:" + DEFAULT_TIMEOUT_SECONDS + "}") long timeoutSeconds, + BaseSessionService sessionService, + BaseArtifactService artifactService, + BaseMemoryService memoryService) { + logger.info( "Initializing A2A send message executor for appName {} with timeout {}s", appName, timeoutSeconds); - return new A2ASendMessageExecutor(agent, appName, Duration.ofSeconds(timeoutSeconds)); + logger.info( + "Using services: session={}, artifact={}, memory={}", + sessionService.getClass().getSimpleName(), + artifactService.getClass().getSimpleName(), + memoryService.getClass().getSimpleName()); + + return new A2ASendMessageExecutor( + agent, + appName, + Duration.ofSeconds(timeoutSeconds), + sessionService, + artifactService, + memoryService); } } diff --git a/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationCustomServicesTest.java b/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationCustomServicesTest.java new file mode 100644 index 000000000..824d3d940 --- /dev/null +++ b/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationCustomServicesTest.java @@ -0,0 +1,65 @@ +package com.google.adk.webservice; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; + +import com.google.adk.a2a.A2ASendMessageExecutor; +import com.google.adk.artifacts.BaseArtifactService; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.memory.BaseMemoryService; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.BaseSessionService; +import com.google.adk.sessions.InMemorySessionService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration( + classes = { + A2ARemoteConfiguration.class, + TestAgentConfig.class, + A2ARemoteConfigurationCustomServicesTest.WithCustomServicesTestConfig.class + }) +public class A2ARemoteConfigurationCustomServicesTest { + + @TestConfiguration + static class WithCustomServicesTestConfig { + private static final BaseSessionService CUSTOM_SESSION_SERVICE = new InMemorySessionService(); + private static final BaseArtifactService CUSTOM_ARTIFACT_SERVICE = + new InMemoryArtifactService(); + private static final BaseMemoryService CUSTOM_MEMORY_SERVICE = new InMemoryMemoryService(); + + @Bean + public BaseSessionService customSessionService() { + return CUSTOM_SESSION_SERVICE; + } + + @Bean + public BaseArtifactService customArtifactService() { + return CUSTOM_ARTIFACT_SERVICE; + } + + @Bean + public BaseMemoryService customMemoryService() { + return CUSTOM_MEMORY_SERVICE; + } + } + + @Autowired private A2ASendMessageExecutor executor; + @Autowired private BaseSessionService sessionService; + @Autowired private BaseArtifactService artifactService; + @Autowired private BaseMemoryService memoryService; + + @Test + public void beanCreation_withCustomServices_autowires() { + assertNotNull(executor); + assertSame(WithCustomServicesTestConfig.CUSTOM_SESSION_SERVICE, sessionService); + assertSame(WithCustomServicesTestConfig.CUSTOM_ARTIFACT_SERVICE, artifactService); + assertSame(WithCustomServicesTestConfig.CUSTOM_MEMORY_SERVICE, memoryService); + } +} diff --git a/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationTest.java b/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationTest.java new file mode 100644 index 000000000..07e8ca543 --- /dev/null +++ b/a2a/webservice/src/test/java/com/google/adk/webservice/A2ARemoteConfigurationTest.java @@ -0,0 +1,35 @@ +package com.google.adk.webservice; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.google.adk.a2a.A2ASendMessageExecutor; +import com.google.adk.artifacts.BaseArtifactService; +import com.google.adk.artifacts.InMemoryArtifactService; +import com.google.adk.memory.BaseMemoryService; +import com.google.adk.memory.InMemoryMemoryService; +import com.google.adk.sessions.BaseSessionService; +import com.google.adk.sessions.InMemorySessionService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = {A2ARemoteConfiguration.class, TestAgentConfig.class}) +public class A2ARemoteConfigurationTest { + + @Autowired private A2ASendMessageExecutor executor; + @Autowired private BaseSessionService sessionService; + @Autowired private BaseArtifactService artifactService; + @Autowired private BaseMemoryService memoryService; + + @Test + public void beanCreation_withoutCustomServices_usesDefaults() { + assertNotNull(executor); + assertTrue(sessionService instanceof InMemorySessionService); + assertTrue(artifactService instanceof InMemoryArtifactService); + assertTrue(memoryService instanceof InMemoryMemoryService); + } +} diff --git a/a2a/webservice/src/test/java/com/google/adk/webservice/TestAgentConfig.java b/a2a/webservice/src/test/java/com/google/adk/webservice/TestAgentConfig.java new file mode 100644 index 000000000..0b43cb0fc --- /dev/null +++ b/a2a/webservice/src/test/java/com/google/adk/webservice/TestAgentConfig.java @@ -0,0 +1,27 @@ +package com.google.adk.webservice; + +import com.google.adk.agents.BaseAgent; +import com.google.adk.agents.InvocationContext; +import com.google.adk.events.Event; +import com.google.common.collect.ImmutableList; +import io.reactivex.rxjava3.core.Flowable; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestAgentConfig { + @Bean + public BaseAgent testAgent() { + return new BaseAgent("test", "test agent", ImmutableList.of(), null, null) { + @Override + protected Flowable runAsyncImpl(InvocationContext ctx) { + return Flowable.empty(); + } + + @Override + protected Flowable runLiveImpl(InvocationContext ctx) { + return Flowable.empty(); + } + }; + } +}