Skip to content

Commit 683b793

Browse files
authored
tests(codewhisperer): add more unit tests #3195
* add basicCommands security scan tests * add authUtil tests (WIP) * initial showSsoPrompt test + cleanup * add export awsIdSignIn * additional inlineCompletionService tests * add CWInlineCompletionProvider tests * export CWInlineCompletionItemProvider to enable testing * fix failing tests * skip tests failing macOS nodejs (16.x, minimum) tests * add backend.ts tests and fix failing securityScan test * add showConnectionPrompt test * codewhisperer explorer node tests * securityPanelViewProvider tests + additional authUtil test * cleanup authUtil per team comments * additional authUtil test updates * refactor and cleanup * remove test causing other tests to fail * remove inlineCompletionService tests that were failing macOS nodejs minimum tests * fix/remove failing tests
1 parent 7437676 commit 683b793

File tree

10 files changed

+555
-8
lines changed

10 files changed

+555
-8
lines changed

src/codewhisperer/service/inlineCompletionService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import globals from '../../shared/extensionGlobals'
2323
import { AuthUtil } from '../util/authUtil'
2424
import { shared } from '../../shared/utilities/functionUtils'
2525

26-
class CWInlineCompletionItemProvider implements vscode.InlineCompletionItemProvider {
26+
export class CWInlineCompletionItemProvider implements vscode.InlineCompletionItemProvider {
2727
private activeItemIndex: number | undefined
2828
public nextMove: number
2929

src/codewhisperer/util/showSsoPrompt.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const showConnectionPrompt = async () => {
5757
}
5858
}
5959

60-
async function awsIdSignIn() {
60+
export async function awsIdSignIn() {
6161
getLogger().info('selected AWS ID sign in')
6262
try {
6363
await AuthUtil.instance.connectToAwsBuilderId()

src/test/codewhisperer/commands/basicCommands.test.ts

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,20 @@
55

66
import * as vscode from 'vscode'
77
import * as assert from 'assert'
8-
import { beforeEach } from 'mocha'
98
import * as sinon from 'sinon'
9+
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
1010
import { resetCodeWhispererGlobalVariables } from '../testUtil'
1111
import { assertTelemetryCurried } from '../../testUtil'
12-
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
13-
import { toggleCodeSuggestions, get, set } from '../../../codewhisperer/commands/basicCommands'
14-
import { FakeMemento } from '../../fakeExtensionContext'
12+
import { toggleCodeSuggestions, get, set, showSecurityScan } from '../../../codewhisperer/commands/basicCommands'
13+
import { FakeMemento, FakeExtensionContext } from '../../fakeExtensionContext'
1514
import { testCommand } from '../../shared/vscode/testUtils'
1615
import { Command } from '../../../shared/vscode/commands2'
16+
import { SecurityPanelViewProvider } from '../../../codewhisperer/views/securityPanelViewProvider'
17+
import { DefaultCodeWhispererClient } from '../../../codewhisperer/client/codewhisperer'
18+
import { stub } from '../../utilities/stubber'
19+
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
20+
import { getTestWindow } from '../../shared/vscode/window'
21+
import { ExtContext } from '../../../shared/extensions'
1722

1823
describe('CodeWhisperer-basicCommands', function () {
1924
let targetCommand: Command<any> & vscode.Disposable
@@ -86,4 +91,44 @@ describe('CodeWhisperer-basicCommands', function () {
8691
})
8792
})
8893
})
94+
95+
describe('showSecurityScan', function () {
96+
let mockExtensionContext: vscode.ExtensionContext
97+
let mockSecurityPanelViewProvider: SecurityPanelViewProvider
98+
let mockClient: DefaultCodeWhispererClient
99+
let mockExtContext: ExtContext
100+
101+
beforeEach(async function () {
102+
resetCodeWhispererGlobalVariables()
103+
mockExtensionContext = await FakeExtensionContext.create()
104+
mockSecurityPanelViewProvider = new SecurityPanelViewProvider(mockExtensionContext)
105+
mockClient = stub(DefaultCodeWhispererClient)
106+
mockExtContext = await FakeExtensionContext.getFakeExtContext()
107+
})
108+
109+
afterEach(function () {
110+
targetCommand?.dispose()
111+
sinon.restore()
112+
})
113+
114+
it('prompts user to reauthenticate if connection is expired', async function () {
115+
targetCommand = testCommand(showSecurityScan, mockExtContext, mockSecurityPanelViewProvider, mockClient)
116+
117+
sinon.stub(AuthUtil.instance, 'isConnectionExpired').returns(true)
118+
const spy = sinon.stub(AuthUtil.instance, 'showReauthenticatePrompt')
119+
120+
await targetCommand.execute()
121+
assert.ok(spy.called)
122+
})
123+
124+
it('shows information message if there is no active text editor', async function () {
125+
targetCommand = testCommand(showSecurityScan, mockExtContext, mockSecurityPanelViewProvider, mockClient)
126+
127+
sinon.stub(AuthUtil.instance, 'isConnectionExpired').returns(false)
128+
129+
assert.ok(vscode.window.activeTextEditor === undefined)
130+
await targetCommand.execute()
131+
assert.strictEqual(getTestWindow().shownMessages[0].message, "Open a valid file to scan.")
132+
})
133+
})
89134
})
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*!
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as assert from 'assert'
7+
import * as sinon from 'sinon'
8+
import {
9+
createEnableCodeSuggestionsNode,
10+
createAutoSuggestionsNode,
11+
createOpenReferenceLogNode,
12+
createSecurityScanNode,
13+
createSsoSignIn,
14+
createLearnMore,
15+
createFreeTierLimitMetNode
16+
} from '../../../codewhisperer/explorer/codewhispererChildrenNodes'
17+
18+
describe('codewhisperer children nodes', function () {
19+
afterEach(function () {
20+
sinon.restore()
21+
})
22+
23+
it('should build enableCodeSuggestions command node', function () {
24+
const node = createEnableCodeSuggestionsNode()
25+
26+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.enableCodeSuggestions')
27+
})
28+
29+
it('should build toggleCodeSuggestions command node', function () {
30+
const node = createAutoSuggestionsNode(true)
31+
32+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.toggleCodeSuggestion')
33+
})
34+
35+
it('should build showReferenceLog command node', function () {
36+
const node = createOpenReferenceLogNode()
37+
38+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.openReferencePanel')
39+
})
40+
41+
it('should build showSecurityScan command node', function () {
42+
const node = createSecurityScanNode()
43+
44+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.security.scan')
45+
})
46+
47+
it('should build showSsoSignIn command node', function () {
48+
const node = createSsoSignIn()
49+
50+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.sso')
51+
})
52+
53+
it('should build showLearnMore command node', function () {
54+
const node = createLearnMore()
55+
56+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.learnMore')
57+
})
58+
59+
it('should build showFreeTierLimit command node', function () {
60+
const node = createFreeTierLimitMetNode()
61+
62+
assert.strictEqual(node.resource.id, 'aws.codeWhisperer.freeTierLimit')
63+
})
64+
})
65+
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*!
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import * as vscode from 'vscode'
7+
import * as assert from 'assert'
8+
import * as sinon from 'sinon'
9+
import { codewhispererNode } from '../../../codewhisperer/explorer/codewhispererNode'
10+
import { AuthUtil } from '../../../codewhisperer/util/authUtil'
11+
12+
describe('codewhispererNode', function () {
13+
describe('getTreeItem', function () {
14+
afterEach(function () {
15+
sinon.restore()
16+
})
17+
18+
it('should create a node with correct label and description', function () {
19+
const node = codewhispererNode
20+
const treeItem = node.getTreeItem()
21+
22+
assert.strictEqual(treeItem.label, 'CodeWhisperer (Preview)')
23+
assert.strictEqual(treeItem.contextValue, 'awsCodeWhispererNode')
24+
assert.strictEqual(treeItem.description, '')
25+
})
26+
27+
it('should create a node showing AWS Builder ID connection', function () {
28+
sinon.stub(AuthUtil.instance, 'isUsingSavedConnection').get(() => true)
29+
sinon.stub(AuthUtil.instance, 'isConnectionValid').resolves(true)
30+
const node = codewhispererNode
31+
const treeItem = node.getTreeItem()
32+
33+
assert.strictEqual(treeItem.label, 'CodeWhisperer (Preview)')
34+
assert.strictEqual(treeItem.contextValue, 'awsCodeWhispererNodeSaved')
35+
assert.strictEqual(treeItem.description, 'AWS Builder ID Connected')
36+
assert.strictEqual(treeItem.collapsibleState, vscode.TreeItemCollapsibleState.Collapsed)
37+
})
38+
39+
it('should create a node showing enterprise SSO connection', function () {
40+
sinon.stub(AuthUtil.instance, 'isUsingSavedConnection').get(() => true)
41+
sinon.stub(AuthUtil.instance, 'isConnectionValid').resolves(true)
42+
sinon.stub(AuthUtil.instance, 'isEnterpriseSsoInUse').resolves(true)
43+
const node = codewhispererNode
44+
const treeItem = node.getTreeItem()
45+
46+
assert.strictEqual(treeItem.label, 'CodeWhisperer (Preview)')
47+
assert.strictEqual(treeItem.contextValue, 'awsCodeWhispererNodeSaved')
48+
assert.strictEqual(treeItem.description, 'IAM Identity Center Connected')
49+
assert.strictEqual(treeItem.collapsibleState, vscode.TreeItemCollapsibleState.Collapsed)
50+
})
51+
})
52+
53+
describe('getChildren', function () {
54+
afterEach(function () {
55+
sinon.restore()
56+
})
57+
58+
it('should get correct child nodes if user is not connected', function () {
59+
const node = codewhispererNode
60+
const children = node.getChildren()
61+
const ssoSignInNode = children.find(c => c.resource.id == 'aws.codeWhisperer.sso')
62+
const learnMorenNode = children.find(c => c.resource.id == 'aws.codeWhisperer.learnMore')
63+
64+
assert.strictEqual(children.length, 2)
65+
assert.ok(ssoSignInNode)
66+
assert.ok(learnMorenNode)
67+
})
68+
})
69+
})

src/test/codewhisperer/service/inlineCompletionService.test.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import * as vscode from 'vscode'
77
import * as assert from 'assert'
88
import * as sinon from 'sinon'
9-
import { InlineCompletionService } from '../../../codewhisperer/service/inlineCompletionService'
10-
import { createMockTextEditor, resetCodeWhispererGlobalVariables } from '../testUtil'
9+
import { InlineCompletionService, CWInlineCompletionItemProvider } from '../../../codewhisperer/service/inlineCompletionService'
10+
import { createMockTextEditor, resetCodeWhispererGlobalVariables, createMockDocument } from '../testUtil'
1111
import { ReferenceInlineProvider } from '../../../codewhisperer/service/referenceInlineProvider'
1212
import { RecommendationHandler } from '../../../codewhisperer/service/recommendationHandler'
1313
import * as codewhispererSdkClient from '../../../codewhisperer/client/codewhisperer'
@@ -93,6 +93,8 @@ describe('inlineCompletionService', function () {
9393
{ content: "\n\t\tconsole.log('Hello world!');\n\t}" },
9494
{ content: '' },
9595
]
96+
97+
assert.ok(RecommendationHandler.instance.recommendations.length > 0)
9698
await InlineCompletionService.instance.clearInlineCompletionStates(createMockTextEditor())
9799
assert.strictEqual(ReferenceInlineProvider.instance.refs.length, 0)
98100
assert.strictEqual(RecommendationHandler.instance.recommendations.length, 0)
@@ -142,3 +144,36 @@ describe('inlineCompletionService', function () {
142144
})
143145
})
144146
})
147+
148+
describe('CWInlineCompletionProvider', function () {
149+
beforeEach(function () {
150+
resetCodeWhispererGlobalVariables()
151+
})
152+
153+
describe('provideInlineCompletionItems', function () {
154+
beforeEach(function () {
155+
resetCodeWhispererGlobalVariables()
156+
})
157+
158+
afterEach(function () {
159+
sinon.restore()
160+
})
161+
162+
it('should return undefined if position is before RecommendationHandler start pos', async function () {
163+
RecommendationHandler.instance.startPos = new vscode.Position(1, 1)
164+
const position = new vscode.Position(0, 0)
165+
const document = createMockDocument()
166+
const fakeContext = {triggerKind: 0, selectedCompletionInfo: undefined}
167+
const token = new vscode.CancellationTokenSource().token
168+
const provider = new CWInlineCompletionItemProvider(0, 0)
169+
const result = await provider.provideInlineCompletionItems(
170+
document,
171+
position,
172+
fakeContext,
173+
token
174+
)
175+
176+
assert.ok(result === undefined)
177+
})
178+
})
179+
})

0 commit comments

Comments
 (0)