Skip to content

Commit 0b31636

Browse files
committed
chore(amazonq): refactor codeWhispereServer.ts
1 parent 1f6b7f7 commit 0b31636

File tree

9 files changed

+1097
-708
lines changed

9 files changed

+1097
-708
lines changed

server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { TestFeatures } from '@aws/language-server-runtimes/testing'
1212
import * as assert from 'assert'
1313
import { AWSError } from 'aws-sdk'
1414
import sinon, { StubbedInstance } from 'ts-sinon'
15-
import { CodeWhispererServer, CodewhispererServerFactory, getLanguageIdFromUri } from './codeWhispererServer'
15+
import { CodeWhispererServer, CodewhispererServerFactory } from './codeWhispererServer'
1616
import {
1717
CodeWhispererServiceBase,
1818
CodeWhispererServiceToken,
@@ -27,7 +27,6 @@ import {
2727
EXPECTED_REFERENCE,
2828
EXPECTED_RESPONSE_CONTEXT,
2929
EXPECTED_RESULT,
30-
EXPECTED_RESULT_EDITS,
3130
EXPECTED_RESULT_WITHOUT_IMPORTS,
3231
EXPECTED_RESULT_WITHOUT_REFERENCES,
3332
EXPECTED_RESULT_WITH_IMPORTS,
@@ -63,6 +62,7 @@ import { AmazonQError } from '../../shared/amazonQServiceManager/errors'
6362
import * as path from 'path'
6463
import { CONTEXT_CHARACTERS_LIMIT } from './contants/constants'
6564
import { IdleWorkspaceManager } from '../workspaceContext/IdleWorkspaceManager'
65+
import { getLanguageIdFromUri } from './utils/textDocumentUtils'
6666

6767
const updateConfiguration = async (
6868
features: TestFeatures,

server/aws-lsp-codewhisperer/src/language-server/inline-completion/codeWhispererServer.ts

Lines changed: 46 additions & 684 deletions
Large diffs are not rendered by default.

server/aws-lsp-codewhisperer/src/language-server/inline-completion/editCompletionHandler.ts renamed to server/aws-lsp-codewhisperer/src/language-server/inline-completion/handler/editCompletionHandler.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,35 +9,35 @@ import {
99
ResponseError,
1010
TextDocument,
1111
} from '@aws/language-server-runtimes/protocol'
12-
import { RecentEditTracker } from './tracker/codeEditTracker'
12+
import { RecentEditTracker } from '../tracker/codeEditTracker'
1313
import { CredentialsProvider, Logging, Telemetry, Workspace } from '@aws/language-server-runtimes/server-interface'
1414
import {
1515
CodeWhispererServiceToken,
1616
GenerateSuggestionsRequest,
1717
GenerateSuggestionsResponse,
1818
getFileContext,
1919
SuggestionType,
20-
} from '../../shared/codeWhispererService'
21-
import { CodeWhispererSession, SessionManager } from './session/sessionManager'
22-
import { CursorTracker } from './tracker/cursorTracker'
23-
import { CodewhispererLanguage, getSupportedLanguageId } from '../../shared/languageDetection'
24-
import { WorkspaceFolderManager } from '../workspaceContext/workspaceFolderManager'
25-
import { shouldTriggerEdits } from './trigger'
20+
} from '../../../shared/codeWhispererService'
21+
import { CodeWhispererSession, SessionManager } from '../session/sessionManager'
22+
import { CursorTracker } from '../tracker/cursorTracker'
23+
import { CodewhispererLanguage, getSupportedLanguageId } from '../../../shared/languageDetection'
24+
import { WorkspaceFolderManager } from '../../workspaceContext/workspaceFolderManager'
25+
import { shouldTriggerEdits } from '../trigger'
2626
import {
2727
emitEmptyUserTriggerDecisionTelemetry,
2828
emitServiceInvocationFailure,
2929
emitServiceInvocationTelemetry,
3030
emitUserTriggerDecisionTelemetry,
31-
} from './telemetry/telemetry'
32-
import { TelemetryService } from '../../shared/telemetry/telemetryService'
31+
} from '../telemetry/telemetry'
32+
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
3333
import { textUtils } from '@aws/lsp-core'
34-
import { AmazonQBaseServiceManager } from '../../shared/amazonQServiceManager/BaseAmazonQServiceManager'
35-
import { RejectedEditTracker } from './tracker/rejectedEditTracker'
36-
import { getErrorMessage, hasConnectionExpired } from '../../shared/utils'
37-
import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../shared/amazonQServiceManager/errors'
38-
import { DocumentChangedListener } from './documentChangedListener'
39-
import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from './contants/constants'
40-
import { StreakTracker } from './tracker/streakTracker'
34+
import { AmazonQBaseServiceManager } from '../../../shared/amazonQServiceManager/BaseAmazonQServiceManager'
35+
import { RejectedEditTracker } from '../tracker/rejectedEditTracker'
36+
import { getErrorMessage, hasConnectionExpired } from '../../../shared/utils'
37+
import { AmazonQError, AmazonQServiceConnectionExpiredError } from '../../../shared/amazonQServiceManager/errors'
38+
import { DocumentChangedListener } from '../documentChangedListener'
39+
import { EMPTY_RESULT, EDIT_DEBOUNCE_INTERVAL_MS } from '../contants/constants'
40+
import { StreakTracker } from '../tracker/streakTracker'
4141

4242
export class EditCompletionHandler {
4343
private readonly editsEnabled: boolean
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import * as assert from 'assert'
2+
import * as sinon from 'sinon'
3+
import { TextDocument } from 'vscode-languageserver-textdocument'
4+
import { InlineCompletionHandler } from './inlineCompletionHandler'
5+
import { SessionManager } from '../session/sessionManager'
6+
import { CodePercentageTracker } from '../tracker/codePercentageTracker'
7+
import { RecentEditTracker } from '../tracker/codeEditTracker'
8+
import { CursorTracker } from '../tracker/cursorTracker'
9+
import { StreakTracker } from '../tracker/streakTracker'
10+
import { TelemetryService } from '../../../shared/telemetry/telemetryService'
11+
import { UserWrittenCodeTracker } from '../../../shared/userWrittenCodeTracker'
12+
import { InlineCompletionTriggerKind, CancellationToken } from '@aws/language-server-runtimes/server-interface'
13+
import { EMPTY_RESULT } from '../contants/constants'
14+
import * as IdleWorkspaceManagerModule from '../../workspaceContext/IdleWorkspaceManager'
15+
import * as telemetryModule from '../telemetry/telemetry'
16+
17+
describe('InlineCompletionHandler', () => {
18+
const testDocument = TextDocument.create('file:///test.cs', 'csharp', 1, 'test content')
19+
20+
const completionParams = {
21+
textDocument: { uri: testDocument.uri },
22+
position: { line: 0, character: 0 },
23+
context: { triggerKind: InlineCompletionTriggerKind.Invoked },
24+
}
25+
26+
let handler: InlineCompletionHandler
27+
let completionSessionManager: SessionManager
28+
let amazonQServiceManager: any
29+
let codePercentageTracker: sinon.SinonStubbedInstance<CodePercentageTracker>
30+
let userWrittenCodeTracker: sinon.SinonStubbedInstance<UserWrittenCodeTracker>
31+
let recentEditTracker: sinon.SinonStubbedInstance<RecentEditTracker>
32+
let cursorTracker: sinon.SinonStubbedInstance<CursorTracker>
33+
let streakTracker: sinon.SinonStubbedInstance<StreakTracker>
34+
let telemetryService: sinon.SinonStubbedInstance<TelemetryService>
35+
let lsp: any
36+
let telemetry: any
37+
let credentialsProvider: any
38+
let workspace: any
39+
let logging: any
40+
let getTextDocument: sinon.SinonStub
41+
42+
beforeEach(() => {
43+
SessionManager.reset()
44+
completionSessionManager = SessionManager.getInstance('COMPLETIONS')
45+
46+
amazonQServiceManager = {
47+
getCodewhispererService: sinon.stub(),
48+
getConfiguration: sinon.stub().returns({ inlineSuggestions: {} }),
49+
}
50+
codePercentageTracker = sinon.createStubInstance(CodePercentageTracker)
51+
userWrittenCodeTracker = sinon.createStubInstance(UserWrittenCodeTracker)
52+
recentEditTracker = sinon.createStubInstance(RecentEditTracker)
53+
cursorTracker = sinon.createStubInstance(CursorTracker)
54+
streakTracker = sinon.createStubInstance(StreakTracker)
55+
telemetryService = sinon.createStubInstance(TelemetryService)
56+
57+
workspace = { getWorkspaceFolder: sinon.stub() }
58+
logging = { log: sinon.stub(), debug: sinon.stub() }
59+
getTextDocument = sinon.stub().resolves(testDocument)
60+
lsp = { getClientInitializeParams: sinon.stub() } as any
61+
telemetry = { emitMetric: sinon.stub() } as any
62+
credentialsProvider = { getConnectionMetadata: sinon.stub() } as any
63+
64+
// Stub IdleWorkspaceManager and telemetry functions
65+
sinon.stub(IdleWorkspaceManagerModule.IdleWorkspaceManager, 'recordActivityTimestamp')
66+
sinon.stub(telemetryModule, 'emitServiceInvocationTelemetry')
67+
sinon.stub(telemetryModule, 'emitServiceInvocationFailure')
68+
sinon.stub(telemetryModule, 'emitUserTriggerDecisionTelemetry')
69+
70+
handler = new InlineCompletionHandler(
71+
logging,
72+
workspace,
73+
amazonQServiceManager,
74+
completionSessionManager,
75+
codePercentageTracker,
76+
userWrittenCodeTracker,
77+
recentEditTracker,
78+
cursorTracker,
79+
streakTracker,
80+
telemetry,
81+
telemetryService,
82+
credentialsProvider,
83+
() => false,
84+
() => 1000,
85+
lsp
86+
)
87+
})
88+
89+
afterEach(() => {
90+
sinon.restore()
91+
})
92+
93+
it('should return empty result when concurrent request is in progress', async () => {
94+
// Make handler busy
95+
handler['isOnInlineCompletionHandlerInProgress'] = true
96+
97+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
98+
99+
assert.deepEqual(result, EMPTY_RESULT)
100+
sinon.assert.calledWith(logging.log, 'Skip concurrent inline completion')
101+
})
102+
103+
it('should return empty result when service manager not initialized', async () => {
104+
handler = new InlineCompletionHandler(
105+
logging,
106+
workspace,
107+
null as any,
108+
completionSessionManager,
109+
codePercentageTracker,
110+
userWrittenCodeTracker,
111+
recentEditTracker,
112+
cursorTracker,
113+
streakTracker,
114+
{ emitMetric: sinon.stub() } as any,
115+
telemetryService,
116+
{ getConnectionMetadata: sinon.stub() } as any,
117+
() => false,
118+
() => 1000,
119+
{ getClientInitializeParams: sinon.stub() } as any
120+
)
121+
122+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
123+
124+
assert.deepEqual(result, EMPTY_RESULT)
125+
sinon.assert.calledWith(logging.log, 'Amazon Q Service Manager not initialized yet')
126+
})
127+
128+
it('should return empty result when text document not found', async () => {
129+
getTextDocument.resolves(null)
130+
131+
const result = await handler.onInlineCompletion(completionParams, CancellationToken.None)
132+
133+
assert.deepEqual(result, EMPTY_RESULT)
134+
sinon.assert.calledWith(logging.log, `textDocument [${testDocument.uri}] not found`)
135+
})
136+
137+
it('should track cursor position when cursor tracker available', async () => {
138+
getTextDocument.resolves(null) // Will return early
139+
140+
await handler.onInlineCompletion(completionParams, CancellationToken.None)
141+
142+
sinon.assert.calledWith(cursorTracker.trackPosition, testDocument.uri, completionParams.position)
143+
})
144+
})

0 commit comments

Comments
 (0)