Skip to content

Commit 23fd55c

Browse files
authored
chore(CTS): benchmark the search method (#3328)
1 parent 850a96f commit 23fd55c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1167
-650
lines changed

.github/workflows/check.yml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,17 +242,17 @@ jobs:
242242
key: node-modules-tests-${{ hashFiles('tests/output/javascript/yarn.lock') }}
243243

244244
- name: Run unit CTS
245-
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --exclude-e2e
245+
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --no-e2e
246246

247247
- name: Run e2e CTS
248248
id: cts-e2e
249249
continue-on-error: true
250250
if: ${{ !github.event.pull_request.head.repo.fork }}
251-
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --exclude-unit
251+
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --no-client --no-requests
252252

253253
- name: Retry e2e CTS
254254
if: ${{ !github.event.pull_request.head.repo.fork && steps.cts-e2e.outcome == 'failure' }}
255-
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --exclude-unit
255+
run: yarn cli cts run javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }} --no-client --no-requests
256256

257257
- name: Generate code snippets for documentation
258258
run: yarn cli snippets javascript ${{ fromJSON(needs.setup.outputs.JAVASCRIPT_DATA).toRun }}
@@ -336,17 +336,17 @@ jobs:
336336
run: yarn cli cts generate ${{ matrix.client.language }} ${{ matrix.client.toRun }}
337337

338338
- name: Run unit CTS
339-
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --exclude-e2e
339+
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --no-e2e
340340

341341
- name: Run e2e CTS
342342
id: cts-e2e
343343
continue-on-error: true
344344
if: ${{ !github.event.pull_request.head.repo.fork }}
345-
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --exclude-unit
345+
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --no-client --no-requests
346346

347347
- name: Retry e2e CTS
348348
if: ${{ !github.event.pull_request.head.repo.fork && steps.cts-e2e.outcome == 'failure' }}
349-
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --exclude-unit
349+
run: yarn cli cts run ${{ matrix.client.language }} ${{ matrix.client.toRun }} --no-client --no-requests
350350

351351
- name: Generate code snippets for documentation
352352
run: yarn cli snippets ${{ matrix.client.language }} ${{ matrix.client.toRun }}
@@ -504,7 +504,7 @@ jobs:
504504
| 🪓 Triggered by | [`${{ github.sha }}`](${{ github.event.pull_request.base.repo.html_url }}/commit/${{ github.sha }}) |
505505
| 🍃 Generated commit | [`${{ steps.pushGeneratedCode.outputs.GENERATED_COMMIT }}`](${{ github.event.pull_request.base.repo.html_url }}/commit/${{ steps.pushGeneratedCode.outputs.GENERATED_COMMIT }}) |
506506
| 🌲 Generated branch | [`generated/${{ github.head_ref }}`](${{ github.event.pull_request.base.repo.html_url }}/tree/generated/${{ github.head_ref }}) |
507-
507+
508508
- name: Build website
509509
if: ${{ github.ref == 'refs/heads/main' || github.base_ref == 'main' }}
510510
run: yarn website:build

generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ public void processOpts() {
6161
ctsManager.addTestsSupportingFiles(supportingFiles);
6262

6363
testsGenerators.add(new TestsRequest(language, client, false));
64-
testsGenerators.add(new TestsClient(language, client));
64+
testsGenerators.add(new TestsClient(language, client, true));
65+
testsGenerators.add(new TestsClient(language, client, false));
6566
} else if (mode.equals("snippets")) {
6667
ctsManager.addSnippetsSupportingFiles(supportingFiles);
6768

@@ -148,6 +149,8 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> obj
148149
if (hasRegionalHost) {
149150
bundle.put("defaultRegion", regionVariable.defaultValue);
150151
}
152+
// special lambda for dynamic templates
153+
bundle.put("dynamicTemplate", new DynamicTemplateLambda(this));
151154
bundle.put("lambda", lambda);
152155

153156
ctsManager.addDataToBundle(bundle);
@@ -170,9 +173,6 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> obj
170173
}
171174
}
172175

173-
// special lambda for dynamic templates
174-
bundle.put("dynamicTemplate", new DynamicTemplateLambda(this));
175-
176176
// Generation notice, added on every generated files
177177
bundle.put("generationBanner", Helpers.setGenerationBanner(additionalProperties));
178178

generators/src/main/java/com/algolia/codegen/cts/manager/PythonCTSManager.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public void addTestsSupportingFiles(List<SupportingFile> supportingFiles) {
1919
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/requests", "__init__.py"));
2020
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/client", "__init__.py"));
2121
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/e2e", "__init__.py"));
22+
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/benchmark", "__init__.py"));
2223
}
2324

2425
@Override

generators/src/main/java/com/algolia/codegen/cts/tests/ClientTestData.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class Step {
1414

1515
public String type;
1616
public String method;
17+
public int times;
1718
public Map<String, Object> parameters;
1819
public Expected expected;
1920
}

generators/src/main/java/com/algolia/codegen/cts/tests/TestsClient.java

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616

1717
public class TestsClient extends TestsGenerator {
1818

19-
public TestsClient(String language, String client) {
19+
private final boolean withBenchmark;
20+
private final String testType;
21+
22+
public TestsClient(String language, String client, boolean withBenchmark) {
2023
super(language, client);
24+
this.withBenchmark = withBenchmark;
25+
this.testType = withBenchmark ? "benchmark" : "client";
2126
}
2227

2328
@Override
@@ -27,8 +32,17 @@ public boolean available() {
2732
return false;
2833
}
2934

30-
File templates = new File("templates/" + language + "/tests/client/suite.mustache");
31-
return templates.exists();
35+
File templates = new File("templates/" + language + "/tests/client/" + testType + ".mustache");
36+
if (!templates.exists()) {
37+
return false;
38+
}
39+
40+
if (withBenchmark) {
41+
File benchmarkTest = new File("tests/CTS/benchmark/" + client + "/benchmark.json");
42+
return benchmarkTest.exists();
43+
}
44+
45+
return true;
3246
}
3347

3448
@Override
@@ -38,15 +52,15 @@ public void addSupportingFiles(List<SupportingFile> supportingFiles, String outp
3852
}
3953
supportingFiles.add(
4054
new SupportingFile(
41-
"tests/client/suite.mustache",
42-
"tests/output/" + language + "/" + outputFolder + "/client",
55+
"tests/client/" + testType + ".mustache",
56+
"tests/output/" + language + "/" + outputFolder + "/" + testType,
4357
Helpers.createClientName(client, language) + extension
4458
)
4559
);
4660
}
4761

4862
public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation> operations, Map<String, Object> bundle) throws Exception {
49-
Map<String, ClientTestData[]> cts = loadCTS("client", client, ClientTestData[].class);
63+
Map<String, ClientTestData[]> cts = loadCTS(testType, client, ClientTestData[].class);
5064
ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client);
5165

5266
List<Object> blocks = new ArrayList<>();
@@ -62,17 +76,18 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
6276
testOut.put("testName", test.testName);
6377
testOut.put("testIndex", testIndex++);
6478
testOut.put("autoCreateClient", test.autoCreateClient);
79+
testOut.put("useEchoRequester", true);
80+
testOut.put("isBenchmark", withBenchmark);
6581
for (Step step : test.steps) {
6682
Map<String, Object> stepOut = new HashMap<>();
67-
stepOut.put("useEchoRequester", true);
83+
if (step.times > 1) stepOut.put("times", step.times);
6884
CodegenOperation ope = null;
6985
if (step.type.equals("createClient")) {
7086
stepOut.put("stepTemplate", "tests/client/createClient.mustache");
7187
stepOut.put("isCreateClient", true); // TODO: remove once kotlin is converted
7288

7389
boolean hasCustomHosts = step.parameters != null && step.parameters.containsKey("customHosts");
74-
75-
stepOut.put("useEchoRequester", !hasCustomHosts);
90+
if (hasCustomHosts) testOut.put("useEchoRequester", false);
7691
stepOut.put("hasCustomHosts", hasCustomHosts);
7792
if (hasCustomHosts) {
7893
stepOut.put("customHosts", step.parameters.get("customHosts"));
@@ -95,6 +110,10 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
95110
stepOut.put("stepTemplate", "tests/client/method.mustache");
96111
stepOut.put("isMethod", true); // TODO: remove once kotlin is converted
97112
stepOut.put("hasParams", ope.hasParams);
113+
stepOut.put("isGeneric", (boolean) ope.vendorExtensions.getOrDefault("x-is-generic", false));
114+
if (ope.returnType != null && ope.returnType.length() > 0) {
115+
stepOut.put("returnType", Helpers.toPascalCase(ope.returnType));
116+
}
98117

99118
// set on testOut because we need to wrap everything for java.
100119
testOut.put("isHelper", (boolean) ope.vendorExtensions.getOrDefault("x-helper", false));
@@ -181,6 +200,6 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
181200
testObj.put("testType", blockEntry.getKey());
182201
blocks.add(testObj);
183202
}
184-
bundle.put("blocksClient", blocks);
203+
bundle.put(withBenchmark ? "blocksBenchmark" : "blocksClient", blocks);
185204
}
186205
}

generators/src/main/java/com/algolia/codegen/cts/tests/TestsGenerator.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,11 @@ protected <T> Map<String, T> loadCTS(String path, String clientName, Class<T> js
4141
if (!dir.exists()) {
4242
throw new CTSException("CTS not found at " + dir.getAbsolutePath(), true);
4343
}
44-
if (!commonTestDir.exists()) {
45-
throw new CTSException("CTS not found at " + commonTestDir.getAbsolutePath(), true);
46-
}
4744
List<File> allTests = new ArrayList<>();
4845
Collections.addAll(allTests, dir.listFiles());
49-
Collections.addAll(allTests, commonTestDir.listFiles());
46+
if (commonTestDir.exists()) {
47+
Collections.addAll(allTests, commonTestDir.listFiles());
48+
}
5049

5150
Map<String, T> cts = new TreeMap<>();
5251

scripts/ci/githubActions/createMatrix.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ async function createClientMatrix(baseBranch: string): Promise<void> {
6969
const testsRootFolder = `tests/output/${language}`;
7070
const testsOutputBase = `${testsRootFolder}/${getTestOutputFolder(language)}`;
7171
// We delete tests to ensure the CI only run tests against what changed.
72-
const testsToDelete = `${testsOutputBase}/client ${testsOutputBase}/requests ${testsOutputBase}/e2e`;
72+
const testsToDelete = `${testsOutputBase}/client ${testsOutputBase}/requests ${testsOutputBase}/e2e ${testsOutputBase}/benchmark`;
7373

7474
// We only store tests of clients that ran during this job, the rest stay as is
7575
let testsToStore = matrix[language].toRun
7676
.map((client) => {
7777
const clientName = createClientName(client, language);
7878
const extension = getTestExtension(language);
7979

80-
return `${testsOutputBase}/client/${clientName}${extension} ${testsOutputBase}/requests/${clientName}${extension} ${testsOutputBase}/e2e/${clientName}${extension}`;
80+
return `${testsOutputBase}/client/${clientName}${extension} ${testsOutputBase}/requests/${clientName}${extension} ${testsOutputBase}/e2e/${clientName}${extension} ${testsOutputBase}/benchmark/${clientName}${extension}`;
8181
})
8282
.join(' ');
8383

scripts/cli/index.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,15 @@ ctsCommand
129129
.addArgument(args.language)
130130
.addArgument(args.clients)
131131
.option(flags.verbose.flag, flags.verbose.description)
132-
.option('-e, --exclude-e2e', "don't run the e2e tests, useful for offline testing")
133-
.option('-u, --exclude-unit', "don't run the client and requests tests")
132+
.option('-e, --no-e2e', 'run the e2e tests, that requires internet connection')
133+
.option('-c, --no-client', 'run the client tests')
134+
.option('-r, --no-requests', 'run the requests tests')
135+
.option('-b, --benchmark', 'run the benchmarks')
134136
.action(
135137
async (
136138
langArg: LangArg,
137139
clientArg: string[],
138-
{ verbose, excludeE2e: excludeE2E, excludeUnit },
140+
{ verbose, e2e, client: includeClient, requests, benchmark },
139141
) => {
140142
const { language, client } = transformSelection({
141143
langArg,
@@ -144,12 +146,12 @@ ctsCommand
144146

145147
setVerbose(Boolean(verbose));
146148

147-
await runCts(
148-
language === ALL ? LANGUAGES : [language],
149-
client,
150-
Boolean(excludeE2E),
151-
Boolean(excludeUnit),
152-
);
149+
await runCts(language === ALL ? LANGUAGES : [language], client, {
150+
client: includeClient,
151+
requests,
152+
e2e,
153+
benchmark,
154+
});
153155
},
154156
);
155157

scripts/cts/runCts.ts

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,40 @@ import { getTestOutputFolder } from '../config.js';
55
import { createSpinner } from '../spinners.js';
66
import type { Language } from '../types.js';
77

8-
import { startTestServer } from './testServer';
8+
import { startBenchmarkServer, startTestServer } from './testServer';
9+
import { printBenchmarkReport } from './testServer/benchmark.js';
910
import { assertChunkWrapperValid } from './testServer/chunkWrapper.js';
1011
import { assertValidReplaceAllObjects } from './testServer/replaceAllObjects.js';
1112
import { assertValidTimeouts } from './testServer/timeout.js';
1213
import { assertValidWaitForApiKey } from './testServer/waitForApiKey.js';
1314

14-
async function runCtsOne(
15-
language: Language,
16-
excludeE2E: boolean,
17-
excludeUnit: boolean,
18-
): Promise<void> {
19-
const cwd = `tests/output/${language}`;
15+
export type CTSType = 'benchmark' | 'client' | 'e2e' | 'requests';
2016

21-
const folders: string[] = [];
22-
if (!excludeE2E) {
23-
// check if the folder has files
24-
const e2eFolder = toAbsolutePath(
25-
`tests/output/${language}/${getTestOutputFolder(language)}/e2e`,
17+
async function buildFilter(
18+
language: Language,
19+
suites: Record<CTSType, boolean>,
20+
): Promise<CTSType[]> {
21+
const folders: CTSType[] = [];
22+
for (const [suite, include] of Object.entries(suites)) {
23+
// check if the folder has files in it
24+
const folder = toAbsolutePath(
25+
`tests/output/${language}/${getTestOutputFolder(language)}/${suite}`,
2626
);
2727
if (
28-
(await exists(e2eFolder)) &&
29-
(await fsp.readdir(e2eFolder)).filter((f) => f !== '__init__.py' && f !== '__pycache__')
30-
.length > 0
28+
include &&
29+
(await exists(folder)) &&
30+
(await fsp.readdir(folder)).filter((f) => f !== '__init__.py' && f !== '__pycache__').length >
31+
0
3132
)
32-
folders.push('e2e');
33-
}
34-
if (!excludeUnit) {
35-
folders.push('client', 'requests');
33+
folders.push(suite as CTSType);
3634
}
3735

36+
return folders;
37+
}
38+
39+
async function runCtsOne(language: Language, suites: Record<CTSType, boolean>): Promise<void> {
40+
const cwd = `tests/output/${language}`;
41+
const folders = await buildFilter(language, suites);
3842
const spinner = createSpinner(`running cts for '${language}' in folder(s) ${folders.join(', ')}`);
3943

4044
if (folders.length === 0) {
@@ -81,7 +85,10 @@ async function runCtsOne(
8185
);
8286
break;
8387
case 'kotlin':
84-
await run('./gradle/gradlew -p tests/output/kotlin allTests', { language });
88+
await run(
89+
`./gradle/gradlew -p tests/output/kotlin jvmTest ${filter((f) => `--tests 'com.algolia.${f}*'`)}`,
90+
{ language },
91+
);
8592
break;
8693
case 'php':
8794
await runComposerInstall();
@@ -133,20 +140,28 @@ async function runCtsOne(
133140
export async function runCts(
134141
languages: Language[],
135142
clients: string[],
136-
excludeE2E: boolean,
137-
excludeUnit: boolean,
143+
suites: Record<CTSType, boolean>,
138144
): Promise<void> {
139-
const useTestServer = !excludeUnit && (clients.includes('search') || clients.includes('all'));
140-
let close: () => Promise<void> = async () => {};
145+
const useTestServer = suites.client && (clients.includes('search') || clients.includes('all'));
146+
const useBenchmarkServer =
147+
suites.benchmark && (clients.includes('search') || clients.includes('all'));
148+
149+
let closeTestServer: () => Promise<void> = async () => {};
141150
if (useTestServer) {
142-
close = await startTestServer();
151+
closeTestServer = await startTestServer();
152+
}
153+
154+
let closeBenchmarkServer: () => Promise<void> = async () => {};
155+
if (useBenchmarkServer) {
156+
closeBenchmarkServer = await startBenchmarkServer();
143157
}
158+
144159
for (const lang of languages) {
145-
await runCtsOne(lang, excludeE2E, excludeUnit);
160+
await runCtsOne(lang, suites);
146161
}
147162

148163
if (useTestServer) {
149-
await close();
164+
await closeTestServer();
150165

151166
const skip = (lang: Language): number => (languages.includes(lang) ? 1 : 0);
152167

@@ -155,4 +170,10 @@ export async function runCts(
155170
assertValidReplaceAllObjects(languages.length - skip('dart') - skip('scala'));
156171
assertValidWaitForApiKey(languages.length - skip('dart') - skip('scala'));
157172
}
173+
174+
if (useBenchmarkServer) {
175+
await closeBenchmarkServer();
176+
177+
printBenchmarkReport();
178+
}
158179
}

0 commit comments

Comments
 (0)