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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// ********RoostGPT********
/*
Test generated by RoostGPT for test unit-java-adk using AI Type Azure Open AI and AI Model gpt-5

ROOST_METHOD_HASH=content_f95ec3ddc9
ROOST_METHOD_SIG_HASH=content_accc65ce1a


Scenario 1: Returns the same Content instance that was supplied at construction

Details:
TestName: returnsSameContentInstance
Description: Verify that the content() method returns the exact Content object that was used to build the AutoValue_MemoryEntry instance (reference identity, not a copy).

Execution:
Arrange: Create a valid Content instance (e.g., a concrete instance or a simple test double) and build a MemoryEntry via the Builder with that Content.
Act: Call content() on the built MemoryEntry.
Assert: Use JUnit assertions to confirm that the returned Content is the same object instance as the one provided during construction (reference equality).

Validation:
This assertion verifies that content() is a simple accessor returning the internal field without copying or transforming it. It ensures the method exposes the exact Content reference stored in the entry, which is important for consumers relying on object identity or avoiding unnecessary allocations.

*/

// ********RoostGPT********

package com.google.adk.memory;

import static org.junit.jupiter.api.Assertions.*;

import com.google.genai.types.Content;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import javax.annotation.Nullable;
import javax.annotation.processing.Generated;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

@Generated("AutoValueMemoryEntryContentTest")
public abstract class AutoValueMemoryEntryContentTest extends MemoryEntry {

// Intentionally left abstract as per requirement.

}

class AutoValueMemoryEntryContentTestCases {

private Content defaultContent;

@BeforeEach
public void setUp() {
defaultContent = Mockito.mock(Content.class);
}

@Test
@Tag("valid")
public void testReturnsSameContentInstance() {
MemoryEntry entry = (MemoryEntry) createEntry(defaultContent, null, null);
Content actual = (Content) entry.content();
assertSame(
(Content) defaultContent,
(Content) actual,
"content() should return the same Content instance provided to constructor");
}

@Test
@Tag("valid")
public void testContentNotNullWhenConstructedWithNonNullContent() {
MemoryEntry entry = (MemoryEntry) createEntry(defaultContent, null, null);
Content actual = (Content) entry.content();
assertNotNull(
(Object) actual, "content() should not return null when constructed with non-null Content");
}

@Test
@Tag("invalid")
public void testConstructorWithNullContent_throwsNullPointerException() {
assertThrows(
NullPointerException.class,
() -> {
createEntry(null, null, null);
});
}

@Test
@Tag("boundary")
public void testReturnsSameContentInstance_withTimestampAndAuthorVariants() {
Content content = Mockito.mock(Content.class);
// TODO: Change author if needed for specific scenario
@Nullable String author = null;
// Using a static ISO-8601 timestamp example
String timestamp = "2020-01-01T00:00:00Z";
MemoryEntry entry = (MemoryEntry) createEntry(content, author, timestamp);
Content actual = (Content) entry.content();
assertSame(
(Content) content,
(Content) actual,
"content() should return the same instance irrespective of author/timestamp values");
}

private AutoValue_MemoryEntry createEntry(
@Nullable Content content, @Nullable String author, @Nullable String timestamp) {
try {
Constructor<AutoValue_MemoryEntry> ctor =
AutoValue_MemoryEntry.class.getDeclaredConstructor(
Content.class, String.class, String.class);
ctor.setAccessible(true);
return ctor.newInstance(content, author, timestamp);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
}
if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(cause);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
//This test file is marked invalid as it contains compilation errors. Change the extension to of this file to .java, to manually edit its contents
/*
* 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 unit-java-adk using AI Type Azure Open AI and AI Model gpt-5

ROOST_METHOD_HASH=addSessionToMemory_8a630adf5c
ROOST_METHOD_SIG_HASH=addSessionToMemory_3e3003d0a0

Scenario 1: Successfully stores a session with events that have non-empty parts

Details:
TestName: storesSessionWithEventsHavingNonEmptyParts
Description: Verifies that addSessionToMemory stores a session whose events include content with present, non-empty parts. Confirms that the returned Completable completes without errors and that the stored events are discoverable via searchMemory.

Execution:
Arrange: Create a Session with appName "appA", userId "user1", session id "s1", and events where at least one event has content().isPresent() and parts().isPresent() with a non-empty list containing a Part with non-empty text like "hello world".
Act: Invoke addSessionToMemory(session) and await the Completable to complete. Then call searchMemory("appA", "user1", "hello") to retrieve memories.
Assert: Assert the Completable completes successfully. Assert that searchMemory returns at least one MemoryEntry with content containing the word "hello".

Validation:
Confirms that events meeting the filter (content present, parts present and non-empty) are retained and can be retrieved through searchMemory. Ensures the Completable signals completion, indicating the write to memory occurred.

*/

// ********RoostGPT********

package com.google.adk.memory;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.google.adk.events.Event;
import com.google.genai.types.Content;
import com.google.adk.sessions.Session;
import com.google.genai.types.Part;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.observers.TestObserver;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.junit.jupiter.api.*;
import static com.google.common.collect.ImmutableList.toImmutableList;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import io.reactivex.rxjava3.core.Single;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class InMemoryMemoryServiceAddSessionToMemoryTest {
private InMemoryMemoryService memoryService;
@BeforeEach
public void setUp() {
memoryService = new InMemoryMemoryService();
}
@Test
@Tag("integration")
public void testStoresSessionWithEventsHavingNonEmptyParts() {
// Arrange
String appName = "appA";
String userId = "user1";
String sessionId = "s1";
Session session = Mockito.mock(Session.class);
Mockito.when(session.appName()).thenReturn(appName);
Mockito.when(session.userId()).thenReturn(userId);
Mockito.when(session.id()).thenReturn(sessionId);
// Event with non-empty parts
Event eventWithText = Mockito.mock(Event.class);
Content contentWithText = Mockito.mock(Content.class);
Part partWithText = Mockito.mock(Part.class);
Mockito.when(partWithText.text()).thenReturn((Optional<String>) Optional.of("hello world"));
Mockito.when(contentWithText.parts()).thenReturn((Optional<List<Part>>) Optional.of((List<Part>) List.of(partWithText)));
Mockito.when(eventWithText.content()).thenReturn((Optional<Content>) Optional.of(contentWithText));
Mockito.when(eventWithText.author()).thenReturn("user");
Mockito.when(eventWithText.timestamp()).thenReturn(1_710_000_000L);
// Event with empty parts should be filtered out
Event eventWithEmptyParts = Mockito.mock(Event.class);
Content emptyContent = Mockito.mock(Content.class);
Mockito.when(emptyContent.parts()).thenReturn((Optional<List<Part>>) Optional.of((List<Part>) Collections.emptyList()));
Mockito.when(eventWithEmptyParts.content()).thenReturn((Optional<Content>) Optional.of(emptyContent));
Mockito.when(session.events()).thenReturn((List<Event>) List.of(eventWithText, eventWithEmptyParts));
// Act
Completable addCompletable = memoryService.addSessionToMemory(session);
TestObserver<Void> addObserver = addCompletable.test();
// Assert add completion
addObserver.assertComplete();
addObserver.assertNoErrors();
// Act - search memory
SearchMemoryResponse response = (SearchMemoryResponse) memoryService.searchMemory(appName, userId, "hello").blockingGet();
// Assert - memories should include the event with "hello"
List<MemoryEntry> memories = (List<MemoryEntry>) response.memories();
assertFalse(((List<MemoryEntry>) memories).isEmpty());
MemoryEntry first = ((List<MemoryEntry>) memories).get(0);
Content content = (Content) first.content();
Optional<List<Part>> partsOpt = (Optional<List<Part>>) content.parts();
assertTrue(((Optional<List<Part>>) partsOpt).isPresent());
List<Part> parts = ((Optional<List<Part>>) partsOpt).get();
assertFalse(((List<Part>) parts).isEmpty());
Optional<String> txt = ((Part) parts.get(0)).text();
assertTrue(((Optional<String>) txt).isPresent());
assertTrue(((String) txt.get()).toLowerCase(Locale.ROOT).contains("hello"));
}
@Test
@Tag("boundary")
public void testDoesNotStoreEventsWithEmptyParts() {
// Arrange
String appName = "appB";
String userId = "user2";
String sessionId = "s2";
Session session = Mockito.mock(Session.class);
Mockito.when(session.appName()).thenReturn(appName);
Mockito.when(session.userId()).thenReturn(userId);
Mockito.when(session.id()).thenReturn(sessionId);
// Event with empty parts
Event eventWithEmptyParts = Mockito.mock(Event.class);
Content emptyContent = Mockito.mock(Content.class);
Mockito.when(emptyContent.parts()).thenReturn((Optional<List<Part>>) Optional.of((List<Part>) Collections.emptyList()));
Mockito.when(eventWithEmptyParts.content()).thenReturn((Optional<Content>) Optional.of(emptyContent));
Mockito.when(session.events()).thenReturn((List<Event>) List.of(eventWithEmptyParts));
// Act
Completable addCompletable = memoryService.addSessionToMemory(session);
TestObserver<Void> addObserver = addCompletable.test();
// Assert add completion
addObserver.assertComplete();
addObserver.assertNoErrors();
// Search for any term should yield no memories as event parts were empty
SearchMemoryResponse response = (SearchMemoryResponse) memoryService.searchMemory(appName, userId, "anything").blockingGet();
// Assert
List<MemoryEntry> memories = (List<MemoryEntry>) response.memories();
assertTrue(((List<MemoryEntry>) memories).isEmpty());
}
@Test
@Tag("invalid")
public void testAddSessionToMemory_withNullSession_emitsError() {
// Arrange
Session nullSession = null; // TODO: If test requires different invalid input, adjust accordingly.
// Act
Completable addCompletable = memoryService.addSessionToMemory(nullSession);
// Assert
addCompletable
.test()
.assertError(throwable -> throwable instanceof NullPointerException);
}
}
Loading