Skip to content

Commit 29bec3e

Browse files
authored
test: rewrite UTs related to agent resolution in URI handling (#203)
Inspired by coder/jetbrains-coder@5f0e363 which took a while to debug and understand. This rewrite arguably provides better test names, better data setup with cleaner descriptions.
1 parent b316d1d commit 29bec3e

File tree

1 file changed

+147
-90
lines changed

1 file changed

+147
-90
lines changed

src/test/kotlin/com/coder/toolbox/util/CoderProtocolHandlerTest.kt

Lines changed: 147 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,27 @@ import kotlinx.coroutines.CoroutineScope
2121
import kotlinx.coroutines.channels.Channel
2222
import kotlinx.coroutines.flow.MutableStateFlow
2323
import kotlinx.coroutines.runBlocking
24-
import org.junit.jupiter.api.DisplayName
2524
import java.util.UUID
2625
import kotlin.test.Test
2726
import kotlin.test.assertEquals
2827
import kotlin.test.assertNull
2928

3029
internal class CoderProtocolHandlerTest {
30+
31+
private companion object {
32+
val AGENT_RIKER = AgentTestData(name = "Riker", id = "9a920eee-47fb-4571-9501-e4b3120c12f2")
33+
val AGENT_BILL = AgentTestData(name = "Bill", id = "fb3daea4-da6b-424d-84c7-36b90574cfef")
34+
val AGENT_BOB = AgentTestData(name = "Bob", id = "b0e4c54d-9ba9-4413-8512-11ca1e826a24")
35+
36+
val ALL_AGENTS = mapOf(
37+
AGENT_BOB.name to AGENT_BOB.id,
38+
AGENT_BILL.name to AGENT_BILL.id,
39+
AGENT_RIKER.name to AGENT_RIKER.id
40+
)
41+
42+
val SINGLE_AGENT = mapOf(AGENT_BOB.name to AGENT_BOB.id)
43+
}
44+
3145
private val context = CoderToolboxContext(
3246
mockk<ToolboxUi>(relaxed = true),
3347
mockk<EnvironmentUiPageManager>(),
@@ -51,128 +65,171 @@ internal class CoderProtocolHandlerTest {
5165
MutableStateFlow(false)
5266
)
5367

54-
private val agents =
55-
mapOf(
56-
"agent_name_bob" to "b0e4c54d-9ba9-4413-8512-11ca1e826a24",
57-
"agent_name_bill" to "fb3daea4-da6b-424d-84c7-36b90574cfef",
58-
"agent_name_riker" to "9a920eee-47fb-4571-9501-e4b3120c12f2",
59-
)
60-
private val agentBob =
61-
mapOf(
62-
"agent_name_bob" to "b0e4c54d-9ba9-4413-8512-11ca1e826a24",
63-
)
64-
6568
@Test
66-
@DisplayName("given a ws with multiple agents, expect the correct agent to be resolved if it matches the agent_name query param")
67-
fun getMatchingAgent() {
68-
val ws = DataGen.workspace("ws", agents = agents)
69-
70-
val tests =
71-
listOf(
72-
Pair(
73-
mapOf("agent_name" to "agent_name_riker"),
74-
"9a920eee-47fb-4571-9501-e4b3120c12f2"
75-
),
76-
Pair(
77-
mapOf("agent_name" to "agent_name_bill"),
78-
"fb3daea4-da6b-424d-84c7-36b90574cfef"
79-
),
80-
Pair(
81-
mapOf("agent_name" to "agent_name_bob"),
82-
"b0e4c54d-9ba9-4413-8512-11ca1e826a24"
83-
)
69+
fun `given a workspace with multiple agents when getMatchingAgent is called with a valid agent name then it correctly resolves resolves an agent`() {
70+
val ws = DataGen.workspace("ws", agents = ALL_AGENTS)
71+
72+
val testCases = listOf(
73+
AgentMatchTestCase(
74+
"resolves agent with name Riker",
75+
mapOf("agent_name" to AGENT_RIKER.name),
76+
AGENT_RIKER.uuid
77+
),
78+
AgentMatchTestCase(
79+
"resolves agent with name Bill",
80+
mapOf("agent_name" to AGENT_BILL.name),
81+
AGENT_BILL.uuid
82+
),
83+
AgentMatchTestCase(
84+
"resolves agent with name Bob",
85+
mapOf("agent_name" to AGENT_BOB.name),
86+
AGENT_BOB.uuid
8487
)
88+
)
89+
8590
runBlocking {
86-
tests.forEach {
87-
assertEquals(UUID.fromString(it.second), protocolHandler.getMatchingAgent(it.first, ws)?.id)
91+
testCases.forEach { testCase ->
92+
assertEquals(
93+
testCase.expectedAgentId,
94+
protocolHandler.getMatchingAgent(testCase.params, ws)?.id,
95+
"Failed: ${testCase.description}"
96+
)
8897
}
8998
}
9099
}
91100

92101
@Test
93-
@DisplayName("given a ws with only multiple agents expect the agent resolution to fail if none match the agent_name query param")
94-
fun failsToGetMatchingAgent() {
95-
val ws = DataGen.workspace("ws", agents = agents)
96-
val tests =
97-
listOf(
98-
Triple(emptyMap(), MissingArgumentException::class, "Unable to determine"),
99-
Triple(mapOf("agent_name" to ""), MissingArgumentException::class, "Unable to determine"),
100-
Triple(mapOf("agent_name" to null), MissingArgumentException::class, "Unable to determine"),
101-
Triple(mapOf("agent_name" to "not-an-agent-name"), IllegalArgumentException::class, "agent with ID"),
102-
Triple(
103-
mapOf("agent_name" to "agent_name_homer"),
104-
IllegalArgumentException::class,
105-
"agent with name"
106-
)
102+
fun `given a workspace with multiple agents when getMatchingAgent is called with invalid agent names then no agent is resolved`() {
103+
val ws = DataGen.workspace("ws", agents = ALL_AGENTS)
104+
105+
val testCases = listOf(
106+
AgentNullResultTestCase(
107+
"empty parameters (i.e. no agent name) does not return any agent",
108+
emptyMap()
109+
),
110+
AgentNullResultTestCase(
111+
"empty agent_name does not return any agent",
112+
mapOf("agent_name" to "")
113+
),
114+
AgentNullResultTestCase(
115+
"null agent_name does not return any agent",
116+
mapOf("agent_name" to null)
117+
),
118+
AgentNullResultTestCase(
119+
"non-existent agent does not return any agent",
120+
mapOf("agent_name" to "agent_name_homer")
121+
),
122+
AgentNullResultTestCase(
123+
"UUID instead of name does not return any agent",
124+
mapOf("agent_name" to "not-an-agent-name")
107125
)
126+
)
127+
108128
runBlocking {
109-
tests.forEach {
110-
assertNull(protocolHandler.getMatchingAgent(it.first, ws)?.id)
129+
testCases.forEach { testCase ->
130+
assertNull(
131+
protocolHandler.getMatchingAgent(testCase.params, ws)?.id,
132+
"Failed: ${testCase.description}"
133+
)
111134
}
112135
}
113136
}
114137

115138
@Test
116-
@DisplayName("given a ws with only one agent, the agent is selected even when agent_name query param was not provided")
117-
fun getsFirstAgentWhenOnlyOne() {
118-
val ws = DataGen.workspace("ws", agents = agentBob)
119-
val tests =
120-
listOf(
139+
fun `given a workspace with a single agent when getMatchingAgent is called with an empty agent name then the default agent is resolved`() {
140+
val ws = DataGen.workspace("ws", agents = SINGLE_AGENT)
141+
142+
val testCases = listOf(
143+
AgentMatchTestCase(
144+
"empty parameters (i.e. no agent name) auto-selects the one and only agent available",
121145
emptyMap(),
146+
AGENT_BOB.uuid
147+
),
148+
AgentMatchTestCase(
149+
"empty agent_name auto-selects the one and only agent available",
122150
mapOf("agent_name" to ""),
123-
mapOf("agent_name" to null)
151+
AGENT_BOB.uuid
152+
),
153+
AgentMatchTestCase(
154+
"null agent_name auto-selects the one and only agent available",
155+
mapOf("agent_name" to null),
156+
AGENT_BOB.uuid
124157
)
158+
)
159+
125160
runBlocking {
126-
tests.forEach {
161+
testCases.forEach { testCase ->
127162
assertEquals(
128-
UUID.fromString("b0e4c54d-9ba9-4413-8512-11ca1e826a24"),
129-
protocolHandler.getMatchingAgent(
130-
it,
131-
ws,
132-
)?.id,
163+
testCase.expectedAgentId,
164+
protocolHandler.getMatchingAgent(testCase.params, ws)?.id,
165+
"Failed: ${testCase.description}"
133166
)
134167
}
135168
}
136169
}
137170

138171
@Test
139-
@DisplayName("given a ws with only one agent, the agent is NOT selected when agent_name query param was provided but does not match")
140-
fun failsToGetAgentWhenOnlyOne() {
141-
val wsWithAgentBob = DataGen.workspace("ws", agents = agentBob)
142-
val tests =
143-
listOf(
144-
Triple(
145-
mapOf("agent_name" to "agent_name_garfield"),
146-
IllegalArgumentException::class,
147-
"agent with name"
148-
),
149-
)
172+
fun `given a workspace with a single agent when getMatchingAgent is called with an invalid agent name then no agent is resolved`() {
173+
val ws = DataGen.workspace("ws", agents = SINGLE_AGENT)
174+
175+
val testCase = AgentNullResultTestCase(
176+
"non-matching agent_name with single agent",
177+
mapOf("agent_name" to "agent_name_garfield")
178+
)
179+
150180
runBlocking {
151-
tests.forEach {
152-
assertNull(protocolHandler.getMatchingAgent(it.first, wsWithAgentBob))
153-
}
181+
assertNull(
182+
protocolHandler.getMatchingAgent(testCase.params, ws),
183+
"Failed: ${testCase.description}"
184+
)
154185
}
155186
}
156187

157188
@Test
158-
@DisplayName("fails to resolve any agent when the workspace has no agents")
159-
fun failsToGetAgentWhenWorkspaceHasNoAgents() {
160-
val wsWithoutAgents = DataGen.workspace("ws")
161-
val tests =
162-
listOf(
163-
Triple(emptyMap(), IllegalArgumentException::class, "has no agents"),
164-
Triple(mapOf("agent_name" to ""), IllegalArgumentException::class, "has no agents"),
165-
Triple(mapOf("agent_name" to null), IllegalArgumentException::class, "has no agents"),
166-
Triple(
167-
mapOf("agent_name" to "agent_name_riker"),
168-
IllegalArgumentException::class,
169-
"has no agents"
170-
),
189+
fun `given a workspace with no agent when getMatchingAgent is called then no agent is resolved`() {
190+
val ws = DataGen.workspace("ws")
191+
192+
val testCases = listOf(
193+
AgentNullResultTestCase(
194+
"empty parameters (i.e. no agent name) does not return any agent",
195+
emptyMap()
196+
),
197+
AgentNullResultTestCase(
198+
"empty agent_name does not return any agent",
199+
mapOf("agent_name" to "")
200+
),
201+
AgentNullResultTestCase(
202+
"null agent_name does not return any agent",
203+
mapOf("agent_name" to null)
204+
),
205+
AgentNullResultTestCase(
206+
"valid agent_name does not return any agent",
207+
mapOf("agent_name" to AGENT_RIKER.name)
171208
)
209+
)
210+
172211
runBlocking {
173-
tests.forEach {
174-
assertNull(protocolHandler.getMatchingAgent(it.first, wsWithoutAgents))
212+
testCases.forEach { testCase ->
213+
assertNull(
214+
protocolHandler.getMatchingAgent(testCase.params, ws),
215+
"Failed: ${testCase.description}"
216+
)
175217
}
176218
}
177219
}
178-
}
220+
221+
internal data class AgentTestData(val name: String, val id: String) {
222+
val uuid: UUID get() = UUID.fromString(id)
223+
}
224+
225+
internal data class AgentMatchTestCase(
226+
val description: String,
227+
val params: Map<String, String?>,
228+
val expectedAgentId: UUID
229+
)
230+
231+
internal data class AgentNullResultTestCase(
232+
val description: String,
233+
val params: Map<String, String?>
234+
)
235+
}

0 commit comments

Comments
 (0)