Skip to content

Commit 401fc1e

Browse files
authored
test(amazonq): performance test for LSP setup. (aws#5677)
## Problem continuation of reliability work ## Solution `tryInstallLsp` in `src/amazonq/lsp/lspController.ts` captures many potentially high risk paths in a single function, such as some I/O operations, and heavy use of the `admZip` dependency. Two performance tests were added, one for handling zipping and maniupulating many small files, and one with few large files. Thresholds are set very leniently to avoid flaky tests. The "many files" test does 250 files w/ 10 bytes each. The "large files" does 10 files w/ 1000 bytes each. These values were chosen to avoid flakiness in CI. Included in this PR is removing the use of fs-extra in `src/amazonq/lsp/lspController.ts`
1 parent a7256e5 commit 401fc1e

File tree

2 files changed

+118
-1
lines changed

2 files changed

+118
-1
lines changed

packages/core/src/amazonq/lsp/lspController.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
import * as vscode from 'vscode'
77
import * as path from 'path'
8-
import { createWriteStream } from 'fs'
98
import * as crypto from 'crypto'
9+
import { createWriteStream } from 'fs'
1010
import { getLogger } from '../../shared/logger/logger'
1111
import { CurrentWsFolders, collectFilesForIndex } from '../../shared/utilities/workspaceUtils'
1212
import fetch from 'node-fetch'
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*!
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
import assert from 'assert'
6+
import sinon from 'sinon'
7+
import { Content } from 'aws-sdk/clients/codecommit'
8+
import AdmZip from 'adm-zip'
9+
import path from 'path'
10+
import { LspController } from '../amazonq'
11+
import { fs, getRandomString, globals } from '../shared'
12+
import { createTestWorkspace } from '../test/testUtil'
13+
import { performanceTest } from '../shared/performance/performance'
14+
15+
// fakeFileContent is matched to fakeQServerContent based on hash.
16+
const fakeHash = '4eb2865c8f40a322aa04e17d8d83bdaa605d6f1cb363af615240a5442a010e0aef66e21bcf4c88f20fabff06efe8a214'
17+
18+
const fakeQServerContent = {
19+
filename: 'qserver-fake.zip',
20+
url: 'https://aws-language-servers/fake.zip',
21+
hashes: [`sha384:${fakeHash}`],
22+
bytes: 93610849,
23+
serverVersion: '1.1.1',
24+
}
25+
26+
const fakeNodeContent = {
27+
filename: 'fake-file',
28+
url: 'https://aws-language-servers.fake-file',
29+
hashes: [`sha384:${fakeHash}`],
30+
bytes: 94144448,
31+
serverVersion: '1.1.1',
32+
}
33+
34+
function createStubs(numberOfFiles: number, fileSize: number) {
35+
// Avoid making HTTP request or mocking giant manifest, stub what we need directly from request.
36+
sinon.stub(LspController.prototype, 'fetchManifest')
37+
// Directly feed the runtime specifications.
38+
sinon.stub(LspController.prototype, 'getQserverFromManifest').returns(fakeQServerContent)
39+
sinon.stub(LspController.prototype, 'getNodeRuntimeFromManifest').returns(fakeNodeContent)
40+
// avoid fetch call.
41+
sinon.stub(LspController.prototype, '_download').callsFake(getFakeDownload(numberOfFiles, fileSize))
42+
// Hard code the hash since we are creating files on the spot, whose hashes can't be predicted.
43+
sinon.stub(LspController.prototype, 'getFileSha384').resolves(fakeHash)
44+
// Don't allow tryInstallLsp to move runtimes out of temporary folder.
45+
sinon.stub(fs, 'rename')
46+
}
47+
48+
/**
49+
* Creates a fake zip with some files in it.
50+
* @param filepath where to write the zip to.
51+
* @param _content unused parameter, for compatability with real function.
52+
*/
53+
const getFakeDownload = function (numberOfFiles: number, fileSize: number) {
54+
return async function (filepath: string, _content: Content) {
55+
const dummyFilesPath = (
56+
await createTestWorkspace(numberOfFiles, {
57+
fileNamePrefix: 'fakeFile',
58+
fileContent: getRandomString(fileSize),
59+
workspaceName: 'workspace',
60+
})
61+
).uri.fsPath
62+
await fs.writeFile(path.join(dummyFilesPath, 'qserver'), 'this value shouldnt matter')
63+
const zip = new AdmZip()
64+
zip.addLocalFolder(dummyFilesPath)
65+
zip.writeZip(filepath)
66+
}
67+
}
68+
69+
function performanceTestWrapper(numFiles: number, fileSize: number) {
70+
return performanceTest(
71+
{
72+
testRuns: 10,
73+
linux: {
74+
userCpuUsage: 100,
75+
systemCpuUsage: 35,
76+
heapTotal: 6,
77+
duration: 15,
78+
},
79+
darwin: {
80+
userCpuUsage: 100,
81+
systemCpuUsage: 35,
82+
heapTotal: 6,
83+
duration: 15,
84+
},
85+
win32: {
86+
userCpuUsage: 100,
87+
systemCpuUsage: 35,
88+
heapTotal: 6,
89+
duration: 15,
90+
},
91+
},
92+
'many small files in zip',
93+
function () {
94+
return {
95+
setup: async () => {
96+
createStubs(numFiles, fileSize)
97+
},
98+
execute: async () => {
99+
return await LspController.instance.tryInstallLsp(globals.context)
100+
},
101+
verify: async (_setup: any, result: boolean) => {
102+
assert.ok(result)
103+
},
104+
}
105+
}
106+
)
107+
}
108+
109+
describe('tryInstallLsp', function () {
110+
afterEach(function () {
111+
sinon.restore()
112+
})
113+
describe('performance tests', function () {
114+
performanceTestWrapper(250, 10)
115+
performanceTestWrapper(10, 1000)
116+
})
117+
})

0 commit comments

Comments
 (0)