Skip to content

Commit 476c4ed

Browse files
committed
fix(cts): split requests and e2e tests
1 parent 5761ef5 commit 476c4ed

File tree

29 files changed

+1710
-1072
lines changed

29 files changed

+1710
-1072
lines changed

clients/algoliasearch-client-php/composer.lock

Lines changed: 1014 additions & 589 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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
@@ -17,6 +17,7 @@ public PythonCTSManager(String client) {
1717
public void addTestsSupportingFiles(List<SupportingFile> supportingFiles) {
1818
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/", "__init__.py"));
1919
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/requests", "__init__.py"));
20+
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/requests_e2e", "__init__.py"));
2021
supportingFiles.add(new SupportingFile("tests/__init__.mustache", "tests/output/python/tests/client", "__init__.py"));
2122
}
2223

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

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
public class TestsRequest extends TestsGenerator {
1616

1717
private final boolean withSnippets;
18+
private List<SupportingFile> supportingFiles;
1819

1920
public TestsRequest(String language, String client, boolean withSnippets) {
2021
super(language, client);
@@ -64,13 +65,39 @@ public void addSupportingFiles(List<SupportingFile> supportingFiles, String outp
6465
if (!available()) {
6566
return;
6667
}
68+
this.supportingFiles = supportingFiles;
69+
6770
supportingFiles.add(
6871
new SupportingFile(
6972
"tests/requests/requests.mustache",
7073
"tests/output/" + language + "/" + outputFolder + "/requests",
7174
Helpers.createClientName(client, language) + extension
7275
)
7376
);
77+
if (new File("templates/" + language + "/tests/requests/requests_e2e.mustache").exists()) {
78+
supportingFiles.add(
79+
new SupportingFile(
80+
"tests/requests/requests_e2e.mustache",
81+
"tests/output/" + language + "/" + outputFolder + "/requests_e2e",
82+
Helpers.createClientName(client, language) + extension
83+
)
84+
);
85+
}
86+
}
87+
88+
private String escapeBody(String body) {
89+
if (body == null) {
90+
return null;
91+
}
92+
93+
switch (language) {
94+
case "go": // jsonassert expect % to be formatted, we need to escape them
95+
return body.replace("%", "%%");
96+
case "dart": // Same thing but for $
97+
return body.replace("$", "\\$");
98+
default:
99+
return body;
100+
}
74101
}
75102

76103
@Override
@@ -82,6 +109,7 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
82109
}
83110

84111
List<Object> blocks = new ArrayList<>();
112+
List<Object> blocksE2E = new ArrayList<>();
85113
ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client);
86114

87115
bundle.put("e2eApiKey", client.equals("monitoring") ? "MONITORING_API_KEY" : "ALGOLIA_ADMIN_KEY");
@@ -138,15 +166,7 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
138166
req.request.body = "{}";
139167
}
140168

141-
// For golang, jsonassert expect % to be formatted, we need to escape them
142-
if (language.equals("go") && req.request.body != null) {
143-
req.request.body = req.request.body.replace("%", "%%");
144-
}
145-
146-
// For dart, same thing but for $
147-
if (language.equals("dart") && req.request.body != null) {
148-
req.request.body = req.request.body.replace("$", "\\$");
149-
}
169+
req.request.body = escapeBody(req.request.body);
150170

151171
// In a case of a `GET` or `DELETE` request, we want to assert if the body
152172
// is correctly parsed (absent from the payload)
@@ -156,7 +176,7 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
156176
}
157177

158178
if (req.response != null) {
159-
bundle.put("hasE2E", true);
179+
req.response.body = escapeBody(req.response.body);
160180
test.put("response", req.response);
161181
}
162182

@@ -219,7 +239,21 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
219239
}
220240

221241
blocks.add(testObj);
242+
243+
// extract e2e
244+
List<Map<String, Object>> e2e = tests.stream().filter(t -> t.get("response") != null).toList();
245+
if (e2e.size() > 0) {
246+
Map<String, Object> e2eObj = new HashMap<>();
247+
e2eObj.put("tests", e2e);
248+
e2eObj.put("operationId", operationId);
249+
blocksE2E.add(e2eObj);
250+
}
222251
}
223252
bundle.put("blocksRequests", blocks);
253+
if (!blocksE2E.isEmpty()) {
254+
bundle.put("blocksRequestsE2E", blocksE2E);
255+
} else {
256+
supportingFiles.removeIf(f -> f.getTemplateFile().equals("tests/requests/requests_e2e.mustache"));
257+
}
224258
}
225259
}

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`;
72+
const testsToDelete = `${testsOutputBase}/client ${testsOutputBase}/requests ${testsOutputBase}/requests_e2e`;
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}`;
80+
return `${testsOutputBase}/client/${clientName}${extension} ${testsOutputBase}/requests/${clientName}${extension} ${testsOutputBase}/requests_e2e/${clientName}${extension}`;
8181
})
8282
.join(' ');
8383

scripts/cts/runCts.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,12 @@ async function runCtsOne(language: string): Promise<void> {
3636
break;
3737
case 'php':
3838
await runComposerInstall();
39-
await run(`php ./clients/algoliasearch-client-php/vendor/bin/phpunit ${cwd}`, {
40-
language,
41-
});
39+
await run(
40+
`php ./clients/algoliasearch-client-php/vendor/bin/phpunit --testdox --fail-on-warning ${cwd}`,
41+
{
42+
language,
43+
},
44+
);
4245
break;
4346
case 'python':
4447
await run('poetry lock --no-update && poetry install --sync && poetry run pytest -vv', {

scripts/husky/pre-commit.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export function getPatterns() {
2222
for (const [language, { tests }] of Object.entries(clientConfig)) {
2323
entries.unshift(`tests/output/${language}/${tests.outputFolder}/client/**`);
2424
entries.unshift(`tests/output/${language}/${tests.outputFolder}/requests/**`);
25+
entries.unshift(`tests/output/${language}/${tests.outputFolder}/requests_e2e/**`);
2526
}
2627
return entries;
2728
}

templates/csharp/tests/requests/requests.mustache

Lines changed: 1 addition & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,13 @@ using Action = Algolia.Search.Models.Search.Action;
1212

1313
public class {{client}}RequestTests
1414
{
15-
private readonly {{client}} _client{{#hasE2E}}, _e2eClient{{/hasE2E}};
15+
private readonly {{client}} _client;
1616
private readonly EchoHttpRequester _echo;
1717

1818
public {{client}}RequestTests()
1919
{
2020
_echo = new EchoHttpRequester();
2121
_client = new {{client}}(new {{clientPrefix}}Config("appId", "apiKey"{{#hasRegionalHost}},"{{defaultRegion}}"{{/hasRegionalHost}}), _echo);
22-
23-
{{#hasE2E}}
24-
DotEnv.Load(options: new DotEnvOptions(ignoreExceptions: true, probeForEnv: true, probeLevelsToSearch: 8, envFilePaths: new[] { ".env" }));
25-
26-
var e2EAppId = Environment.GetEnvironmentVariable("ALGOLIA_APPLICATION_ID");
27-
if (e2EAppId == null)
28-
{
29-
throw new Exception("please provide an `ALGOLIA_APPLICATION_ID` env var for e2e tests");
30-
}
31-
32-
var e2EApiKey = Environment.GetEnvironmentVariable("{{e2eApiKey}}");
33-
if (e2EApiKey == null)
34-
{
35-
throw new Exception("please provide an `{{e2eApiKey}}` env var for e2e tests");
36-
}
37-
38-
_e2eClient = new {{client}}(new {{clientPrefix}}Config(e2EAppId, e2EApiKey{{#hasRegionalHost}},"{{defaultRegion}}"{{/hasRegionalHost}}));
39-
{{/hasE2E}}
4022
}
4123

4224
[Fact]
@@ -99,32 +81,6 @@ private readonly {{client}} _client{{#hasE2E}}, _e2eClient{{/hasE2E}};
9981
}
10082
{{/headers}}
10183
{{/request}}
102-
103-
104-
{{#response}}
105-
// e2e
106-
try {
107-
var resp = await _e2eClient.{{#lambda.pascalcase}}{{method}}{{/lambda.pascalcase}}Async{{#isGeneric}}<Hit>{{/isGeneric}}({{#parametersWithDataType}}{{> tests/generateParams}}{{^-last}},{{/-last}}{{/parametersWithDataType}}{{#hasRequestOptions}}, new RequestOptions(){
108-
{{#requestOptions.queryParameters}}
109-
QueryParameters = new Dictionary<string, object>(){ {{#parametersWithDataType}} {"{{{key}}}", {{> tests/requests/requestOptionsParams}} } {{^-last}},{{/-last}}{{/parametersWithDataType}} },
110-
{{/requestOptions.queryParameters}}
111-
{{#requestOptions.headers}}
112-
Headers = new Dictionary<string, string>(){ {{#parametersWithDataType}} {"{{{key}}}", "{{{value}}}" } {{^-last}},{{/-last}}{{/parametersWithDataType}} },
113-
{{/requestOptions.headers}}
114-
}{{/hasRequestOptions}});
115-
{{#statusCode}}
116-
// Check status code {{statusCode}}
117-
Assert.NotNull(resp);
118-
{{/statusCode}}
119-
120-
{{#body}}
121-
JsonAssert.EqualOverrideDefault("{{#lambda.escapeQuotes}}{{{.}}}{{/lambda.escapeQuotes}}", JsonSerializer.Serialize(resp, JsonConfig.Options), new JsonDiffConfig(true));
122-
{{/body}}
123-
} catch (Exception e)
124-
{
125-
Assert.Fail("An exception was thrown: " + e.Message);
126-
}
127-
{{/response}}
12884
}
12985
{{/tests}}
13086
{{/blocksRequests}}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// {{generationBanner}}
2+
using Algolia.Search.Http;
3+
using Algolia.Search.Clients;
4+
using Algolia.Search.Models.{{clientPrefix}};
5+
using Algolia.Search.Serializer;
6+
using Algolia.Search.Tests.Utils;
7+
using Xunit;
8+
using System.Text.Json;
9+
using Quibble.Xunit;
10+
using dotenv.net;
11+
using Action = Algolia.Search.Models.Search.Action;
12+
13+
public class {{client}}RequestTestsE2E
14+
{
15+
private readonly {{client}} _client;
16+
17+
public {{client}}RequestTestsE2E()
18+
{
19+
DotEnv.Load(options: new DotEnvOptions(ignoreExceptions: true, probeForEnv: true, probeLevelsToSearch: 8, envFilePaths: new[] { ".env" }));
20+
21+
var appId = Environment.GetEnvironmentVariable("ALGOLIA_APPLICATION_ID");
22+
if (appId == null)
23+
{
24+
throw new Exception("please provide an `ALGOLIA_APPLICATION_ID` env var for e2e tests");
25+
}
26+
27+
var apiKey = Environment.GetEnvironmentVariable("{{e2eApiKey}}");
28+
if (apiKey == null)
29+
{
30+
throw new Exception("please provide an `{{e2eApiKey}}` env var for e2e tests");
31+
}
32+
33+
_client = new {{client}}(new {{clientPrefix}}Config(appId, apiKey{{#hasRegionalHost}},"{{defaultRegion}}"{{/hasRegionalHost}}));
34+
}
35+
36+
[Fact]
37+
public void Dispose()
38+
{
39+
40+
}
41+
42+
{{#blocksRequestsE2E}}
43+
{{#tests}}
44+
[Fact(DisplayName = "{{{testName}}}")]
45+
public async Task {{#lambda.pascalcase}}{{method}}Test{{testIndex}}{{/lambda.pascalcase}}()
46+
{
47+
try {
48+
var resp = await _client.{{#lambda.pascalcase}}{{method}}{{/lambda.pascalcase}}Async{{#isGeneric}}<Hit>{{/isGeneric}}({{#parametersWithDataType}}{{> tests/generateParams}}{{^-last}},{{/-last}}{{/parametersWithDataType}}{{#hasRequestOptions}}, new RequestOptions(){
49+
{{#requestOptions.queryParameters}}
50+
QueryParameters = new Dictionary<string, object>(){ {{#parametersWithDataType}} {"{{{key}}}", {{> tests/requests/requestOptionsParams}} } {{^-last}},{{/-last}}{{/parametersWithDataType}} },
51+
{{/requestOptions.queryParameters}}
52+
{{#requestOptions.headers}}
53+
Headers = new Dictionary<string, string>(){ {{#parametersWithDataType}} {"{{{key}}}", "{{{value}}}" } {{^-last}},{{/-last}}{{/parametersWithDataType}} },
54+
{{/requestOptions.headers}}
55+
}{{/hasRequestOptions}});
56+
{{#response}}
57+
{{#statusCode}}
58+
// Check status code {{statusCode}}
59+
Assert.NotNull(resp);
60+
{{/statusCode}}
61+
62+
{{#body}}
63+
JsonAssert.EqualOverrideDefault("{{#lambda.escapeQuotes}}{{{.}}}{{/lambda.escapeQuotes}}", JsonSerializer.Serialize(resp, JsonConfig.Options), new JsonDiffConfig(true));
64+
{{/body}}
65+
} catch (Exception e)
66+
{
67+
Assert.Fail("An exception was thrown: " + e.Message);
68+
}
69+
{{/response}}
70+
}
71+
{{/tests}}
72+
{{/blocksRequestsE2E}}
73+
}

templates/go/tests/requests/requests.mustache

Lines changed: 7 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,16 @@ package requests
33

44
import (
55
"encoding/json"
6-
"net/url"
7-
"os"
8-
"testing"
9-
"time"
10-
"strings"
6+
"testing"
7+
"time"
118

12-
"github.com/kinbiko/jsonassert"
13-
"github.com/stretchr/testify/require"
9+
"github.com/kinbiko/jsonassert"
10+
"github.com/stretchr/testify/require"
1411

15-
"github.com/joho/godotenv"
12+
"gotests/tests"
1613

17-
"gotests/tests"
18-
19-
"github.com/algolia/algoliasearch-client-go/v4/algolia/{{clientImport}}"
20-
"github.com/algolia/algoliasearch-client-go/v4/algolia/transport"
14+
"github.com/algolia/algoliasearch-client-go/v4/algolia/{{clientImport}}"
15+
"github.com/algolia/algoliasearch-client-go/v4/algolia/transport"
2116
)
2217

2318
func create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t *testing.T) (*{{clientPrefix}}.APIClient, *tests.EchoRequester) {
@@ -38,24 +33,6 @@ func create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t *t
3833
return client, echo
3934
}
4035

41-
{{#hasE2E}}
42-
func createE2E{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t *testing.T) *{{clientPrefix}}.APIClient {
43-
t.Helper()
44-
45-
appID := os.Getenv("ALGOLIA_APPLICATION_ID")
46-
if appID == "" && os.Getenv("CI") != "true" {
47-
err := godotenv.Load("../../../../.env")
48-
require.NoError(t, err)
49-
appID = os.Getenv("ALGOLIA_APPLICATION_ID")
50-
}
51-
apiKey := os.Getenv("{{e2eApiKey}}")
52-
client, err := {{clientPrefix}}.NewClient(appID, apiKey, {{#hasRegionalHost}}{{clientPrefix}}.{{#lambda.uppercase}}{{defaultRegion}}{{/lambda.uppercase}},{{/hasRegionalHost}})
53-
require.NoError(t, err)
54-
55-
return client
56-
}
57-
{{/hasE2E}}
58-
5936
{{#blocksRequests}}
6037
func Test{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}_{{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}}(t *testing.T) {
6138
client, echo := create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t)
@@ -102,37 +79,6 @@ func Test{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}_{{#lambda.ti
10279
}
10380
{{/queryParameters}}
10481
{{/request}}
105-
{{#response}}
106-
clientE2E := createE2E{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t)
107-
res, err := clientE2E.{{#lambda.titlecase}}{{method}}{{/lambda.titlecase}}({{#hasOperationParams}}client.NewApi{{#lambda.titlecase}}{{method}}{{/lambda.titlecase}}Request(
108-
{{#parametersWithDataType}}{{#required}}{{> tests/generateParams}},{{/required}}{{/parametersWithDataType}}
109-
){{#parametersWithDataType}}{{^required}}.With{{#lambda.pascalcase}}{{{key}}}{{/lambda.pascalcase}}({{> tests/generateParams}}){{/required}}{{/parametersWithDataType}}{{/hasOperationParams}}{{#requestOptions}}{{#hasOperationParams}},{{/hasOperationParams}}
110-
{{#queryParameters.parametersWithDataType}}{{clientPrefix}}.QueryParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/queryParameters.parametersWithDataType}}{{#headers.parametersWithDataType}}{{clientPrefix}}.HeaderParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/headers.parametersWithDataType}}
111-
{{/requestOptions}})
112-
require.NoError(t, err)
113-
_ = res
114-
115-
{{#body}}
116-
rawBody, err := json.Marshal(res)
117-
require.NoError(t, err)
118-
119-
var rawBodyMap any
120-
err = json.Unmarshal(rawBody, &rawBodyMap)
121-
require.NoError(t, err)
122-
123-
expectedBodyRaw := `{{{.}}}`
124-
var expectedBody any
125-
err = json.Unmarshal([]byte(expectedBodyRaw), &expectedBody)
126-
require.NoError(t, err)
127-
128-
unionBody := tests.Union(expectedBody, rawBodyMap)
129-
unionBodyRaw, err := json.Marshal(unionBody)
130-
require.NoError(t, err)
131-
132-
jaE2E := jsonassert.New(t)
133-
jaE2E.Assertf(expectedBodyRaw, strings.ReplaceAll(string(unionBodyRaw), "%", "%%"))
134-
{{/body}}
135-
{{/response}}
13682
})
13783
{{/tests}}
13884
}

0 commit comments

Comments
 (0)