|
20 | 20 | import com.google.adk.events.Event; |
21 | 21 | import com.google.adk.events.EventActions; |
22 | 22 | import io.reactivex.rxjava3.core.Single; |
| 23 | +import java.lang.reflect.Field; |
23 | 24 | import java.time.Instant; |
24 | 25 | import java.util.HashMap; |
25 | 26 | import java.util.Optional; |
@@ -266,4 +267,54 @@ public void sequentialAgents_shareTempState() { |
266 | 267 | assertThat(retrievedSession.state()).doesNotContainKey("temp:agent1_output"); |
267 | 268 | assertThat(retrievedSession.state()).containsEntry("temp:agent2_output", "processed_data"); |
268 | 269 | } |
| 270 | + |
| 271 | + @Test |
| 272 | + public void deleteSession_cleansUpEmptyParentMaps() throws Exception { |
| 273 | + InMemorySessionService sessionService = new InMemorySessionService(); |
| 274 | + |
| 275 | + Session session = sessionService.createSession("app-name", "user-id").blockingGet(); |
| 276 | + |
| 277 | + sessionService.deleteSession(session.appName(), session.userId(), session.id()).blockingAwait(); |
| 278 | + |
| 279 | + // Use reflection to access the private 'sessions' field |
| 280 | + Field field = InMemorySessionService.class.getDeclaredField("sessions"); |
| 281 | + field.setAccessible(true); |
| 282 | + ConcurrentMap<?, ?> sessions = (ConcurrentMap<?, ?>) field.get(sessionService); |
| 283 | + |
| 284 | + // After deleting the only session for "user-id" under "app-name", |
| 285 | + // both the userId map and the appName map should have been removed |
| 286 | + assertThat(sessions).isEmpty(); |
| 287 | + } |
| 288 | + |
| 289 | + @Test |
| 290 | + public void deleteSession_doesNotRemoveUserMapWhenOtherSessionsExist() throws Exception { |
| 291 | + InMemorySessionService sessionService = new InMemorySessionService(); |
| 292 | + |
| 293 | + Session session1 = sessionService.createSession("app-name", "user-id").blockingGet(); |
| 294 | + Session session2 = sessionService.createSession("app-name", "user-id").blockingGet(); |
| 295 | + |
| 296 | + // Delete only one of the two sessions |
| 297 | + sessionService |
| 298 | + .deleteSession(session1.appName(), session1.userId(), session1.id()) |
| 299 | + .blockingAwait(); |
| 300 | + |
| 301 | + // session2 should still be retrievable |
| 302 | + assertThat( |
| 303 | + sessionService |
| 304 | + .getSession(session2.appName(), session2.userId(), session2.id(), Optional.empty()) |
| 305 | + .blockingGet()) |
| 306 | + .isNotNull(); |
| 307 | + |
| 308 | + // The userId entry should still exist (not pruned) because session2 remains |
| 309 | + Field field = InMemorySessionService.class.getDeclaredField("sessions"); |
| 310 | + field.setAccessible(true); |
| 311 | + @SuppressWarnings("unchecked") |
| 312 | + ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, ?>>> sessions = |
| 313 | + (ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, ?>>>) |
| 314 | + field.get(sessionService); |
| 315 | + |
| 316 | + assertThat(sessions.get("app-name")).isNotNull(); |
| 317 | + assertThat(sessions.get("app-name").get("user-id")).isNotNull(); |
| 318 | + assertThat(sessions.get("app-name").get("user-id")).hasSize(1); |
| 319 | + } |
269 | 320 | } |
0 commit comments