Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(cts): update doc and client test doc #766

Merged
merged 3 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,6 @@ public Map<String, Object> postProcessSupportingFileData(Map<String, Object> obj
bundle.put("defaultRegion", client.equals("predict") ? "ew" : "us");
bundle.put("lambda", lambda);

if (language.equals("javascript")) {
bundle.put("npmNamespace", Utils.getClientConfigField(language, "npmNamespace"));
}

ctsManager.addDataToBundle(bundle);

for (TestsGenerator testGen : testsGenerators) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void addSupportingFiles(List<SupportingFile> supportingFiles) {}
@Override
public void addDataToBundle(Map<String, Object> bundle) throws GeneratorException {
bundle.put("utilsPackageVersion", Utils.getClientConfigField("javascript", "utilsPackageVersion"));
bundle.put("npmNamespace", Utils.getClientConfigField("javascript", "npmNamespace"));

JsonNode openApiToolsConfig = Utils.readJsonFile("config/openapitools.json").get("generator-cli").get("generators");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,11 @@ private Map<String, Object> traverseParams(
if (language.equals("java") && paramName.startsWith("_")) {
finalParamName = paramName.substring(1);
}
Boolean isFirstLevel = suffix == 0;

Map<String, Object> testOutput = createDefaultOutput();
testOutput.put("key", finalParamName);
testOutput.put("parentSuffix", suffix - 1);
testOutput.put("isFirstLevel", isFirstLevel);
testOutput.put("hasGeneratedKey", finalParamName.matches("(.*)_[0-9]$"));
testOutput.put("useAnonymousKey", !finalParamName.matches("(.*)_[0-9]$") && suffix != 0);
testOutput.put("suffix", suffix);
testOutput.put("parent", parent);
testOutput.put("objectName", Utils.capitalize(baseType));
Expand Down Expand Up @@ -161,13 +159,11 @@ private Map<String, Object> traverseParams(String paramName, Object param, Strin
if (language.equals("java") && paramName.startsWith("_")) {
finalParamName = paramName.substring(1);
}
Boolean isFirstLevel = suffix == 0;

Map<String, Object> testOutput = createDefaultOutput();
testOutput.put("key", finalParamName);
testOutput.put("parentSuffix", suffix - 1);
testOutput.put("isFirstLevel", isFirstLevel);
testOutput.put("hasGeneratedKey", finalParamName.matches("(.*)_[0-9]$"));
testOutput.put("useAnonymousKey", !finalParamName.matches("(.*)_[0-9]$") && suffix != 0);
testOutput.put("suffix", suffix);
testOutput.put("parent", parent);
// cannot determine objectName with inference
Expand Down
2 changes: 1 addition & 1 deletion templates/php/tests/generateParams.mustache
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{^isFirstLevel}}{{^hasGeneratedKey}}"{{{key}}}" => {{/hasGeneratedKey}}{{/isFirstLevel}}
{{#useAnonymousKey}}"{{{key}}}" => {{/useAnonymousKey}}
{{#isNull}}
null,
{{/isNull}}
Expand Down
3 changes: 2 additions & 1 deletion website/docs/contributing/add-new-language.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,8 @@ This parameter **must** be the last parameter of a method, and allow a user to o

### Requesters

> TODO: informations
The requester needs to be configurable, or overwriten completely and use a user defined requester.
shortcuts marked this conversation as resolved.
Show resolved Hide resolved
The default requester must be the classic HTTP requester, and it's possible to provide other alternatives like an Echo Requester that just send the request back.
shortcuts marked this conversation as resolved.
Show resolved Hide resolved

### Logger

Expand Down
114 changes: 77 additions & 37 deletions website/docs/contributing/testing/common-test-suite.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ title: Common Test Suite

# Common Test Suite

The CTS aims at ensuring minimal working operation for the API clients, by comparing the request formed by sample parameters.
It is automatically generated for all languages, from a JSON entry point.
The CTS gather multiple types of tests that make sure our API clients generate the correct requests and throws the correct error, it does not aim at testing the engine.
It is automatically generated for all languages, from JSON files and the specs.
shortcuts marked this conversation as resolved.
Show resolved Hide resolved

:::info

Expand All @@ -17,7 +17,13 @@ Common Test Suite requires all clients to be built.

## How to add test

The test generation script requires a JSON file name from the `operationId` (e.g. `search.json`), located in the `CTS/<client>/requests/` folder (e.g. `CTS/search/requests/`).
There are differents type of tests in the CTS:

### Requests tests

Those tests aims at ensuring minimal working operation for the API clients, by comparing the request formed by sample parameters.

The test generation script requires a JSON file name from the `operationId` (e.g. `search.json`), located in the `tests/CTS/methods/requests/<client>/` folder (e.g. `tests/CTS/methods/requests/search/`).

> See the [browse test file for the search client](https://github.com/algolia/api-clients-automation/blob/main/tests/CTS/methods/requests/search/browse.json)

Expand Down Expand Up @@ -66,27 +72,40 @@ The test generation script requires a JSON file name from the `operationId` (e.g
And that's it! If the name of the file matches an `operationId` in the spec, a test will be generated and will be calling the method name `operationId`.

The list of `queryParameters` must match exactly the actual value, the CTS has to check the number of query parameters and the value of each.
It's important to ensure the number of parameters because the API clients must not set default values, they should be handled by the engine.
shortcuts marked this conversation as resolved.
Show resolved Hide resolved

### Clients tests

The clients tests are located in the folder `tests/CTS/client/<client>`, they aim at testing the constructors and common error thrown by the API, and can be use to build more complex multi-step tests.

> TODO

## How to add a new language

Create a template in [`tests/CTS/methods/requests/templates/<languageName>/requests.mustache`](https://github.com/algolia/api-clients-automation/tree/main/tests/CTS/methods/requests/templates) that parses an array of tests into the test framework of choice.
### Requests tests

> See [implementation of the JavaScript tests](https://github.com/algolia/api-clients-automation/blob/main/tests/CTS/methods/requests/templates/javascript/requests.mustache)
Create a template in `templates/<languageName>/tests/requests.mustache` that parses an array of tests into the test framework of choice.

> See [implementation of the JavaScript tests](https://github.com/algolia/api-clients-automation/blob/main/templates/javascript/tests/requests/requests.mustache)

When writing your template, here is a list of variables accessible from `mustache`:

```json
{
"import": "the name of the package or library to import",
"client": "the name of the API Client object to instanciate and import",
"clientPrefix": "the name of the client without Client at the end",
"hasRegionalHost": "true if the hosts accepts region",
"defaultRegion": "the region to provide by default to the constructor",
"blocks": [
{
// The list of test to implement
"operationID": "the name of the endpoint and the cts file to test",
"tests": [
{
"testName": "the descriptive name test (default to `method`)",
"method": "the method to call on the API Client",
"testName": "the descriptive name test (default to `method`)",
"testIndex": "the index of the test to avoid duplicate function name",
"hasParameters": "true if the method has parameters, useful for `GET` requests",
"parameters": {
// Object of all parameters with their name, to be used for languages that require the parameter name
"parameterName": "value"
Expand All @@ -109,49 +128,45 @@ When writing your template, here is a list of variables accessible from `mustach
"objectName": "SearchParams",
// oneOfModel empty if there is no oneOf
"oneOfModel": {
// the compound type
"parentClassName": "SearchParams",
"type": "SearchParamsObject"
"type": "SearchParamsObject",
"x-one-of-explicit-name": "true if the name needs to be explicit (types are compatible)"
},
// properties used to have unique name and link to parent
"parent": "theParentObject",
"suffix": 7,
"parentSuffix": 6,
"useAnonymousKey": "true if we are in an array at the first level",
// boolean indicating if it is the last parameter
"-last": false
}
],
"requestOptionsWithDataType": [
{
"key": "key",
"value": "value",
// booleans indicating the data type
"isArray": false,
"isObject": true,
"isFreeFormObject": false,
"isString": false,
"isInteger": false,
"isLong": false,
"isDouble": false,
"isEnum": false,
"isBoolean": false,
"objectName": "SearchParams",
// oneOfModel empty if there is no oneOf
"oneOfModel": {
"parentClassName": "SearchParams",
"type": "SearchParamsObject"
},
// properties used to have unique name and link to parent
"parent": "theParentObject",
"suffix": 7,
"parentSuffix": 6,
// boolean indicating if it is the last parameter
"-last": false
"parametersWithDataTypeMap": {
"parameterName": {
// Same as the parametersWithDataType, where the "key" is really a key
}
],
// boolean indicating if the method has parameters, useful for `GET` requests
"hasParameters": true,
},
// boolean indicating if the method has requestOptions, useful to shape your template only if provided
"hasRequestOptions": true,
"requestOptions": {
"queryParameters": {
// the raw JSON object
"parameters": {},
// list of parameters with enhance types
"parametersWithDataType": [],
// map of enhance parameters
"parametersWithDataTypeMap": {}
},
"headers": {
// the raw JSON object
"parameters": {},
// list of parameters with enhance types
"parametersWithDataType": [],
// map of enhance parameters
"parametersWithDataTypeMap": {}
},
},
"request": {
"path": "the expected path of the request",
"method": "the expected method: GET, POST, PUT, DELETE or PATCH",
Expand All @@ -174,6 +189,31 @@ When writing your template, here is a list of variables accessible from `mustach
}
```

As well as lambdas to transform strings:
shortcuts marked this conversation as resolved.
Show resolved Hide resolved
- escapeQuotes - Escapes double quotes characters, replaces `"` with `\"`.
- escapeSlash - Escapes backward slash characters, replaces `\` with `\\`.
- lowercase - Converts all of the characters in this fragment to lower case using the rules of the ROOT locale.
- uppercase - Converts all of the characters in this fragment to upper case using the rules of the ROOT locale.
- titlecase - Converts text in a fragment to title case. For example once upon a time to Once Upon A Time.
- camelcase - Converts text in a fragment to camelCase. For example Input-text to inputText.
- indented - Prepends 4 spaces indention from second line of a fragment on. First line will be indented by Mustache.
- indented_8 - Prepends 8 spaces indention from second line of a fragment on. First line will be indented by Mustache.
- indented_12 - Prepends 12 spaces indention from second line of a fragment on. First line will be indented by Mustache.
- indented_16 - Prepends 16 spaces indention from second line of a fragment on. First line will be indented by Mustache.

If specific values are needed for a specific languages, or custom generated files, they can be added using a custom CTS manager:
- [javascript](https://github.com/algolia/api-clients-automation/blob/main/generators/src/main/java/com/algolia/codegen/cts/manager/JavaScriptCTSManager.java)
- `npmNamespace`: the npm namespace
- `utilsPackageVersion`: the utils version to import
- `import`: the name of the package or library to import
- [java](https://github.com/algolia/api-clients-automation/blob/main/generators/src/main/java/com/algolia/codegen/cts/manager/JavaCTSManager.java)
- `packageVersion`: the version of the Java client
- `import`: the name of the client package to import from

### Clients tests

> TODO

## Add common tests to every clients

You might want to test how every clients behaves, without having to duplicate the same tests. We provide 4 methods on every clients, common to all languages.
Expand Down