Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<!--
Copyright 2025 Google LLC

Expand All @@ -16,19 +16,15 @@
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-parent</artifactId>
<version>0.4.1-SNAPSHOT</version><!-- {x-version-update:google-adk:current} -->
<version>0.4.1-SNAPSHOT</version>
<!-- {x-version-update:google-adk:current} -->
</parent>

<artifactId>google-adk</artifactId>
<name>Agent Development Kit</name>
<description>Agent Development Kit: an open-source, code-first toolkit designed to simplify building, evaluating, and deploying advanced AI agents anywhere.</description>



<dependencies>
<dependency>
<groupId>com.anthropic</groupId>
Expand Down Expand Up @@ -201,6 +197,15 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
<version>0.0.40</version>
<!--Plugin added by RoostGPT-->
</plugin>
</plugins>
<pluginManagement>
<plugins/>
</pluginManagement>
</build>
</project>
</project>
333 changes: 333 additions & 0 deletions core/src/test/java/com/google/adk/agents/BaseAgentFindAgentTest.java
Original file line number Diff line number Diff line change
@@ -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<? extends BaseAgent> subAgents,
List<? extends BeforeAgentCallback> beforeAgentCallback,
List<? extends AfterAgentCallback> afterAgentCallback) {
super(name, description, subAgents, beforeAgentCallback, afterAgentCallback);
}

@Override
protected Flowable<Event> runAsyncImpl(InvocationContext invocationContext) {
return Flowable.empty();
}

@Override
protected Flowable<Event> 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.");
}

}
Loading