@@ -2,6 +2,7 @@ package com.embabel.hub
22
33// import org.springframework.ai.mcp.client.autoconfigure.McpClientAutoConfiguration
44import com.embabel.guide.Neo4jPropertiesInitializer
5+ import com.embabel.guide.chat.service.ThreadService
56import com.embabel.guide.domain.GuideUser
67import com.embabel.guide.domain.GuideUserRepository
78import com.fasterxml.jackson.databind.ObjectMapper
@@ -18,6 +19,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
1819import org.springframework.test.context.ActiveProfiles
1920import org.springframework.test.context.ContextConfiguration
2021import org.springframework.test.web.servlet.MockMvc
22+ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
2123import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
2224import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
2325import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@@ -43,6 +45,9 @@ class HubApiControllerTest {
4345 @Autowired
4446 lateinit var jwtTokenService: JwtTokenService
4547
48+ @Autowired
49+ lateinit var threadService: ThreadService
50+
4651 private val passwordEncoder = BCryptPasswordEncoder ()
4752
4853 @BeforeEach
@@ -524,4 +529,84 @@ class HubApiControllerTest {
524529 .andExpect(jsonPath(" $.token" ).exists())
525530 .andExpect(jsonPath(" $.username" ).value(" test_specialchar" ))
526531 }
532+
533+ // ========== Threads Tests ==========
534+
535+ @Test
536+ fun `GET threads should return list of threads for authenticated user` () {
537+ // Given - Register and login a user
538+ val registerRequest = UserRegistrationRequest (
539+ userDisplayName = " Thread Test User" ,
540+ username = " test_threaduser" ,
541+ 542+ password = " SecurePassword123!" ,
543+ passwordConfirmation = " SecurePassword123!"
544+ )
545+ val registerResult = mockMvc.perform(
546+ post(" /api/hub/register" )
547+ .contentType(MediaType .APPLICATION_JSON )
548+ .content(objectMapper.writeValueAsString(registerRequest))
549+ )
550+ .andExpect(status().isOk)
551+ .andReturn()
552+
553+ val createdUser = objectMapper.readValue(registerResult.response.contentAsString, GuideUser ::class .java)
554+ val token = createdUser.webUser?.refreshToken ? : fail(" Expected refresh token" )
555+
556+ // Create a thread directly (since async welcome thread may not be ready)
557+ threadService.createWelcomeThreadWithMessage(
558+ ownerId = createdUser.core.id,
559+ welcomeMessage = " Test welcome message"
560+ )
561+
562+ // When - Get threads with auth token
563+ mockMvc.perform(
564+ get(" /api/hub/threads" )
565+ .header(" Authorization" , " Bearer $token " )
566+ )
567+ .andExpect(status().isOk)
568+ .andExpect(jsonPath(" $" ).isArray)
569+ .andExpect(jsonPath(" $[0].id" ).exists())
570+ .andExpect(jsonPath(" $[0].title" ).value(" Welcome" ))
571+ }
572+
573+ @Test
574+ fun `GET threads should return 403 when not authenticated` () {
575+ // When & Then - No auth header (Spring Security returns 403 Forbidden)
576+ mockMvc.perform(get(" /api/hub/threads" ))
577+ .andExpect(status().isForbidden)
578+ }
579+
580+ @Test
581+ fun `GET threads should return empty list when user has no threads` () {
582+ // Given - Register a user but don't create any threads
583+ val registerRequest = UserRegistrationRequest (
584+ userDisplayName = " No Threads User" ,
585+ username = " test_nothreadsuser" ,
586+ 587+ password = " SecurePassword123!" ,
588+ passwordConfirmation = " SecurePassword123!"
589+ )
590+ val registerResult = mockMvc.perform(
591+ post(" /api/hub/register" )
592+ .contentType(MediaType .APPLICATION_JSON )
593+ .content(objectMapper.writeValueAsString(registerRequest))
594+ )
595+ .andExpect(status().isOk)
596+ .andReturn()
597+
598+ val createdUser = objectMapper.readValue(registerResult.response.contentAsString, GuideUser ::class .java)
599+ val token = createdUser.webUser?.refreshToken ? : fail(" Expected refresh token" )
600+
601+ // Note: The async welcome thread might not be created yet, which is fine for this test
602+ // We're testing that the endpoint works and returns an array (possibly empty)
603+
604+ // When - Get threads with auth token
605+ mockMvc.perform(
606+ get(" /api/hub/threads" )
607+ .header(" Authorization" , " Bearer $token " )
608+ )
609+ .andExpect(status().isOk)
610+ .andExpect(jsonPath(" $" ).isArray)
611+ }
527612}
0 commit comments