Skip to content

Commit 5c1d84d

Browse files
author
David Hasani
committed
tests(amazonq): improve test coverage
1 parent 3a39b10 commit 5c1d84d

File tree

5 files changed

+70
-36
lines changed

5 files changed

+70
-36
lines changed

packages/core/src/amazonqGumby/chat/controller/controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ import {
5656
} from '../../../shared/telemetry/telemetry'
5757
import { MetadataResult } from '../../../shared/telemetry/telemetryClient'
5858
import { CodeTransformTelemetryState } from '../../telemetry/codeTransformTelemetryState'
59-
import { getAuthType } from '../../../codewhisperer/service/transformByQ/transformApiHandler'
6059
import DependencyVersions from '../../models/dependencies'
6160
import { getStringHash } from '../../../shared/utilities/textUtilities'
6261
import { getVersionData } from '../../../codewhisperer/service/transformByQ/transformMavenHandler'
6362
import AdmZip from 'adm-zip'
6463
import { AuthError } from '../../../auth/sso/server'
64+
import { getAuthType } from '../../../auth/utils'
6565

6666
// These events can be interactions within the chat,
6767
// or elsewhere in the IDE

packages/core/src/auth/utils.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { formatError, ToolkitError } from '../shared/errors'
1818
import { asString } from './providers/credentials'
1919
import { TreeNode } from '../shared/treeview/resourceTreeDataProvider'
2020
import { createInputBox } from '../shared/ui/inputPrompter'
21-
import { telemetry } from '../shared/telemetry/telemetry'
21+
import { CredentialSourceId, telemetry } from '../shared/telemetry/telemetry'
2222
import { createCommonButtons, createExitButton, createHelpButton, createRefreshButton } from '../shared/ui/buttons'
2323
import { getIdeProperties, isAmazonQ, isCloud9 } from '../shared/extensionUtilities'
2424
import { addScopes, getDependentAuths } from './secondaryAuth'
@@ -45,7 +45,7 @@ import { Commands, placeholder } from '../shared/vscode/commands2'
4545
import { Auth } from './auth'
4646
import { validateIsNewSsoUrl, validateSsoUrlFormat } from './sso/validation'
4747
import { getLogger } from '../shared/logger'
48-
import { isValidAmazonQConnection, isValidCodeWhispererCoreConnection } from '../codewhisperer/util/authUtil'
48+
import { AuthUtil, isValidAmazonQConnection, isValidCodeWhispererCoreConnection } from '../codewhisperer/util/authUtil'
4949
import { AuthFormId } from '../login/webview/vue/types'
5050
import { extensionVersion } from '../shared/vscode/env'
5151
import { ExtStartUpSources } from '../shared/telemetry'
@@ -798,3 +798,13 @@ export function initializeCredentialsProviderManager() {
798798
manager.addProviderFactory(new SharedCredentialsProviderFactory())
799799
manager.addProviders(new Ec2CredentialsProvider(), new EcsCredentialsProvider(), new EnvVarsCredentialsProvider())
800800
}
801+
802+
export async function getAuthType() {
803+
let authType: CredentialSourceId | undefined = undefined
804+
if (AuthUtil.instance.isEnterpriseSsoInUse() && AuthUtil.instance.isConnectionValid()) {
805+
authType = 'iamIdentityCenter'
806+
} else if (AuthUtil.instance.isBuilderIdInUse() && AuthUtil.instance.isConnectionValid()) {
807+
authType = 'awsId'
808+
}
809+
return authType
810+
}

packages/core/src/codewhisperer/service/transformByQ/transformApiHandler.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,38 +34,28 @@ import {
3434
import { sleep } from '../../../shared/utilities/timeoutUtils'
3535
import AdmZip from 'adm-zip'
3636
import globals from '../../../shared/extensionGlobals'
37-
import { CredentialSourceId, telemetry } from '../../../shared/telemetry/telemetry'
37+
import { telemetry } from '../../../shared/telemetry/telemetry'
3838
import { CodeTransformTelemetryState } from '../../../amazonqGumby/telemetry/codeTransformTelemetryState'
3939
import { calculateTotalLatency } from '../../../amazonqGumby/telemetry/codeTransformTelemetry'
4040
import { MetadataResult } from '../../../shared/telemetry/telemetryClient'
4141
import request from '../../../shared/request'
4242
import { JobStoppedError, ZipExceedsSizeLimitError } from '../../../amazonqGumby/errors'
4343
import { writeLogs } from './transformFileHandler'
44-
import { AuthUtil } from '../../util/authUtil'
4544
import { createCodeWhispererChatStreamingClient } from '../../../shared/clients/codewhispererChatClient'
4645
import { downloadExportResultArchive } from '../../../shared/utilities/download'
4746
import { ExportIntent, TransformationDownloadArtifactType } from '@amzn/codewhisperer-streaming'
4847
import fs from '../../../shared/fs/fs'
4948
import { ChatSessionManager } from '../../../amazonqGumby/chat/storages/chatSession'
5049
import { encodeHTML } from '../../../shared/utilities/textUtilities'
5150
import { convertToTimeString } from '../../../shared/datetime'
51+
import { getAuthType } from '../../../auth/utils'
5252

5353
export function getSha256(buffer: Buffer) {
5454
const hasher = crypto.createHash('sha256')
5555
hasher.update(buffer)
5656
return hasher.digest('base64')
5757
}
5858

59-
export async function getAuthType() {
60-
let authType: CredentialSourceId | undefined = undefined
61-
if (AuthUtil.instance.isEnterpriseSsoInUse() && AuthUtil.instance.isConnectionValid()) {
62-
authType = 'iamIdentityCenter'
63-
} else if (AuthUtil.instance.isBuilderIdInUse() && AuthUtil.instance.isConnectionValid()) {
64-
authType = 'awsId'
65-
}
66-
return authType
67-
}
68-
6959
export function throwIfCancelled() {
7060
if (transformByQState.isCancelled()) {
7161
throw new TransformByQStoppedError()

packages/core/src/test/codewhisperer/commands/transformByQ.test.ts

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
import assert, { fail } from 'assert'
77
import * as vscode from 'vscode'
88
import * as sinon from 'sinon'
9-
import { makeTemporaryToolkitFolder } from '../../../shared/filesystemUtilities'
109
import { DB, transformByQState, TransformByQStoppedError } from '../../../codewhisperer/models/model'
1110
import {
11+
finalizeTransformationJob,
1212
parseBuildFile,
13+
setMaven,
1314
stopTransformByQ,
1415
validateSQLMetadataFile,
1516
} from '../../../codewhisperer/commands/startTransformByQ'
@@ -40,14 +41,14 @@ import {
4041
} from '../../../codewhisperer/service/transformByQ/transformProjectValidationHandler'
4142
import { TransformationCandidateProject, ZipManifest } from '../../../codewhisperer/models/model'
4243
import globals from '../../../shared/extensionGlobals'
43-
import { fs } from '../../../shared'
44+
import { env, fs } from '../../../shared'
4445
import { convertDateToTimestamp, convertToTimeString } from '../../../shared/datetime'
4546

4647
describe('transformByQ', function () {
4748
let tempDir: string
4849

4950
beforeEach(async function () {
50-
tempDir = await makeTemporaryToolkitFolder()
51+
tempDir = (await TestFolder.create()).path
5152
transformByQState.setToNotStarted()
5253
})
5354

@@ -149,6 +150,30 @@ describe('transformByQ', function () {
149150
sinon.assert.calledWithExactly(stopJobStub, { transformationJobId: 'dummyId' })
150151
})
151152

153+
it('WHEN stopTransformByQ called with job that has already terminated THEN stop API not called', async function () {
154+
const stopJobStub = sinon.stub(codeWhisperer.codeWhispererClient, 'codeModernizerStopCodeTransformation')
155+
transformByQState.setToSucceeded()
156+
await stopTransformByQ('abc-123')
157+
sinon.assert.notCalled(stopJobStub)
158+
})
159+
160+
it('WHEN finalizeTransformationJob on failed job THEN error thrown and error message fields are set', async function () {
161+
await assert.rejects(async () => {
162+
await finalizeTransformationJob('FAILED')
163+
})
164+
assert.notStrictEqual(transformByQState.getJobFailureErrorChatMessage(), undefined)
165+
assert.notStrictEqual(transformByQState.getJobFailureErrorNotification(), undefined)
166+
transformByQState.setJobDefaults() // reset error messages to undefined
167+
})
168+
169+
it('WHEN finalizeTransformationJob on successful job THEN error not thrown and error message fields are not set', async function () {
170+
await assert.doesNotReject(async () => {
171+
await finalizeTransformationJob('COMPLETED')
172+
})
173+
assert.strictEqual(transformByQState.getJobFailureErrorChatMessage(), undefined)
174+
assert.strictEqual(transformByQState.getJobFailureErrorNotification(), undefined)
175+
})
176+
152177
it('WHEN polling completed job THEN returns status as completed', async function () {
153178
const mockJobResponse = {
154179
$response: {
@@ -208,6 +233,16 @@ describe('transformByQ', function () {
208233
assert.deepStrictEqual(actual, expected)
209234
})
210235

236+
it(`WHEN transforming a project with a Windows Maven executable THEN mavenName set correctly`, async function () {
237+
sinon.stub(env, 'isWin').returns(true)
238+
const tempFileName = 'mvnw.cmd'
239+
const tempFilePath = path.join(tempDir, tempFileName)
240+
await toFile('', tempFilePath)
241+
transformByQState.setProjectPath(tempDir)
242+
await setMaven()
243+
assert.strictEqual(transformByQState.getMavenName(), '.\\mvnw.cmd')
244+
})
245+
211246
it(`WHEN zip created THEN manifest.json contains test-compile custom build command`, async function () {
212247
const tempFileName = `testfile-${globals.clock.Date.now()}.zip`
213248
transformByQState.setProjectPath(tempDir)
@@ -234,6 +269,19 @@ describe('transformByQ', function () {
234269
})
235270
})
236271

272+
it('WHEN zipCode THEN ZIP contains all expected files and no unexpected files', async function () {
273+
const zipFilePath = path.join(tempDir, 'test.zip')
274+
const zip = new AdmZip()
275+
await fs.writeFile(path.join(tempDir, 'pom.xml'), 'dummy pom.xml')
276+
zip.addLocalFile(path.join(tempDir, 'pom.xml'))
277+
zip.addFile('manifest.json', Buffer.from(JSON.stringify({ version: '1.0' })))
278+
zip.writeZip(zipFilePath)
279+
const zipFiles = new AdmZip(zipFilePath).getEntries()
280+
const zipFileNames = zipFiles.map((file) => file.name)
281+
assert.strictEqual(zipFileNames.length, 2) // expecting only pom.xml and manifest.json
282+
assert.strictEqual(zipFileNames.includes('pom.xml') && zipFileNames.includes('manifest.json'), true)
283+
})
284+
237285
it(`WHEN zip created THEN dependencies contains no .sha1 or .repositories files`, async function () {
238286
const m2Folders = [
239287
'com/groupid1/artifactid1/version1',

packages/core/src/testE2E/amazonqGumby/transformByQ.test.ts renamed to packages/core/src/testInteg/amazonQTransform/transformByQ.test.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ import * as codeWhisperer from '../../codewhisperer/client/codewhisperer'
1010
import assert from 'assert'
1111
import { getSha256, uploadArtifactToS3, zipCode } from '../../codewhisperer/service/transformByQ/transformApiHandler'
1212
import request from '../../shared/request'
13-
import AdmZip from 'adm-zip'
14-
import { setValidConnection } from '../util/connection'
1513
import { transformByQState, ZipManifest } from '../../codewhisperer/models/model'
1614
import globals from '../../shared/extensionGlobals'
1715
import { fs } from '../../shared'
16+
import { setValidConnection } from '../../testE2E/util/connection'
1817

1918
describe('transformByQ', async function () {
2019
let tempDir = ''
@@ -35,10 +34,6 @@ describe('transformByQ', async function () {
3534
await fs.writeFile(tempFilePath, 'sample content for the test file')
3635
transformByQState.setProjectPath(tempDir)
3736
const zipCodeResult = await zipCode({
38-
dependenciesFolder: {
39-
path: tempFilePath,
40-
name: tempFileName,
41-
},
4237
projectPath: tempDir,
4338
zipManifest: new ZipManifest(),
4439
})
@@ -87,7 +82,7 @@ describe('transformByQ', async function () {
8782
)
8883
})
8984

90-
it('WHEN createUploadUrl THEN URL uses HTTPS and sets 60 second expiration', async function () {
85+
it('WHEN createUploadUrl THEN URL uses HTTPS and sets 30 minute expiration', async function () {
9186
const buffer = Buffer.from(await fs.readFileBytes(zippedCodePath))
9287
const sha256 = getSha256(buffer)
9388
const response = await codeWhisperer.codeWhispererClient.createUploadUrl({
@@ -96,17 +91,8 @@ describe('transformByQ', async function () {
9691
uploadIntent: CodeWhispererConstants.uploadIntent,
9792
})
9893
const uploadUrl = response.uploadUrl
99-
const usesHttpsAndExpiresAfter60Seconds = uploadUrl.includes('https') && uploadUrl.includes('X-Amz-Expires=60')
94+
const usesHttpsAndExpiresAfter60Seconds =
95+
uploadUrl.includes('https') && uploadUrl.includes('X-Amz-Expires=1800')
10096
assert.strictEqual(usesHttpsAndExpiresAfter60Seconds, true)
10197
})
102-
103-
it('WHEN zipCode THEN ZIP contains all expected files and no unexpected files', async function () {
104-
const zipFiles = new AdmZip(zippedCodePath).getEntries()
105-
const zipFileNames: string[] = []
106-
zipFiles.forEach((file) => {
107-
zipFileNames.push(file.name)
108-
})
109-
assert.strictEqual(zipFileNames.length, 2) // expecting only a dummy txt file and a manifest.json
110-
assert.strictEqual(zipFileNames.includes(tempFileName) && zipFileNames.includes('manifest.json'), true)
111-
})
11298
})

0 commit comments

Comments
 (0)