@@ -66,6 +66,37 @@ def _factory(response_json: dict | None, status_code: int = 200) -> KAgentSessio
6666 return _factory
6767
6868
69+ @pytest .mark .asyncio
70+ async def test_create_session_passes_user_id_as_query_param ():
71+ """create_session must include user_id as a query param on POST /api/sessions.
72+
73+ Regression test for the SessionNotFoundError caused by a user_id mismatch:
74+ the controller's UnsecureAuthenticator resolves identity from the query param
75+ (or X-User-Id header), not the JSON body. Without the query param the
76+ controller falls back to "admin@kagent.dev" for the session create, while
77+ every subsequent GET uses the A2A-derived user_id — guaranteeing a 404.
78+ Fixes: https://github.com/kagent-dev/kagent/issues/1882
79+ """
80+ mock_response = MagicMock (spec = httpx .Response )
81+ mock_response .status_code = 201
82+ mock_response .json .return_value = {"data" : {"id" : "sess-1" , "user_id" : "A2A_USER_ctx123" }}
83+ mock_response .raise_for_status = MagicMock ()
84+
85+ client = MagicMock (spec = httpx .AsyncClient )
86+ client .post = AsyncMock (return_value = mock_response )
87+
88+ svc = KAgentSessionService (client )
89+ await svc .create_session (app_name = "my-agent" , user_id = "A2A_USER_ctx123" , session_id = "ctx123" )
90+
91+ client .post .assert_called_once ()
92+ call_kwargs = client .post .call_args .kwargs
93+ assert call_kwargs .get ("params" , {}).get ("user_id" ) == "A2A_USER_ctx123" , (
94+ f"Expected params['user_id']='A2A_USER_ctx123', got params={ call_kwargs .get ('params' )!r} . "
95+ "Without this query param the controller's UnsecureAuthenticator falls back "
96+ "to 'admin@kagent.dev', causing a SessionNotFoundError on subsequent lookups."
97+ )
98+
99+
69100@pytest .mark .asyncio
70101async def test_get_session_returns_none_on_404 (mock_client ):
71102 """A 404 response returns None without raising."""
0 commit comments