Skip to content

Commit 21af16d

Browse files
Merge main into feature/q-dev-ux
2 parents f214cf7 + f009e6f commit 21af16d

File tree

1 file changed

+110
-140
lines changed

1 file changed

+110
-140
lines changed

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeFileScanTest.kt

Lines changed: 110 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,15 @@ package software.aws.toolkits.jetbrains.services.codewhisperer.codescan
55

66
import com.intellij.openapi.fileEditor.FileEditor
77
import com.intellij.openapi.fileEditor.FileEditorManager
8-
import com.intellij.openapi.vfs.VirtualFile
98
import com.intellij.psi.PsiFile
10-
import com.intellij.testFramework.replaceService
119
import kotlinx.coroutines.runBlocking
1210
import kotlinx.coroutines.test.runTest
1311
import org.apache.commons.codec.digest.DigestUtils
1412
import org.assertj.core.api.Assertions.assertThat
1513
import org.junit.Before
1614
import org.junit.Test
1715
import org.mockito.ArgumentMatchers.anyString
18-
import org.mockito.Mockito
1916
import org.mockito.Mockito.mock
20-
import org.mockito.Mockito.times
21-
import org.mockito.Mockito.`when`
22-
import org.mockito.internal.verification.Times
2317
import org.mockito.kotlin.any
2418
import org.mockito.kotlin.argumentCaptor
2519
import org.mockito.kotlin.doNothing
@@ -28,7 +22,9 @@ import org.mockito.kotlin.inOrder
2822
import org.mockito.kotlin.isNull
2923
import org.mockito.kotlin.spy
3024
import org.mockito.kotlin.stub
25+
import org.mockito.kotlin.times
3126
import org.mockito.kotlin.verify
27+
import org.mockito.kotlin.whenever
3228
import software.amazon.awssdk.awscore.exception.AwsErrorDetails
3329
import software.amazon.awssdk.services.codewhisperer.model.CodeWhispererException
3430
import software.amazon.awssdk.services.codewhispererruntime.model.CreateUploadUrlRequest
@@ -42,7 +38,6 @@ import software.aws.toolkits.jetbrains.utils.isInstanceOf
4238
import software.aws.toolkits.jetbrains.utils.isInstanceOfSatisfying
4339
import software.aws.toolkits.jetbrains.utils.rules.PythonCodeInsightTestFixtureRule
4440
import software.aws.toolkits.telemetry.CodewhispererLanguage
45-
import java.io.File
4641
import java.io.FileInputStream
4742
import java.lang.management.ManagementFactory
4843
import java.util.Base64
@@ -52,55 +47,19 @@ import kotlin.io.path.relativeTo
5247
import kotlin.test.assertNotNull
5348

5449
class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeInsightTestFixtureRule()) {
55-
private lateinit var psifile: PsiFile
56-
private lateinit var psifile2: PsiFile
57-
private lateinit var psifile3: PsiFile
58-
private lateinit var psifile4: PsiFile
59-
private lateinit var psifilePerformanceTest: PsiFile
60-
private lateinit var psifilePerformanceTest2: PsiFile
61-
private lateinit var file: File
62-
private lateinit var file2: File
63-
private lateinit var file3: File
64-
private lateinit var file4: File
65-
private lateinit var performanceTestfileWithPayload200KB: File
66-
private lateinit var performanceTestfileWithPayload150KB: File
67-
private lateinit var virtualFile3: VirtualFile
68-
private lateinit var virtualFile4: VirtualFile
69-
private lateinit var sessionConfigSpy: CodeScanSessionConfig
70-
private lateinit var sessionConfigSpy2: CodeScanSessionConfig
71-
private lateinit var sessionConfigSpy3: CodeScanSessionConfig
72-
private lateinit var sessionConfigSpy4: CodeScanSessionConfig
50+
private val codeScanName = UUID.randomUUID().toString()
7351
private val payloadContext = PayloadContext(CodewhispererLanguage.Python, 1, 1, 10, listOf(), 600, 200)
74-
private lateinit var codeScanSessionContext: CodeScanSessionContext
75-
private lateinit var codeScanSessionContext2: CodeScanSessionContext
76-
private lateinit var codeScanSessionContext3: CodeScanSessionContext
52+
53+
private lateinit var pyPsiFile: PsiFile
54+
private lateinit var ktPsiFile: PsiFile
55+
private lateinit var pySession: CodeScanSessionConfig
7756
private lateinit var codeScanSessionSpy: CodeWhispererCodeScanSession
78-
private lateinit var codeScanSessionSpy2: CodeWhispererCodeScanSession
79-
private lateinit var codeScanSessionSpy3: CodeWhispererCodeScanSession
80-
private val codeScanName = UUID.randomUUID().toString()
8157

8258
@Before
8359
override fun setup() {
8460
super.setup()
8561

86-
psifile2 = projectRule.fixture.addFileToProject(
87-
"/subtract.java",
88-
"""public class MathOperations {
89-
public static int subtract(int a, int b) {
90-
return a - b;
91-
}
92-
public static void main(String[] args) {
93-
int num1 = 10;
94-
int num2 = 5;
95-
int result = subtract(num1, num2);
96-
System.out.println(result);
97-
}
98-
}
99-
""".trimMargin()
100-
)
101-
file2 = psifile2.virtualFile.toNioPath().toFile()
102-
103-
psifile = projectRule.fixture.addFileToProject(
62+
pyPsiFile = projectRule.fixture.addFileToProject(
10463
"/test.py",
10564
"""import numpy as np
10665
import from module1 import helper
@@ -110,9 +69,8 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
11069
11170
""".trimMargin()
11271
)
113-
file = psifile.virtualFile.toNioPath().toFile()
11472

115-
psifile3 = projectRule.fixture.addFileToProject(
73+
ktPsiFile = projectRule.fixture.addFileToProject(
11674
"/test.kt",
11775
// write simple addition function in kotlin
11876
"""
@@ -124,96 +82,68 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
12482
}
12583
""".trimMargin()
12684
)
127-
virtualFile3 = psifile3.virtualFile
128-
file3 = virtualFile3.toNioPath().toFile()
12985

130-
psifile4 = projectRule.fixture.addFileToProject(
131-
"../test.java",
132-
"""
133-
public class Addition {
134-
public static void main(String[] args) {
135-
int a = 1;
136-
int b = 2;
137-
int c = a + b;
138-
System.out.println(c);
86+
projectRule.fixture.addFileToProject(
87+
"/subtract.java",
88+
"""public class MathOperations {
89+
public static int subtract(int a, int b) {
90+
return a - b;
13991
}
140-
}
141-
"""
142-
)
143-
virtualFile4 = psifile4.virtualFile
144-
file4 = virtualFile4.toNioPath().toFile()
145-
146-
// Create a 200KB file
147-
val content = "a".repeat(200 * 1024)
148-
psifilePerformanceTest = projectRule.fixture.addFileToProject("test.txt", content)
149-
performanceTestfileWithPayload200KB = psifilePerformanceTest.virtualFile.toNioPath().toFile()
150-
151-
sessionConfigSpy3 = spy(
152-
CodeScanSessionConfig.create(
153-
psifilePerformanceTest.virtualFile,
154-
project,
155-
CodeWhispererConstants.CodeAnalysisScope.FILE
156-
)
157-
)
158-
setupResponse(psifilePerformanceTest.virtualFile.toNioPath().relativeTo(sessionConfigSpy3.projectRoot.toNioPath()))
159-
160-
// Create a 150KB file
161-
val codeContentForPayload = "a".repeat(150 * 1024)
162-
psifilePerformanceTest2 = projectRule.fixture.addFileToProject("test.txt", codeContentForPayload)
163-
performanceTestfileWithPayload150KB = psifilePerformanceTest2.virtualFile.toNioPath().toFile()
164-
165-
sessionConfigSpy4 = spy(
166-
CodeScanSessionConfig.create(
167-
psifilePerformanceTest2.virtualFile,
168-
project,
169-
CodeWhispererConstants.CodeAnalysisScope.FILE
170-
)
171-
)
172-
setupResponse(psifilePerformanceTest2.virtualFile.toNioPath().relativeTo(sessionConfigSpy4.projectRoot.toNioPath()))
173-
sessionConfigSpy = spy(
174-
CodeScanSessionConfig.create(
175-
psifile.virtualFile,
176-
project,
177-
CodeWhispererConstants.CodeAnalysisScope.FILE
178-
)
92+
public static void main(String[] args) {
93+
int num1 = 10;
94+
int num2 = 5;
95+
int result = subtract(num1, num2);
96+
System.out.println(result);
97+
}
98+
}
99+
""".trimMargin()
179100
)
180101

181-
sessionConfigSpy2 = spy(
102+
pySession = spy(
182103
CodeScanSessionConfig.create(
183-
virtualFile4,
104+
pyPsiFile.virtualFile,
184105
project,
185106
CodeWhispererConstants.CodeAnalysisScope.FILE
186107
)
187108
)
109+
setupResponse(pyPsiFile.virtualFile.toNioPath().relativeTo(pySession.projectRoot.toNioPath()))
188110

189-
setupResponse(psifile.virtualFile.toNioPath().relativeTo(sessionConfigSpy.projectRoot.toNioPath()))
190-
191-
sessionConfigSpy.stub {
192-
onGeneric { sessionConfigSpy.createPayload() }.thenReturn(Payload(payloadContext, file))
111+
pySession.stub {
112+
onGeneric { pySession.createPayload() }.thenReturn(Payload(payloadContext, pyPsiFile.virtualFile.toNioPath().toFile()))
193113
}
194114

195115
// Mock CodeWhispererClient needs to be setup before initializing CodeWhispererCodeScanSession
196-
codeScanSessionContext = CodeScanSessionContext(project, sessionConfigSpy, CodeWhispererConstants.CodeAnalysisScope.FILE)
197-
codeScanSessionSpy = spy(CodeWhispererCodeScanSession(codeScanSessionContext))
198-
doNothing().`when`(codeScanSessionSpy).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
199-
200-
codeScanSessionContext2 = CodeScanSessionContext(project, sessionConfigSpy3, CodeWhispererConstants.CodeAnalysisScope.FILE)
201-
codeScanSessionSpy2 = spy(CodeWhispererCodeScanSession(codeScanSessionContext2))
202-
doNothing().`when`(codeScanSessionSpy2).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
116+
val pySessionContext = CodeScanSessionContext(project, pySession, CodeWhispererConstants.CodeAnalysisScope.FILE)
117+
codeScanSessionSpy = spy(CodeWhispererCodeScanSession(pySessionContext))
118+
doNothing().whenever(codeScanSessionSpy).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
203119

204-
codeScanSessionContext3 = CodeScanSessionContext(project, sessionConfigSpy4, CodeWhispererConstants.CodeAnalysisScope.FILE)
205-
codeScanSessionSpy3 = spy(CodeWhispererCodeScanSession(codeScanSessionContext3))
206-
doNothing().`when`(codeScanSessionSpy3).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
207120
mockClient.stub {
208-
onGeneric { createUploadUrl(any()) }.thenReturn(fakeCreateUploadUrlResponse)
209-
onGeneric { createCodeScan(any(), any()) }.thenReturn(fakeCreateCodeScanResponse)
210-
onGeneric { getCodeScan(any(), any()) }.thenReturn(fakeGetCodeScanResponse)
211-
onGeneric { listCodeScanFindings(any(), any()) }.thenReturn(fakeListCodeScanFindingsResponse)
121+
// setupResponse dynamically modifies these fake responses so this is very hard to follow and makes me question if we even need this
122+
onGeneric { createUploadUrl(any()) }.thenAnswer { fakeCreateUploadUrlResponse }
123+
onGeneric { createCodeScan(any(), any()) }.thenAnswer { fakeCreateCodeScanResponse }
124+
onGeneric { getCodeScan(any(), any()) }.thenAnswer { fakeGetCodeScanResponse }
125+
onGeneric { listCodeScanFindings(any(), any()) }.thenAnswer { fakeListCodeScanFindingsResponse }
212126
}
213127
}
214128

215129
@Test
216-
fun `test run() - measure CPU and memory usage`() {
130+
fun `test run() - measure CPU and memory usage with payload of 200KB`() {
131+
// Create a 200KB file
132+
val content = "a".repeat(200 * 1024)
133+
val psiFile = projectRule.fixture.addFileToProject("test.txt", content)
134+
135+
val sessionConfig = spy(
136+
CodeScanSessionConfig.create(
137+
psiFile.virtualFile,
138+
project,
139+
CodeWhispererConstants.CodeAnalysisScope.FILE
140+
)
141+
)
142+
setupResponse(psiFile.virtualFile.toNioPath().relativeTo(sessionConfig.projectRoot.toNioPath()))
143+
val sessionContext = CodeScanSessionContext(project, sessionConfig, CodeWhispererConstants.CodeAnalysisScope.FILE)
144+
val session = spy(CodeWhispererCodeScanSession(sessionContext))
145+
doNothing().whenever(session).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
146+
217147
// Set up CPU and Memory monitoring
218148
val runtime = Runtime.getRuntime()
219149
val bean = ManagementFactory.getThreadMXBean()
@@ -223,7 +153,7 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
223153

224154
// Run the code scan
225155
runBlocking {
226-
codeScanSessionSpy2.run()
156+
session.run()
227157
}
228158

229159
// Calculate CPU and memory usage
@@ -248,6 +178,22 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
248178

249179
@Test
250180
fun `test run() - measure CPU and memory usage with payload of 150KB`() {
181+
// Create a 150KB file
182+
val codeContentForPayload = "a".repeat(150 * 1024)
183+
val psiFile = projectRule.fixture.addFileToProject("test.txt", codeContentForPayload)
184+
185+
val sessionConfig = spy(
186+
CodeScanSessionConfig.create(
187+
psiFile.virtualFile,
188+
project,
189+
CodeWhispererConstants.CodeAnalysisScope.FILE
190+
)
191+
)
192+
setupResponse(psiFile.virtualFile.toNioPath().relativeTo(sessionConfig.projectRoot.toNioPath()))
193+
val sessionContext = CodeScanSessionContext(project, sessionConfig, CodeWhispererConstants.CodeAnalysisScope.FILE)
194+
val session = spy(CodeWhispererCodeScanSession(sessionContext))
195+
doNothing().whenever(session).uploadArtifactToS3(any(), any(), any(), any(), isNull(), any())
196+
251197
// Set up CPU and Memory monitoring
252198
val runtime = Runtime.getRuntime()
253199
val bean = ManagementFactory.getThreadMXBean()
@@ -257,7 +203,7 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
257203

258204
// Run the code scan
259205
runBlocking {
260-
codeScanSessionSpy3.run()
206+
session.run()
261207
}
262208

263209
// Calculate CPU and memory usage
@@ -282,6 +228,7 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
282228

283229
@Test
284230
fun `test createUploadUrlAndUpload()`() {
231+
val file = pyPsiFile.virtualFile.toNioPath().toFile()
285232
val fileMd5: String = Base64.getEncoder().encodeToString(DigestUtils.md5(FileInputStream(file)))
286233
codeScanSessionSpy.stub {
287234
onGeneric { codeScanSessionSpy.createUploadUrl(any(), any(), any()) }
@@ -327,7 +274,9 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
327274

328275
@Test
329276
fun `test run() - happypath`() = runTest {
330-
assertNotNull(sessionConfigSpy)
277+
val file = pyPsiFile.virtualFile.toNioPath().toFile()
278+
279+
assertNotNull(pySession)
331280
val codeScanResponse = codeScanSessionSpy.run()
332281
assertThat(codeScanResponse).isInstanceOfSatisfying<CodeScanResponse.Success> {
333282
assertThat(it.issues).hasSize(2)
@@ -336,14 +285,38 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
336285
}
337286

338287
val inOrder = inOrder(codeScanSessionSpy)
339-
inOrder.verify(codeScanSessionSpy, Times(1)).createUploadUrlAndUpload(eq(file), eq("SourceCode"), anyString())
340-
inOrder.verify(codeScanSessionSpy, Times(1)).createCodeScan(eq(CodewhispererLanguage.Python.toString()), anyString())
341-
inOrder.verify(codeScanSessionSpy, Times(1)).getCodeScan(any())
342-
inOrder.verify(codeScanSessionSpy, Times(1)).listCodeScanFindings(eq("jobId"), eq(null))
288+
inOrder.verify(codeScanSessionSpy, times(1)).createUploadUrlAndUpload(eq(file), eq("SourceCode"), anyString())
289+
inOrder.verify(codeScanSessionSpy, times(1)).createCodeScan(eq(CodewhispererLanguage.Python.toString()), anyString())
290+
inOrder.verify(codeScanSessionSpy, times(1)).getCodeScan(any())
291+
inOrder.verify(codeScanSessionSpy, times(1)).listCodeScanFindings(eq("jobId"), eq(null))
343292
}
344293

345294
@Test
346295
fun `test createPayload for files outside Project Root`() {
296+
val externalFile = projectRule.fixture.addFileToProject(
297+
"../test.java",
298+
"""
299+
public class Addition {
300+
public static void main(String[] args) {
301+
int a = 1;
302+
int b = 2;
303+
int c = a + b;
304+
System.out.println(c);
305+
}
306+
}
307+
"""
308+
)
309+
310+
val sessionConfigSpy2 = spy(
311+
CodeScanSessionConfig.create(
312+
externalFile.virtualFile,
313+
project,
314+
CodeWhispererConstants.CodeAnalysisScope.FILE
315+
)
316+
)
317+
318+
setupResponse(pyPsiFile.virtualFile.toNioPath().relativeTo(pySession.projectRoot.toNioPath()))
319+
347320
val payload = sessionConfigSpy2.createPayload()
348321
assertNotNull(payload)
349322
val payloadZipFile = ZipFile(payload.srcZip)
@@ -354,16 +327,13 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
354327

355328
@Test
356329
fun `unsupported languages file scan fail`() = runTest {
357-
scanManagerSpy = Mockito.spy(CodeWhispererCodeScanManager.getInstance(projectRule.project))
358-
projectRule.project.replaceService(CodeWhispererCodeScanManager::class.java, scanManagerSpy, disposableRule.disposable)
359-
360-
val fileEditorManager = mock(FileEditorManager::class.java)
361-
val selectedEditor = mock(FileEditor::class.java)
362-
val editorList: MutableList<FileEditor> = mutableListOf(selectedEditor)
330+
val fileEditorManager = mock<FileEditorManager>()
331+
val selectedEditor = mock<FileEditor>()
332+
val editorList = mutableListOf(selectedEditor)
363333

364-
`when`(fileEditorManager.selectedEditorWithRemotes).thenReturn(editorList)
365-
`when`(fileEditorManager.selectedEditor).thenReturn(selectedEditor)
366-
`when`(selectedEditor.file).thenReturn(virtualFile3)
334+
whenever(fileEditorManager.selectedEditorWithRemotes).thenReturn(editorList)
335+
whenever(fileEditorManager.selectedEditor).thenReturn(selectedEditor)
336+
whenever(selectedEditor.file).thenReturn(ktPsiFile.virtualFile)
367337

368338
scanManagerSpy.runCodeScan(CodeWhispererConstants.CodeAnalysisScope.FILE)
369339
// verify that function was run but none of the results/error handling methods were called.
@@ -374,7 +344,7 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
374344

375345
@Test
376346
fun `test run() - file scans limit reached`() = runTest {
377-
assertNotNull(sessionConfigSpy)
347+
assertNotNull(pySession)
378348

379349
mockClient.stub {
380350
onGeneric { codeScanSessionSpy.createUploadUrlAndUpload(any(), any(), any()) }.thenThrow(
@@ -441,7 +411,7 @@ class CodeWhispererCodeFileScanTest : CodeWhispererCodeScanTestBase(PythonCodeIn
441411

442412
@Test
443413
fun `test run() - getCodeScan pending timeout`() = runTest {
444-
sessionConfigSpy.stub {
414+
pySession.stub {
445415
onGeneric { overallJobTimeoutInSeconds() }.thenReturn(5)
446416
}
447417
mockClient.stub {

0 commit comments

Comments
 (0)