diff --git a/core/pom.xml b/core/pom.xml index fe65715f3..7d2032c7e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,4 +1,4 @@ - + 4.0.0 - com.google.adk google-adk-parent - 0.4.1-SNAPSHOT + 0.4.1-SNAPSHOT + - google-adk Agent Development Kit Agent Development Kit: an open-source, code-first toolkit designed to simplify building, evaluating, and deploying advanced AI agents anywhere. - - - com.anthropic @@ -201,6 +197,15 @@ maven-compiler-plugin + + io.spring.javaformat + spring-javaformat-maven-plugin + 0.0.40 + + + + + - + \ No newline at end of file diff --git a/core/src/test/java/com/google/adk/agents/BaseAgentFindAgentTest.java b/core/src/test/java/com/google/adk/agents/BaseAgentFindAgentTest.java new file mode 100644 index 000000000..bea720625 --- /dev/null +++ b/core/src/test/java/com/google/adk/agents/BaseAgentFindAgentTest.java @@ -0,0 +1,333 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed 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. + */ +// ********RoostGPT******** +/* +Test generated by RoostGPT for test june-java-unit using AI Type AWS Bedrock Runtime AI and AI Model global.anthropic.claude-sonnet-4-6 + +ROOST_METHOD_HASH=findAgent_fb90a0fcc1 +ROOST_METHOD_SIG_HASH=findAgent_611fa42d7c + +Scenario 1: Find Agent by Its Own Name (Self-Match) + +Details: + TestName: findAgentReturnsSelfWhenNameMatches + Description: Verifies that when the `findAgent` method is called with a name that matches + the current agent's own name, the method returns the agent itself (this reference). + This validates the first branch of the conditional logic in `findAgent`. +Execution: + Arrange: Create a concrete implementation of BaseAgent with a specific name, e.g., "rootAgent", + and no sub-agents (empty list). + Act: Call findAgent("rootAgent") on the created agent instance. + Assert: Assert that the returned BaseAgent is the same instance as the root agent + (use assertSame to verify object identity). +Validation: + The assertion verifies that when the agent's own name is provided, the method immediately + returns itself without delegating to findSubAgent. This is critical for correct self-identification + in agent trees, ensuring that agents can locate themselves when traversal begins from their node. + +*/ + +// ********RoostGPT******** +package com.google.adk.agents; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import com.google.adk.agents.Callbacks.AfterAgentCallback; +import com.google.adk.agents.Callbacks.BeforeAgentCallback; +import com.google.adk.events.Event; +import com.google.adk.plugins.PluginManager; +import com.google.common.collect.ImmutableList; +import com.google.genai.types.Content; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.Maybe; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; +import static com.google.common.collect.ImmutableList.toImmutableList; +import com.google.adk.Telemetry; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +import com.google.errorprone.annotations.DoNotCall; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.reactivex.rxjava3.core.Single; +import java.util.function.Function; +import java.util.stream.Stream; +import org.jspecify.annotations.Nullable; + +class BaseAgentFindAgentTest { + + // Concrete implementation of BaseAgent for testing purposes + static class TestAgent extends BaseAgent { + + public TestAgent(String name, String description, List subAgents, + List beforeAgentCallback, + List afterAgentCallback) { + super(name, description, subAgents, beforeAgentCallback, afterAgentCallback); + } + + @Override + protected Flowable runAsyncImpl(InvocationContext invocationContext) { + return Flowable.empty(); + } + + @Override + protected Flowable runLiveImpl(InvocationContext invocationContext) { + return Flowable.empty(); + } + + } + + // ----------------------------------------------------------------------- + // Scenario 1: Find Agent by Its Own Name (Self-Match) + // ----------------------------------------------------------------------- + @Test + @Tag("valid") + void findAgentReturnsSelfWhenNameMatches() { + TestAgent rootAgent = new TestAgent("rootAgent", "Root agent description", Collections.emptyList(), null, null); + BaseAgent result = rootAgent.findAgent("rootAgent"); + assertSame(rootAgent, result, "findAgent should return the agent itself when the name matches its own name."); + } + + // ----------------------------------------------------------------------- + // Additional valid scenarios + // ----------------------------------------------------------------------- + @Test + @Tag("valid") + void findAgentReturnsSelfWithNoSubAgentsAndMatchingName() { + TestAgent agent = new TestAgent("myAgent", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("myAgent"); + assertNotNull(result, "Result should not be null when the agent's own name is matched."); + assertSame(agent, result, "The returned agent should be the same instance as the called agent."); + } + + @Test + @Tag("valid") + void findAgentReturnsNullWhenNameDoesNotMatchAndNoSubAgents() { + TestAgent agent = new TestAgent("agentA", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("nonExistentAgent"); + assertNull(result, "findAgent should return null when there are no sub-agents and the name does not match."); + } + + @Test + @Tag("valid") + void findAgentFindsDirectSubAgentByName() { + TestAgent child = new TestAgent("childAgent", "Child description", ImmutableList.of(), null, null); + TestAgent parent = new TestAgent("parentAgent", "Parent description", Collections.singletonList(child), null, + null); + BaseAgent result = parent.findAgent("childAgent"); + assertNotNull(result, "Should find a direct sub-agent by name."); + assertSame(child, result, "The returned agent should be the child agent instance."); + } + + @Test + @Tag("valid") + void findAgentFindsDeeplyNestedSubAgentByName() { + TestAgent grandchild = new TestAgent("grandchildAgent", "Grandchild description", ImmutableList.of(), null, + null); + TestAgent child = new TestAgent("childAgent", "Child description", Collections.singletonList(grandchild), null, + null); + TestAgent root = new TestAgent("rootAgent", "Root description", Collections.singletonList(child), null, null); + BaseAgent result = root.findAgent("grandchildAgent"); + assertNotNull(result, "Should find a deeply nested sub-agent by name."); + assertSame(grandchild, result, "The returned agent should be the grandchild agent instance."); + } + + @Test + @Tag("valid") + void findAgentWithMultipleSubAgentsReturnsCorrectOne() { + TestAgent child1 = new TestAgent("child1", "Child1 description", ImmutableList.of(), null, null); + TestAgent child2 = new TestAgent("child2", "Child2 description", ImmutableList.of(), null, null); + TestAgent child3 = new TestAgent("child3", "Child3 description", ImmutableList.of(), null, null); + TestAgent parent = new TestAgent("parent", "Parent description", Arrays.asList(child1, child2, child3), null, + null); + BaseAgent result = parent.findAgent("child2"); + assertNotNull(result, "Should find child2 among multiple sub-agents."); + assertSame(child2, result, "The returned agent should be child2 instance."); + } + + @Test + @Tag("valid") + void findAgentReturnsParentWhenParentNameIsQueried() { + TestAgent child = new TestAgent("childAgent", "Child description", ImmutableList.of(), null, null); + TestAgent parent = new TestAgent("parentAgent", "Parent description", Collections.singletonList(child), null, + null); + BaseAgent result = parent.findAgent("parentAgent"); + assertSame(parent, result, "findAgent should return itself when the parent's own name is queried."); + } + + // ----------------------------------------------------------------------- + // Invalid / edge case scenarios + // ----------------------------------------------------------------------- + @Test + @Tag("invalid") + void findAgentReturnsNullForUnknownNameWithSubAgents() { + TestAgent child = new TestAgent("childAgent", "Child description", ImmutableList.of(), null, null); + TestAgent parent = new TestAgent("parentAgent", "Parent description", Collections.singletonList(child), null, + null); + BaseAgent result = parent.findAgent("unknownAgent"); + assertNull(result, "findAgent should return null when the name is not found in the agent tree."); + } + + @Test + @Tag("invalid") + void findAgentIsCaseSensitiveDoesNotMatchDifferentCase() { + TestAgent agent = new TestAgent("MyAgent", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("myagent"); + assertNull(result, "findAgent should be case-sensitive and not match 'myagent' for 'MyAgent'."); + } + + @Test + @Tag("invalid") + void findAgentDoesNotMatchPartialName() { + TestAgent agent = new TestAgent("myAgent", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("my"); + assertNull(result, "findAgent should not match partial names; 'my' should not match 'myAgent'."); + } + + @Test + @Tag("invalid") + void findAgentDoesNotMatchSupersetName() { + TestAgent agent = new TestAgent("myAgent", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("myAgentExtra"); + assertNull(result, "findAgent should not match a name that is a superset of the agent's actual name."); + } + + @Test + @Tag("invalid") + void findAgentReturnsNullForEmptyNameWhenAgentNameIsNonEmpty() { + TestAgent agent = new TestAgent("agentName", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent(""); + assertNull(result, + "findAgent should return null when searching for an empty string and agent name is non-empty."); + } + + @Test + @Tag("boundary") + void findAgentWithEmptySubAgentListReturnsNullForNonMatchingName() { + TestAgent agent = new TestAgent("agentA", "Description", Collections.emptyList(), null, null); + BaseAgent result = agent.findAgent("agentB"); + assertNull(result, "findAgent should return null when there are no sub-agents and name does not match."); + } + + @Test + @Tag("boundary") + void findAgentReturnsSelfWhenAgentHasSpecialCharactersInName() { + TestAgent agent = new TestAgent("agent-1_special.name", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("agent-1_special.name"); + assertSame(agent, result, "findAgent should return itself even when the name contains special characters."); + } + + @Test + @Tag("boundary") + void findAgentWithSingleCharacterName() { + TestAgent agent = new TestAgent("A", "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent("A"); + assertSame(agent, result, "findAgent should return itself when using a single character name."); + } + + @Test + @Tag("boundary") + void findAgentWithLongAgentName() { + String longName = "a".repeat(1000); + TestAgent agent = new TestAgent(longName, "Description", ImmutableList.of(), null, null); + BaseAgent result = agent.findAgent(longName); + assertSame(agent, result, "findAgent should return itself even for very long agent names."); + } + + @Test + @Tag("boundary") + void findAgentWithNullSubAgentListDefaultsToEmpty() { + // When subAgents is null, the constructor defaults to ImmutableList.of() + TestAgent agent = new TestAgent("agentA", "Description", null, null, null); + BaseAgent result = agent.findAgent("agentA"); + assertSame(agent, result, + "findAgent should return itself even when subAgents was initialized as null (defaults to empty)."); + } + + @Test + @Tag("boundary") + void findAgentReturnsNullWithNullSubAgentListAndNonMatchingName() { + TestAgent agent = new TestAgent("agentA", "Description", null, null, null); + BaseAgent result = agent.findAgent("agentB"); + assertNull(result, + "findAgent should return null when sub-agents list is empty (null input) and name does not match."); + } + + // ----------------------------------------------------------------------- + // Integration scenarios + // ----------------------------------------------------------------------- + @Test + @Tag("integration") + void findAgentInDeepTreeTraversesAllLevels() { + TestAgent level4 = new TestAgent("level4", "Level4", ImmutableList.of(), null, null); + TestAgent level3 = new TestAgent("level3", "Level3", Collections.singletonList(level4), null, null); + TestAgent level2 = new TestAgent("level2", "Level2", Collections.singletonList(level3), null, null); + TestAgent level1 = new TestAgent("level1", "Level1", Collections.singletonList(level2), null, null); + TestAgent root = new TestAgent("root", "Root", Collections.singletonList(level1), null, null); + assertSame(root, root.findAgent("root"), "Should find root itself."); + assertSame(level1, root.findAgent("level1"), "Should find level1."); + assertSame(level2, root.findAgent("level2"), "Should find level2."); + assertSame(level3, root.findAgent("level3"), "Should find level3."); + assertSame(level4, root.findAgent("level4"), "Should find level4."); + assertNull(root.findAgent("nonExistent"), "Should return null for non-existent agent."); + } + + @Test + @Tag("integration") + void findAgentInWideTreeWithManySubAgents() { + TestAgent[] children = new TestAgent[10]; + for (int i = 0; i < 10; i++) { + children[i] = new TestAgent("child" + i, "Child " + i, ImmutableList.of(), null, null); + } + TestAgent parent = new TestAgent("parent", "Parent", Arrays.asList(children), null, null); + for (int i = 0; i < 10; i++) { + BaseAgent found = parent.findAgent("child" + i); + assertSame(children[i], found, "Should find child" + i + " in a wide tree."); + } + } + + @Test + @Tag("integration") + void findAgentReturnsSelfCorrectlyWithCallbacks() { + BeforeAgentCallback beforeCallback = callbackContext -> Maybe.empty(); + AfterAgentCallback afterCallback = callbackContext -> Maybe.empty(); + TestAgent agent = new TestAgent("agentWithCallbacks", "Description", ImmutableList.of(), + Collections.singletonList(beforeCallback), Collections.singletonList(afterCallback)); + BaseAgent result = agent.findAgent("agentWithCallbacks"); + assertSame(agent, result, "findAgent should return itself correctly even when callbacks are configured."); + } + + @Test + @Tag("integration") + void findAgentSearchesCorrectlyInMixedDepthTree() { + TestAgent deepChild = new TestAgent("deepChild", "Deep Child", ImmutableList.of(), null, null); + TestAgent middleChild = new TestAgent("middleChild", "Middle Child", Collections.singletonList(deepChild), null, + null); + TestAgent sibling = new TestAgent("siblingAgent", "Sibling", ImmutableList.of(), null, null); + TestAgent root = new TestAgent("rootAgent", "Root", Arrays.asList(sibling, middleChild), null, null); + assertSame(root, root.findAgent("rootAgent"), "Should find root itself."); + assertSame(sibling, root.findAgent("siblingAgent"), "Should find sibling at top level."); + assertSame(middleChild, root.findAgent("middleChild"), "Should find middleChild at second level."); + assertSame(deepChild, root.findAgent("deepChild"), "Should find deepChild at third level."); + assertNull(root.findAgent("notInTree"), "Should return null for an agent not in the tree."); + } + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6009c7316..24fd6ece6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,4 @@ - + - + 4.0.0 - com.google.adk google-adk-parent - 0.4.1-SNAPSHOT + 0.4.1-SNAPSHOT + pom - Google Agent Development Kit Maven Parent POM https://github.com/google/adk-java Google Agent Development Kit (ADK) for Java - core dev @@ -39,12 +35,10 @@ a2a a2a/webservice - 17 ${java.version} UTF-8 - 1.11.0 3.4.1 1.49.0 @@ -73,7 +67,6 @@ 3.9.0 5.4.3 - @@ -112,7 +105,6 @@ pom import - com.anthropic @@ -274,9 +266,21 @@ assertj-core ${assertj.version} + + org.mockito + mockito-junit-jupiter + 2.23.4 + test + + + + io.spring.javaformat + spring-javaformat-formatter + 0.0.40 + + - @@ -324,8 +328,7 @@ plain - + **/*Test.java @@ -469,6 +472,36 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.2.5 + + testReport + + + + + org.apache.maven.plugins + maven-site-plugin + 2.1 + + testReport + + + + + io.spring.javaformat + spring-javaformat-maven-plugin + 0.0.40 + + @@ -528,7 +561,6 @@ - The Apache License, Version 2.0 @@ -558,4 +590,19 @@ https://central.sonatype.com/repository/maven-snapshots/ + + + org.mockito + mockito-junit-jupiter + 2.23.4 + test + + + + io.spring.javaformat + spring-javaformat-formatter + 0.0.40 + + + \ No newline at end of file