Skip to content

Commit

Permalink
feat(go): CTS implementation for go client (#1509)
Browse files Browse the repository at this point in the history
## 🧭 What and Why

🎟 JIRA Ticket: https://algolia.atlassian.net/browse/APIC-661

The CTS suite for go client implemented. 

### Changes included:

- Test templates created for the generation. 
    - When creating tests, json unmarshaller is used to parse requests. Initially, I tried to create the request the regular way but couldn't do it properly. The main issues were mostly about different "oneof" types and some very detailed requests. Unfortunately, generating these in Go with the mustache is not easy since mustache is all about "Logic-less" templates. 
    - Maybe we can revisit this later. We may need some improvements for CTS in general because creating CTS stuff is hard to manage and not straightforward. 
- `extras` field added to test json specs.  
    - It is added for `skipForGo` prop. It was needed for three specific test cases. The client was working okay but the test unmarshalling was not working properly because of the payload. No need to block this improvement for this.
    - These `extras` can be also used for some other cases in the future because the only request may not be enough for all the language generations. 
- Added some improvements for client generation. 
    - `UnmarshalJSON` implemented for request struct to handle json parsing for the direct request. 
    - "OneOf" model unmarshaling updated to add an extra validation.

## 🧪 Test

The test should run with CI.
  • Loading branch information
mehmetaligok authored May 9, 2023
1 parent 558b8fb commit 4fb9def
Show file tree
Hide file tree
Showing 29 changed files with 441 additions and 57 deletions.
11 changes: 11 additions & 0 deletions clients/algoliasearch-client-go/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
module github.com/algolia/algoliasearch-client-go/v4

go 1.19

require github.com/go-playground/validator/v10 v10.12.0

require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/leodido/go-urn v1.2.2 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
)
32 changes: 32 additions & 0 deletions clients/algoliasearch-client-go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2 changes: 1 addition & 1 deletion config/clients.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"customGenerator": "algolia-go",
"tests": {
"extension": "_test.go",
"outputFolder": ""
"outputFolder": "tests"
}
},
"kotlin": {
Expand Down
11 changes: 9 additions & 2 deletions generators/src/main/java/com/algolia/codegen/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,22 @@ public static String camelize(String kebabStr) {
* escape '/' in the path variable
*/
public static CodegenOperation specifyCustomRequest(CodegenOperation ope) {
if (CUSTOM_METHOD.contains(ope.nickname)) {
if (CUSTOM_METHOD.contains(ope.operationIdOriginal)) {
ope.vendorExtensions.put("x-is-custom-request", true);
}
return ope;
}

/** Returns the client name for the given language */
public static String createClientName(String client, String language) {
return language.equals("javascript") ? camelize(client) : capitalize(camelize(client));
switch (language) {
case "javascript":
return camelize(client);
case "go":
return client;
default:
return capitalize(camelize(client));
}
}

// testInput -> test-input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public static CTSManager getManager(String language, String client) {
return new PhpCTSManager();
case "kotlin":
return new KotlinCTSManager(client);
case "go":
return new GoCTSManager();
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.algolia.codegen.cts.manager;

import com.algolia.codegen.exceptions.GeneratorException;
import java.util.*;
import org.openapitools.codegen.SupportingFile;

public class GoCTSManager implements CTSManager {

@Override
public void addSupportingFiles(List<SupportingFile> supportingFiles) {
supportingFiles.add(new SupportingFile("common.mustache", "tests/methods/requests", "common.go"));
}

@Override
public void addDataToBundle(Map<String, Object> bundle) throws GeneratorException {
Object clientPrefix = bundle.get("clientPrefix");

if (clientPrefix.equals("query-suggestions")) {
bundle.put("clientPrefix", "suggestions");
}

bundle.put("clientImport", clientPrefix);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@ private Map<String, Object> traverseParams(
finalParamName = paramName.substring(1);
}

// type is a reserved keyword in go, we need to add more generic way to handle reversed keywords
// for all languages.
if (language.equals("go") && paramName.equals("type")) {
finalParamName = "type_";
}

Map<String, Object> testOutput = createDefaultOutput();
testOutput.put("key", finalParamName);
testOutput.put("isKeyAllUpperCase", StringUtils.isAllUpperCase(finalParamName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class Request {
public Map<String, Object> parameters;
public RequestOptions requestOptions;
public RequestProp request;
public Map<String, Object> extras;

@Override
public String toString() {
Expand All @@ -25,6 +26,7 @@ public String toString() {
sb.append(" parameters: ").append(parameters).append("\n");
sb.append(" requestOptions: ").append(requestOptions).append("\n");
sb.append(" request: ").append(request).append("\n");
sb.append(" extras: ").append(extras).append("\n");
sb.append("}");
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>

test.put("request", req.request);
test.put("hasParameters", req.parameters.size() != 0);
test.put("extras", req.extras);

if (req.requestOptions != null) {
test.put("hasRequestOptions", true);
Expand Down
10 changes: 10 additions & 0 deletions playground/go/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ require (
github.com/algolia/algoliasearch-client-go/v4 v4.0.0
github.com/joho/godotenv v1.4.0
)

require (
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.12.0 // indirect
github.com/leodido/go-urn v1.2.2 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
)
32 changes: 32 additions & 0 deletions playground/go/go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,34 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.12.0 h1:E4gtWgxWxp8YSxExrQFv5BpCahla0PVF2oTTEYaWQGI=
github.com/go-playground/validator/v10 v10.12.0/go.mod h1:hCAPuzYvKdP33pxWa+2+6AIKXEKqjIUyqsNCtbsSJrA=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2 changes: 1 addition & 1 deletion playground/go/insights.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func testInsights(appID, apiKey string) int {
insights.WithInsightEventQueryID("myQueryID")),
})
pushEventsResponse, err := insightsClient.PushEvents(
insightsClient.NewApiPushEventsRequest().WithInsightEvents(*events),
insightsClient.NewApiPushEventsRequest().WithInsightEvents(events),
)
if err != nil {
fmt.Printf("request error with PushEvents: %v\n", err)
Expand Down
2 changes: 1 addition & 1 deletion playground/go/predict.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func testPredict(appID, apiKey string) int {
predict.WithAllParamsTypesToRetrieve(predict.AllowedTypesToRetrieveEnumValues),
))
userProfile, err := predictClient.FetchUserProfile(
predictClient.NewApiFetchUserProfileRequest("userId").WithParams(params),
predictClient.NewApiFetchUserProfileRequest("userId").WithParams(&params),
)
if err != nil {
fmt.Printf("request error with FetchUserProfile: %v\n", err)
Expand Down
2 changes: 1 addition & 1 deletion playground/go/recommend.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func testRecommend(appID, apiKey string) int {
}

searchResponse, err := recommendClient.GetRecommendations(
recommendClient.NewApiGetRecommendationsRequest().WithGetRecommendationsParams(params),
recommendClient.NewApiGetRecommendationsRequest().WithGetRecommendationsParams(&params),
)
if err != nil {
fmt.Printf("request error with SearchSingleIndex: %v\n", err)
Expand Down
2 changes: 1 addition & 1 deletion playground/go/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func testSearch(appID, apiKey string) int {
searchClient := search.NewClient(appID, apiKey)

searchParams := search.SearchParamsStringAsSearchParams(search.NewSearchParamsString(search.WithSearchParamsStringParams("query=jeans&hitsPerPage=2")))
searchResponse, err := searchClient.SearchSingleIndex(searchClient.NewApiSearchSingleIndexRequest(indexName).WithSearchParams(searchParams))
searchResponse, err := searchClient.SearchSingleIndex(searchClient.NewApiSearchSingleIndexRequest(indexName).WithSearchParams(&searchParams))
if err != nil {
fmt.Printf("request error with SearchSingleIndex: %v\n", err)
return 1
Expand Down
3 changes: 3 additions & 0 deletions scripts/ci/githubActions/createMatrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ async function getClientMatrix(baseBranch: string): Promise<void> {
case 'java':
testsToStore = `${testsToStore} ${testsRootFolder}/build.gradle`;
break;
case 'go':
testsToStore = `${testsToStore} ${testsOutputBase}/methods/requests/common.go`;
break;
/**
* The CI runs on a node docker image, therefore it's not needed to run
* via the CLI for the JavaScript client.
Expand Down
11 changes: 8 additions & 3 deletions scripts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,14 @@ export function wait(waitTime: number): Promise<void> {
}

export function createClientName(client: string, language: string): string {
return language === 'javascript'
? camelize(client)
: capitalize(camelize(client));
switch (language) {
case 'javascript':
return camelize(client);
case 'go':
return client;
default:
return capitalize(camelize(client));
}
}

/**
Expand Down
13 changes: 12 additions & 1 deletion scripts/cts/runCts.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { run, runComposerUpdate } from '../common';
import { DOCKER, run, runComposerUpdate } from '../common';
import { createSpinner } from '../spinners';

async function runCtsOne(language: string): Promise<void> {
Expand All @@ -25,6 +25,17 @@ async function runCtsOne(language: string): Promise<void> {
case 'kotlin':
await run('./gradle/gradlew --no-daemon -p tests/output/kotlin allTests');
break;
case 'go':
if (DOCKER) {
await run('/usr/local/go/bin/go test -count 1 ./...', {
cwd: 'tests/output/go',
});
} else {
await run('go test -count 1 ./...', {
cwd: 'tests/output/go',
});
}
break;
default:
spinner.warn(`skipping unknown language '${language}' to run the CTS`);
return;
Expand Down
Loading

0 comments on commit 4fb9def

Please sign in to comment.