Skip to content

Commit fe86a2c

Browse files
committed
refactor ProjectContextProvider and add tests
1 parent 6955ef9 commit fe86a2c

File tree

3 files changed

+263
-100
lines changed

3 files changed

+263
-100
lines changed

plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonq/workspace/context/ProjectContextProviderTest.kt

Lines changed: 148 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,31 @@
33

44
package software.aws.toolkits.jetbrains.services.amazonq.workspace.context
55

6+
import com.github.tomakehurst.wiremock.client.WireMock.aResponse
7+
import com.github.tomakehurst.wiremock.client.WireMock.any
8+
import com.github.tomakehurst.wiremock.client.WireMock.stubFor
9+
import com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo
10+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig
11+
import com.github.tomakehurst.wiremock.http.Body
12+
import com.github.tomakehurst.wiremock.junit.WireMockRule
613
import com.intellij.openapi.project.Project
714
import kotlinx.coroutines.test.TestScope
815
import kotlinx.coroutines.test.runTest
16+
import org.assertj.core.api.Assertions.assertThat
917
import org.junit.Before
1018
import org.junit.Rule
19+
import org.junit.jupiter.api.assertThrows
1120
import org.mockito.kotlin.any
12-
import org.mockito.kotlin.mock
21+
import org.mockito.kotlin.doReturn
22+
import org.mockito.kotlin.spy
23+
import org.mockito.kotlin.stub
1324
import org.mockito.kotlin.times
1425
import org.mockito.kotlin.verify
1526
import org.mockito.kotlin.whenever
1627
import software.aws.toolkits.jetbrains.services.amazonq.project.EncoderServer
28+
import software.aws.toolkits.jetbrains.services.amazonq.project.LspMessage
1729
import software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextProvider
30+
import software.aws.toolkits.jetbrains.services.amazonq.project.RelevantDocument
1831
import software.aws.toolkits.jetbrains.utils.rules.CodeInsightTestFixtureRule
1932
import software.aws.toolkits.jetbrains.utils.rules.JavaCodeInsightTestFixtureRule
2033
import java.net.ConnectException
@@ -25,15 +38,102 @@ class ProjectContextProviderTest {
2538
@JvmField
2639
val projectRule: CodeInsightTestFixtureRule = JavaCodeInsightTestFixtureRule()
2740

41+
@Rule
42+
@JvmField
43+
val wireMock: WireMockRule = createMockServer()
44+
2845
private val project: Project
2946
get() = projectRule.project
3047

31-
private val encoderServer: EncoderServer = mock()
48+
private lateinit var encoderServer: EncoderServer
3249
private lateinit var sut: ProjectContextProvider
3350

3451
@Before
3552
fun setup() {
53+
encoderServer = spy(EncoderServer(project))
54+
encoderServer.stub { on { port } doReturn wireMock.port() }
55+
3656
sut = ProjectContextProvider(project, encoderServer, TestScope())
57+
58+
// initialization
59+
stubFor(any(urlPathEqualTo("/initialize")).willReturn(aResponse().withStatus(200).withResponseBody(Body("initialize response"))))
60+
61+
// build index
62+
stubFor(any(urlPathEqualTo("/indexFiles")).willReturn(aResponse().withStatus(200).withResponseBody(Body("initialize response"))))
63+
64+
// update index
65+
stubFor(any(urlPathEqualTo("/updateIndex")).willReturn(aResponse().withStatus(200).withResponseBody(Body("initialize response"))))
66+
67+
// query
68+
stubFor(
69+
any(urlPathEqualTo("/query")).willReturn(
70+
aResponse()
71+
.withStatus(200)
72+
.withResponseBody(Body(validQueryChatResponse))
73+
)
74+
)
75+
76+
stubFor(
77+
any(urlPathEqualTo("/getUsage"))
78+
.willReturn(
79+
aResponse()
80+
.withStatus(200)
81+
.withResponseBody(Body(validGetUsageResponse))
82+
)
83+
)
84+
}
85+
86+
@Test
87+
fun `Lsp endpoint are correct`() {
88+
assertThat(LspMessage.Initialize.endpoint).isEqualTo("initialize")
89+
assertThat(LspMessage.Index.endpoint).isEqualTo("indexFiles")
90+
assertThat(LspMessage.QueryChat.endpoint).isEqualTo("query")
91+
assertThat(LspMessage.GetUsageMetrics.endpoint).isEqualTo("getUsage")
92+
}
93+
94+
@Test
95+
fun `query chat should return empty if result set non deserializable`() = runTest {
96+
stubFor(
97+
any(urlPathEqualTo("/query")).willReturn(
98+
aResponse().withStatus(200).withResponseBody(
99+
Body(
100+
"""
101+
[
102+
"foo", "bar"
103+
]
104+
""".trimIndent()
105+
)
106+
)
107+
)
108+
)
109+
110+
assertThrows<Exception> {
111+
sut.query("foo")
112+
}
113+
}
114+
115+
@Test
116+
fun `query chat should return deserialized relevantDocument`() = runTest {
117+
val r = sut.query("foo")
118+
assertThat(r).hasSize(2)
119+
assertThat(r[0]).isEqualTo(
120+
RelevantDocument(
121+
"relativeFilePath1",
122+
"context1"
123+
)
124+
)
125+
assertThat(r[1]).isEqualTo(
126+
RelevantDocument(
127+
"relativeFilePath2",
128+
"context2"
129+
)
130+
)
131+
}
132+
133+
@Test
134+
fun `get usage should return memory, cpu usage`() = runTest {
135+
val r = sut.getUsage()
136+
assertThat(r).isEqualTo(ProjectContextProvider.Usage(123, 456))
37137
}
38138

39139
@Test
@@ -57,4 +157,50 @@ class ProjectContextProviderTest {
57157
}
58158
verify(encoderServer, times(1)).encrypt(any())
59159
}
160+
161+
private fun createMockServer() = WireMockRule(wireMockConfig().dynamicPort())
60162
}
163+
164+
val validQueryChatResponse = """
165+
[
166+
{
167+
"filePath": "file1",
168+
"content": "content1",
169+
"id": "id1",
170+
"index": "index1",
171+
"vec": [
172+
"vec_1-1",
173+
"vec_1-2",
174+
"vec_1-3"
175+
],
176+
"context": "context1",
177+
"prev": "prev1",
178+
"next": "next1",
179+
"relativePath": "relativeFilePath1",
180+
"programmingLanguage": "language1"
181+
},
182+
{
183+
"filePath": "file2",
184+
"content": "content2",
185+
"id": "id2",
186+
"index": "index2",
187+
"vec": [
188+
"vec_2-1",
189+
"vec_2-2",
190+
"vec_2-3"
191+
],
192+
"context": "context2",
193+
"prev": "prev2",
194+
"next": "next2",
195+
"relativePath": "relativeFilePath2",
196+
"programmingLanguage": "language2"
197+
}
198+
]
199+
""".trimIndent()
200+
201+
val validGetUsageResponse = """
202+
{
203+
"memoryUsage":123,
204+
"cpuUsage":456
205+
}
206+
""".trimIndent()
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package software.aws.toolkits.jetbrains.services.amazonq.project
5+
6+
sealed interface LspMessage {
7+
val endpoint: String
8+
9+
data object Initialize : LspMessage {
10+
override val endpoint: String = "initialize"
11+
}
12+
13+
data object Index : LspMessage {
14+
override val endpoint: String = "indexFiles"
15+
}
16+
17+
data object UpdateIndex : LspMessage {
18+
override val endpoint: String = "updateIndex"
19+
}
20+
21+
data object QueryChat : LspMessage {
22+
override val endpoint: String = "query"
23+
}
24+
25+
data object GetUsageMetrics : LspMessage {
26+
override val endpoint: String = "getUsage"
27+
}
28+
}
29+
30+
interface LspRequest
31+
32+
data class IndexRequest(
33+
val filePaths: List<String>,
34+
val projectRoot: String,
35+
val refresh: Boolean,
36+
) : LspRequest
37+
38+
data class UpdateIndexRequest(
39+
val filePath: String,
40+
) : LspRequest
41+
42+
data class QueryChatRequest(
43+
val query: String,
44+
) : LspRequest
45+
46+
data class LspResponse(
47+
val responseCode: Int,
48+
val responseBody: String,
49+
)

0 commit comments

Comments
 (0)