From 30a1f2797c9c848d461b6dceee5592aa48910ab2 Mon Sep 17 00:00:00 2001 From: Pierre Millot Date: Thu, 18 Jan 2024 12:17:29 +0100 Subject: [PATCH] feat(go): add client tests (#2552) --- .github/.cache_version | 2 +- clients/algoliasearch-client-go/README.md | 2 +- .../algolia/{internal => }/errs/net_err.go | 0 .../errs/no_more_host_to_try_err.go | 0 .../algolia/{internal => }/errs/wait_err.go | 0 .../algolia/transport/configuration.go | 22 + .../{internal => }/transport/requester.go | 37 +- .../transport/retry_strategy.go | 0 .../{internal => }/transport/stateful_host.go | 0 .../{internal => }/transport/transport.go | 29 +- .../algolia/{internal => }/transport/utils.go | 5 - .../algolia/{abtesting => utils}/utils.go | 18 +- clients/algoliasearch-client-go/go.mod | 2 +- config/generation.config.mjs | 4 +- .../algolia/codegen/AlgoliaGoGenerator.java | 8 +- .../codegen/cts/manager/GoCTSManager.java | 6 - .../codegen/cts/tests/ClientTestData.java | 2 +- .../cts/tests/ParametersWithDataType.java | 24 +- .../codegen/cts/tests/TestsClient.java | 5 + .../com/algolia/codegen/utils/Helpers.java | 6 + scripts/ci/githubActions/createMatrix.ts | 2 +- scripts/cts/runCts.ts | 2 +- templates/go/api.mustache | 52 ++- templates/go/client.mustache | 97 ++--- templates/go/configuration.mustache | 40 +- templates/go/model.mustache | 1 + .../go/tests/client/createClient.mustache | 9 + templates/go/tests/client/method.mustache | 5 + templates/go/tests/client/step.mustache | 6 + templates/go/tests/client/suite.mustache | 74 ++++ templates/go/tests/common.mustache | 35 -- .../go/tests/generateInnerParams.mustache | 2 +- templates/go/tests/requests/requests.mustache | 36 +- templates/go/utils.mustache | 376 ------------------ templates/ruby/snippets/method.mustache | 4 +- templates/ruby/tests/client/method.mustache | 2 +- templates/ruby/tests/generateParams.mustache | 1 + .../tests/requests/generateParams.mustache | 1 - .../ruby/tests/requests/requests.mustache | 6 +- tests/output/go/.golangci.yml | 10 + tests/output/go/go.mod | 4 +- tests/output/go/tests/echo.go | 47 +++ ...-or-move-index-rules-settings-synonyms.mdx | 6 +- .../guides/customized-client-usage.mdx | 8 +- .../docs/clients/guides/delete-objects.mdx | 2 +- .../clients/guides/filtering-your-search.mdx | 6 +- .../guides/manage-dictionary-entries.mdx | 8 +- .../guides/replace-all-rules-synonyms.mdx | 4 +- .../docs/clients/guides/retrieving-facets.mdx | 4 +- .../clients/guides/send-data-to-algolia.mdx | 4 +- .../guides/wait-for-a-task-to-finish.mdx | 2 +- .../guides/wait-for-api-key-to-be-valid.mdx | 2 +- website/docs/clients/installation.mdx | 2 +- website/docs/clients/migration-guides/go.md | 2 +- website/docs/contributing/setup-repository.md | 5 + 55 files changed, 396 insertions(+), 643 deletions(-) rename clients/algoliasearch-client-go/algolia/{internal => }/errs/net_err.go (100%) rename clients/algoliasearch-client-go/algolia/{internal => }/errs/no_more_host_to_try_err.go (100%) rename clients/algoliasearch-client-go/algolia/{internal => }/errs/wait_err.go (100%) create mode 100644 clients/algoliasearch-client-go/algolia/transport/configuration.go rename clients/algoliasearch-client-go/algolia/{internal => }/transport/requester.go (50%) rename clients/algoliasearch-client-go/algolia/{internal => }/transport/retry_strategy.go (100%) rename clients/algoliasearch-client-go/algolia/{internal => }/transport/stateful_host.go (100%) rename clients/algoliasearch-client-go/algolia/{internal => }/transport/transport.go (81%) rename clients/algoliasearch-client-go/algolia/{internal => }/transport/utils.go (79%) rename clients/algoliasearch-client-go/algolia/{abtesting => utils}/utils.go (95%) create mode 100644 templates/go/tests/client/createClient.mustache create mode 100644 templates/go/tests/client/method.mustache create mode 100644 templates/go/tests/client/step.mustache create mode 100644 templates/go/tests/client/suite.mustache delete mode 100644 templates/go/tests/common.mustache delete mode 100644 templates/go/utils.mustache create mode 100644 templates/ruby/tests/generateParams.mustache delete mode 100644 templates/ruby/tests/requests/generateParams.mustache create mode 100644 tests/output/go/.golangci.yml create mode 100644 tests/output/go/tests/echo.go diff --git a/.github/.cache_version b/.github/.cache_version index 238d6e882a..b0f3d96f87 100644 --- a/.github/.cache_version +++ b/.github/.cache_version @@ -1 +1 @@ -1.0.7 +1.0.8 diff --git a/clients/algoliasearch-client-go/README.md b/clients/algoliasearch-client-go/README.md index a98a42ceb6..9a8e3d1108 100644 --- a/clients/algoliasearch-client-go/README.md +++ b/clients/algoliasearch-client-go/README.md @@ -10,7 +10,7 @@ GoDoc Go Report Card License - Supported version + Supported version

diff --git a/clients/algoliasearch-client-go/algolia/internal/errs/net_err.go b/clients/algoliasearch-client-go/algolia/errs/net_err.go similarity index 100% rename from clients/algoliasearch-client-go/algolia/internal/errs/net_err.go rename to clients/algoliasearch-client-go/algolia/errs/net_err.go diff --git a/clients/algoliasearch-client-go/algolia/internal/errs/no_more_host_to_try_err.go b/clients/algoliasearch-client-go/algolia/errs/no_more_host_to_try_err.go similarity index 100% rename from clients/algoliasearch-client-go/algolia/internal/errs/no_more_host_to_try_err.go rename to clients/algoliasearch-client-go/algolia/errs/no_more_host_to_try_err.go diff --git a/clients/algoliasearch-client-go/algolia/internal/errs/wait_err.go b/clients/algoliasearch-client-go/algolia/errs/wait_err.go similarity index 100% rename from clients/algoliasearch-client-go/algolia/internal/errs/wait_err.go rename to clients/algoliasearch-client-go/algolia/errs/wait_err.go diff --git a/clients/algoliasearch-client-go/algolia/transport/configuration.go b/clients/algoliasearch-client-go/algolia/transport/configuration.go new file mode 100644 index 0000000000..794d35d7e1 --- /dev/null +++ b/clients/algoliasearch-client-go/algolia/transport/configuration.go @@ -0,0 +1,22 @@ +package transport + +import ( + "time" + + "github.com/algolia/algoliasearch-client-go/v4/algolia/compression" +) + +type Configuration struct { + AppID string + ApiKey string + + Hosts []string + DefaultHeader map[string]string + UserAgent string + Debug bool + Requester Requester + ReadTimeout time.Duration + WriteTimeout time.Duration + ConnectTimeout time.Duration + Compression compression.Compression +} diff --git a/clients/algoliasearch-client-go/algolia/internal/transport/requester.go b/clients/algoliasearch-client-go/algolia/transport/requester.go similarity index 50% rename from clients/algoliasearch-client-go/algolia/internal/transport/requester.go rename to clients/algoliasearch-client-go/algolia/transport/requester.go index d14cb28ecd..d6c20997dd 100644 --- a/clients/algoliasearch-client-go/algolia/internal/transport/requester.go +++ b/clients/algoliasearch-client-go/algolia/transport/requester.go @@ -22,37 +22,40 @@ const ( // the Algolia API client (by wrapping it in a user-defined instance of // transport.Requester) but would like to wrap it into a middleware layer or // pass it to an HTTP interceptor. -func DefaultHTTPClient() *http.Client { - return &http.Client{ - Transport: defaultTransport, +func DefaultHTTPClient(connectTimeout *time.Duration) *http.Client { + connectTimeoutValue := DefaultConnectTimeout + if connectTimeout != nil { + connectTimeoutValue = *connectTimeout } -} -var defaultTransport = &http.Transport{ - DialContext: (&net.Dialer{ - KeepAlive: DefaultKeepAliveDuration, - Timeout: DefaultConnectTimeout, - }).DialContext, - DisableKeepAlives: false, - MaxIdleConnsPerHost: DefaultMaxIdleConnsPerHost, - Proxy: http.ProxyFromEnvironment, - TLSHandshakeTimeout: DefaultTLSHandshakeTimeout, + return &http.Client{ + Transport: &http.Transport{ + DialContext: (&net.Dialer{ + KeepAlive: DefaultKeepAliveDuration, + Timeout: connectTimeoutValue, + }).DialContext, + DisableKeepAlives: false, + MaxIdleConnsPerHost: DefaultMaxIdleConnsPerHost, + Proxy: http.ProxyFromEnvironment, + TLSHandshakeTimeout: DefaultTLSHandshakeTimeout, + }, + } } type Requester interface { - Request(req *http.Request) (*http.Response, error) + Request(req *http.Request, timeout time.Duration, connectTimeout time.Duration) (*http.Response, error) } type defaultRequester struct { client *http.Client } -func newDefaultRequester() *defaultRequester { +func NewDefaultRequester(connectTimeout *time.Duration) *defaultRequester { return &defaultRequester{ - client: DefaultHTTPClient(), + client: DefaultHTTPClient(connectTimeout), } } -func (r *defaultRequester) Request(req *http.Request) (*http.Response, error) { +func (r *defaultRequester) Request(req *http.Request, _, _ time.Duration) (*http.Response, error) { return r.client.Do(req) } diff --git a/clients/algoliasearch-client-go/algolia/internal/transport/retry_strategy.go b/clients/algoliasearch-client-go/algolia/transport/retry_strategy.go similarity index 100% rename from clients/algoliasearch-client-go/algolia/internal/transport/retry_strategy.go rename to clients/algoliasearch-client-go/algolia/transport/retry_strategy.go diff --git a/clients/algoliasearch-client-go/algolia/internal/transport/stateful_host.go b/clients/algoliasearch-client-go/algolia/transport/stateful_host.go similarity index 100% rename from clients/algoliasearch-client-go/algolia/internal/transport/stateful_host.go rename to clients/algoliasearch-client-go/algolia/transport/stateful_host.go diff --git a/clients/algoliasearch-client-go/algolia/internal/transport/transport.go b/clients/algoliasearch-client-go/algolia/transport/transport.go similarity index 81% rename from clients/algoliasearch-client-go/algolia/internal/transport/transport.go rename to clients/algoliasearch-client-go/algolia/transport/transport.go index 31772cf147..6723a1a11e 100644 --- a/clients/algoliasearch-client-go/algolia/internal/transport/transport.go +++ b/clients/algoliasearch-client-go/algolia/transport/transport.go @@ -11,13 +11,14 @@ import ( "github.com/algolia/algoliasearch-client-go/v4/algolia/call" "github.com/algolia/algoliasearch-client-go/v4/algolia/compression" "github.com/algolia/algoliasearch-client-go/v4/algolia/debug" - "github.com/algolia/algoliasearch-client-go/v4/algolia/internal/errs" + "github.com/algolia/algoliasearch-client-go/v4/algolia/errs" ) type Transport struct { - requester Requester - retryStrategy *RetryStrategy - compression compression.Compression + requester Requester + retryStrategy *RetryStrategy + compression compression.Compression + connectTimeout time.Duration } func New( @@ -25,16 +26,22 @@ func New( requester Requester, readTimeout time.Duration, writeTimeout time.Duration, + connectTimeout time.Duration, compression compression.Compression, ) *Transport { + if connectTimeout == 0 { + connectTimeout = DefaultConnectTimeout + } + if requester == nil { - requester = newDefaultRequester() + requester = NewDefaultRequester(&connectTimeout) } return &Transport{ - requester: requester, - retryStrategy: newRetryStrategy(hosts, readTimeout, writeTimeout), - compression: compression, + requester: requester, + retryStrategy: newRetryStrategy(hosts, readTimeout, writeTimeout), + compression: compression, + connectTimeout: connectTimeout, } } @@ -56,7 +63,7 @@ func (t *Transport) Request(ctx context.Context, req *http.Request, k call.Kind) // cancelled` error may happen when the body is read. perRequestCtx, cancel := context.WithTimeout(ctx, h.timeout) req = req.WithContext(perRequestCtx) - res, err := t.request(req, h.host) + res, err := t.request(req, h.host, h.timeout, t.connectTimeout) code := 0 if res != nil { @@ -98,12 +105,12 @@ func (t *Transport) Request(ctx context.Context, req *http.Request, k call.Kind) return nil, errs.ErrNoMoreHostToTry } -func (t *Transport) request(req *http.Request, host string) (*http.Response, error) { +func (t *Transport) request(req *http.Request, host string, timeout time.Duration, connectTimeout time.Duration) (*http.Response, error) { req.URL.Scheme = "https" req.URL.Host = host debug.Display(req) - res, err := t.requester.Request(req) + res, err := t.requester.Request(req, timeout, connectTimeout) debug.Display(res) if err != nil { diff --git a/clients/algoliasearch-client-go/algolia/internal/transport/utils.go b/clients/algoliasearch-client-go/algolia/transport/utils.go similarity index 79% rename from clients/algoliasearch-client-go/algolia/internal/transport/utils.go rename to clients/algoliasearch-client-go/algolia/transport/utils.go index 4972050916..57e97ea287 100644 --- a/clients/algoliasearch-client-go/algolia/internal/transport/utils.go +++ b/clients/algoliasearch-client-go/algolia/transport/utils.go @@ -2,13 +2,8 @@ package transport import ( "math/rand" - "time" ) -func init() { - rand.Seed(int64(time.Now().Nanosecond())) -} - func Shuffle(hosts []*StatefulHost) []*StatefulHost { if hosts == nil { return nil diff --git a/clients/algoliasearch-client-go/algolia/abtesting/utils.go b/clients/algoliasearch-client-go/algolia/utils/utils.go similarity index 95% rename from clients/algoliasearch-client-go/algolia/abtesting/utils.go rename to clients/algoliasearch-client-go/algolia/utils/utils.go index 559bd8d274..fef1bbdb77 100644 --- a/clients/algoliasearch-client-go/algolia/abtesting/utils.go +++ b/clients/algoliasearch-client-go/algolia/utils/utils.go @@ -1,21 +1,11 @@ -/* -A/B Testing API - -API powering the A/B Testing feature of Algolia. - -API version: 1.0.0 -*/ - -// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. - -package abtesting +package utils import ( "encoding/json" "reflect" "time" - "github.com/algolia/algoliasearch-client-go/v4/algolia/internal/errs" + "github.com/algolia/algoliasearch-client-go/v4/algolia/errs" ) // PtrBool is a helper routine that returns a pointer to given boolean value. @@ -330,8 +320,8 @@ func (v *NullableTime) UnmarshalJSON(src []byte) error { return json.Unmarshal(src, &v.value) } -// isNilorEmpty checks if an input is nil or empty -func isNilorEmpty(i any) bool { +// IsNilOrEmpty checks if an input is nil or empty. +func IsNilOrEmpty(i any) bool { if i == nil { return true } diff --git a/clients/algoliasearch-client-go/go.mod b/clients/algoliasearch-client-go/go.mod index eae471241b..672b1d6cbe 100644 --- a/clients/algoliasearch-client-go/go.mod +++ b/clients/algoliasearch-client-go/go.mod @@ -1,6 +1,6 @@ module github.com/algolia/algoliasearch-client-go/v4 -go 1.19 +go 1.21 require github.com/go-playground/validator/v10 v10.17.0 diff --git a/config/generation.config.mjs b/config/generation.config.mjs index fd8b43ac6a..cd73aa50c9 100644 --- a/config/generation.config.mjs +++ b/config/generation.config.mjs @@ -41,10 +41,12 @@ export const patterns = [ 'clients/algoliasearch-client-go/algolia/**', '!clients/algoliasearch-client-go/.github/**', '!clients/algoliasearch-client-go/*', - '!clients/algoliasearch-client-go/algolia/internal/**', + '!clients/algoliasearch-client-go/algolia/transport/**', + '!clients/algoliasearch-client-go/algolia/errs/**', '!clients/algoliasearch-client-go/algolia/call/*', '!clients/algoliasearch-client-go/algolia/compression/*', '!clients/algoliasearch-client-go/algolia/debug/*', + '!clients/algoliasearch-client-go/algolia/utils/*', 'tests/output/go/go.sum', diff --git a/generators/src/main/java/com/algolia/codegen/AlgoliaGoGenerator.java b/generators/src/main/java/com/algolia/codegen/AlgoliaGoGenerator.java index 648eea7efb..a7ae97abe3 100644 --- a/generators/src/main/java/com/algolia/codegen/AlgoliaGoGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/AlgoliaGoGenerator.java @@ -51,8 +51,6 @@ public void processOpts() { supportingFiles.clear(); supportingFiles.add(new SupportingFile("configuration.mustache", "", "configuration.go")); supportingFiles.add(new SupportingFile("client.mustache", "", "client.go")); - supportingFiles.add(new SupportingFile("response.mustache", "", "response.go")); - supportingFiles.add(new SupportingFile("utils.mustache", "", "utils.go")); try { Helpers.generateServer(client, additionalProperties); @@ -76,11 +74,11 @@ public Map postProcessAllModels(Map objs) for (Map.Entry entry : models.entrySet()) { String modelName = entry.getKey(); - ModelsMap model = entry.getValue(); + CodegenModel model = entry.getValue().getModels().get(0).getModel(); // for some reason the property additionalPropertiesIsAnyType is not propagated to the // property - for (CodegenProperty prop : model.getModels().get(0).getModel().getVars()) { + for (CodegenProperty prop : model.getVars()) { ModelsMap propertyModel = models.get(prop.datatypeWithEnum); if (propertyModel != null && propertyModel.getModels().get(0).getModel().getAdditionalPropertiesIsAnyType()) { // consider it the same as model for our purpose @@ -92,6 +90,8 @@ public Map postProcessAllModels(Map objs) prop.dataType = prop.dataType.replace("[]*[]", "[][]"); prop.vendorExtensions.put("x-go-base-type", prop.dataType); } + + prop.dataType = prop.dataType.replace("NullableBool", "utils.NullableBool"); } } return models; diff --git a/generators/src/main/java/com/algolia/codegen/cts/manager/GoCTSManager.java b/generators/src/main/java/com/algolia/codegen/cts/manager/GoCTSManager.java index 1513b4fd90..3962f728e5 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/manager/GoCTSManager.java +++ b/generators/src/main/java/com/algolia/codegen/cts/manager/GoCTSManager.java @@ -2,15 +2,9 @@ import com.algolia.codegen.exceptions.GeneratorException; import java.util.*; -import org.openapitools.codegen.SupportingFile; public class GoCTSManager implements CTSManager { - @Override - public void addTestsSupportingFiles(List supportingFiles) { - supportingFiles.add(new SupportingFile("tests/common.mustache", "tests/output/go/tests/requests", "common.go")); - } - @Override public void addDataToBundle(Map bundle) throws GeneratorException { Object clientPrefix = bundle.get("clientPrefix"); diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/ClientTestData.java b/generators/src/main/java/com/algolia/codegen/cts/tests/ClientTestData.java index a68d31deb2..66a9cf700b 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/ClientTestData.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/ClientTestData.java @@ -22,6 +22,6 @@ class Step { class Expected { public String type; - public Object error; + public String error; public Object match; } diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java b/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java index b90fd642a2..0fe740856f 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/ParametersWithDataType.java @@ -145,7 +145,7 @@ private Map traverseParams( testOutput.put("isParentFreeFormObject", isParentFreeFormObject); if (param == null) { - handleNull(testOutput); + handleNull(spec, testOutput); } else if (spec.getIsArray()) { handleArray(paramName, param, testOutput, spec, suffix); } else if (spec.getIsEnum()) { @@ -155,7 +155,7 @@ private Map traverseParams( handleModel(paramName, param, testOutput, spec, baseType, parent, suffix); } else if (baseType.equals("Object")) { // not var, no item, pure free form - handleObject(paramName, param, testOutput, suffix); + handleObject(paramName, param, testOutput, true, suffix); } else if (spec.getIsMap()) { // free key but only one type handleMap(paramName, param, testOutput, spec, suffix); @@ -188,11 +188,11 @@ private Map traverseParamsWithoutSpec(String paramName, Object p } if (param == null) { - handleNull(testOutput); + handleNull(null, testOutput); } else if (param instanceof List) { handleArray(paramName, param, testOutput, null, suffix); } else if (param instanceof Map) { - handleObject(paramName, param, testOutput, suffix); + handleObject(paramName, param, testOutput, false, suffix); } else { handlePrimitive(param, testOutput, null); } @@ -205,6 +205,7 @@ private Map createDefaultOutput() { // we need to set all types to false otherwise mustache will read the one from the parent // context and run into a infinite loop testOutput.put("isObject", false); + testOutput.put("isNullObject", false); testOutput.put("isArray", false); testOutput.put("isNull", false); testOutput.put("isFreeFormObject", false); @@ -224,8 +225,11 @@ private Map createDefaultOutput() { return testOutput; } - private void handleNull(Map testOutput) { + private void handleNull(IJsonSchemaValidationProperties spec, Map testOutput) { testOutput.put("isNull", true); + if (spec.getIsModel() || spec instanceof CodegenModel) { + testOutput.put("isNullObject", true); + } } private void handleArray( @@ -385,7 +389,8 @@ private void handleModel( testOutput.put("optionalValue", optionalValues); } - private void handleObject(String paramName, Object param, Map testOutput, int suffix) throws CTSException { + private void handleObject(String paramName, Object param, Map testOutput, boolean isSimpleObject, int suffix) + throws CTSException { Map vars = (Map) param; List values = new ArrayList<>(); @@ -394,11 +399,8 @@ private void handleObject(String paramName, Object param, Map te objSpec.dataType = inferDataType(entry.getValue(), objSpec, null); values.add(traverseParams(entry.getKey(), entry.getValue(), objSpec, paramName, suffix + 1, true)); } - // sometimes it's really just an object - if (testOutput.getOrDefault("objectName", "").equals("Object")) { - testOutput.put("isSimpleObject", true); - } + testOutput.put("isSimpleObject", isSimpleObject); testOutput.put("isFreeFormObject", true); testOutput.put("value", values); } @@ -493,6 +495,8 @@ private String getObjectNameForLanguage(String objectName) { return "bool"; case "List": return "Array"; + case "Object": + return "map[string]any"; } } return Helpers.capitalize(objectName); diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsClient.java b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsClient.java index ca0a5897b1..1e3453e2c6 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsClient.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsClient.java @@ -57,6 +57,7 @@ public void run(Map models, Map try { Map testOut = new HashMap<>(); List steps = new ArrayList<>(); + testOut.put("inClientTest", true); testOut.put("testName", test.testName); testOut.put("testIndex", testIndex++); testOut.put("autoCreateClient", test.autoCreateClient); @@ -101,6 +102,10 @@ public void run(Map models, Map if (step.expected.error != null) { stepOut.put("isError", true); stepOut.put("expectedError", step.expected.error); + if (language.equals("go") && step.path != null) { + // hack for go that use PascalCase, but just in the operationID + stepOut.put("expectedError", step.expected.error.replace(step.path, Helpers.toPascalCase(step.path))); + } } else if (step.expected.match != null) { if (step.expected.match instanceof Map) { Map match = new HashMap<>(); diff --git a/generators/src/main/java/com/algolia/codegen/utils/Helpers.java b/generators/src/main/java/com/algolia/codegen/utils/Helpers.java index 8f284aeeb8..9944564588 100644 --- a/generators/src/main/java/com/algolia/codegen/utils/Helpers.java +++ b/generators/src/main/java/com/algolia/codegen/utils/Helpers.java @@ -79,6 +79,12 @@ public static String toSnakeCase(String s) { return s.replace('-', '_').replaceAll("(.+?)([A-Z])", "$1_$2").toLowerCase(Locale.ROOT); } + // test_input -> TestInput + // test-input -> TestInput + public static String toPascalCase(String s) { + return Arrays.stream(s.split("[_-]")).map(Helpers::capitalize).reduce("", String::concat); + } + /** Inject server info into the client to generate the right URL */ public static void generateServer(String clientKebab, Map additionalProperties) throws ConfigException { Yaml yaml = new Yaml(); diff --git a/scripts/ci/githubActions/createMatrix.ts b/scripts/ci/githubActions/createMatrix.ts index 6fe182694f..c15b633e17 100644 --- a/scripts/ci/githubActions/createMatrix.ts +++ b/scripts/ci/githubActions/createMatrix.ts @@ -102,7 +102,7 @@ async function createClientMatrix(baseBranch: string): Promise { testsToStore = `${testsToStore} ${testsRootFolder}/global.json`; break; case 'go': - testsToStore = `${testsToStore} ${testsOutputBase}/requests/common.go ${testsRootFolder}/go.sum ${testsRootFolder}/go.mod`; + testsToStore = `${testsToStore} ${testsOutputBase}/echo.go ${testsRootFolder}/go.sum ${testsRootFolder}/go.mod`; break; case 'java': testsToStore = `${testsToStore} ${testsRootFolder}/build.gradle`; diff --git a/scripts/cts/runCts.ts b/scripts/cts/runCts.ts index 1aeaa24ca0..d312219793 100644 --- a/scripts/cts/runCts.ts +++ b/scripts/cts/runCts.ts @@ -12,7 +12,7 @@ async function runCtsOne(language: string): Promise { await run('dart test', { cwd, language }); break; case 'go': - await run('go test -count 1 ./...', { + await run('go test -race -count 1 ./...', { cwd, language, }); diff --git a/templates/go/api.mustache b/templates/go/api.mustache index e4ecf45ec7..eb0c056bc5 100644 --- a/templates/go/api.mustache +++ b/templates/go/api.mustache @@ -9,18 +9,15 @@ import ( "io" "net/http" "net/url" - {{#isSearchClient}} - "slices" - {{/isSearchClient}} "strings" {{#isSearchClient}} + "slices" "time" + "github.com/algolia/algoliasearch-client-go/v4/algolia/errs" {{/isSearchClient}} + "github.com/algolia/algoliasearch-client-go/v4/algolia/utils" "github.com/algolia/algoliasearch-client-go/v4/algolia/call" - {{#isSearchClient}} - "github.com/algolia/algoliasearch-client-go/v4/algolia/internal/errs" - {{/isSearchClient}} ) type Option struct { @@ -156,24 +153,25 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r ) requestPath := "{{{path}}}"{{#pathParams}} - requestPath = strings.ReplaceAll(requestPath, "{"+"{{baseName}}"+"}", url.PathEscape(parameterToString(r.{{paramName}}))){{/pathParams}} + requestPath = strings.ReplaceAll(requestPath, {{=<% %>=}}"{<%baseName%>}"<%={{ }}=%>, url.PathEscape(parameterToString(r.{{paramName}}))){{/pathParams}} headers := make(map[string]string) queryParams := url.Values{} {{#allParams}} {{#required}} - {{^isPathParam}} - {{^isPrimitiveType}} - if r.{{paramName}} == nil { - return {{#returnType}}returnValue, {{/returnType}}reportError("{{paramName}} is required and must be specified") - } - {{/isPrimitiveType}} {{#isString}} - if r.{{paramName}} == "" { - return {{#returnType}}returnValue, {{/returnType}}reportError("{{paramName}} is required and must be specified") - } - {{/isString}} - {{/isPathParam}} + if r.{{paramName}} == "" { + return {{#returnType}}returnValue, {{/returnType}}reportError("Parameter `{{paramName}}` is required when calling `{{operationId}}`.") + }{{/isString}}{{#isContainer}} + if len(r.{{paramName}}) == 0 { + return {{#returnType}}returnValue, {{/returnType}}reportError("Parameter `{{paramName}}` is required when calling `{{operationId}}`.") + }{{/isContainer}}{{#isMap}} + if len(r.{{paramName}}) == 0 { + return {{#returnType}}returnValue, {{/returnType}}reportError("Parameter `{{paramName}}` is required when calling `{{operationId}}`.") + }{{/isMap}}{{^isPrimitiveType}}{{^isContainer}}{{^isMap}}{{^isEnumRef}} + if r.{{paramName}} == nil { + return {{#returnType}}returnValue, {{/returnType}}reportError("Parameter `{{paramName}}` is required when calling `{{operationId}}`.") + }{{/isEnumRef}}{{/isMap}}{{/isContainer}}{{/isPrimitiveType}} {{#minItems}} if len({{^isPathParam}}*{{/isPathParam}}r.{{paramName}}) < {{minItems}} { return {{#returnType}}returnValue, {{/returnType}}reportError("{{paramName}} must have at least {{minItems}} elements") @@ -213,7 +211,7 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r {{#vendorExtensions.x-is-custom-request}} {{#queryParams}} - {{^required}}if !isNilorEmpty(r.{{paramName}}) { {{/required}} + {{^required}}if !utils.IsNilOrEmpty(r.{{paramName}}) { {{/required}} for k, v := range r.{{paramName}} { queryParams.Set(k, parameterToString(v)) } @@ -226,7 +224,7 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r queryParams.Set("{{baseName}}", parameterToString({{^isFreeFormObject}}{{^isArray}}{{^isPrimitiveType}}{{^isEnumRef}}*{{/isEnumRef}}{{/isPrimitiveType}}{{/isArray}}{{/isFreeFormObject}}r.{{paramName}})) {{/required}} {{^required}} - if !isNilorEmpty(r.{{paramName}}) { + if !utils.IsNilOrEmpty(r.{{paramName}}) { queryParams.Set("{{baseName}}", parameterToString({{^isFreeFormObject}}{{^isArray}}{{^isPrimitiveType}}{{^isEnumRef}}*{{/isEnumRef}}{{/isPrimitiveType}}{{/isArray}}{{/isFreeFormObject}}r.{{paramName}})) } {{/required}} @@ -237,7 +235,7 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r headers["{{baseName}}"] = parameterToString({{^isFreeFormObject}}{{^isArray}}{{^isPrimitiveType}}{{^isEnumRef}}*{{/isEnumRef}}{{/isPrimitiveType}}{{/isArray}}{{/isFreeFormObject}}r.{{paramName}}) {{/required}} {{^required}} - if !isNilorEmpty(r.{{paramName}}) { + if !utils.IsNilOrEmpty(r.{{paramName}}) { headers["{{baseName}}"] = parameterToString({{^isFreeFormObject}}{{^isArray}}{{^isPrimitiveType}}{{^isEnumRef}}*{{/isEnumRef}}{{/isPrimitiveType}}{{/isArray}}{{/isFreeFormObject}}r.{{paramName}}) } {{/required}} @@ -255,7 +253,7 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r {{#bodyParams}} // body params{{^required}} - if isNilorEmpty(r.{{paramName}}) { + if utils.IsNilOrEmpty(r.{{paramName}}) { postBody = "{}" } else { {{/required}} postBody = r.{{paramName}}{{^required}} @@ -266,7 +264,7 @@ func (c *APIClient) {{nickname}}WithContext(ctx context.Context, {{#hasParams}}r return {{#returnType}}returnValue, {{/returnType}}err } - res, err := c.callAPI(req, {{#vendorExtensions}}{{#x-use-read-transporter}}call.Read{{/x-use-read-transporter}}{{^x-use-read-transporter}}call.Write{{/x-use-read-transporter}}{{/vendorExtensions}}) + res, err := c.callAPI(req, {{#vendorExtensions}}{{#x-use-read-transporter}}true{{/x-use-read-transporter}}{{^x-use-read-transporter}}false{{/x-use-read-transporter}}{{/vendorExtensions}}) if err != nil { return {{#returnType}}returnValue, {{/returnType}}err } @@ -377,7 +375,7 @@ func (c *APIClient) WaitForTaskWithContext( maxDelay *time.Duration, opts ...Option, ) (*GetTaskResponse, error) { - return RetryUntil( + return utils.RetryUntil( func() (*GetTaskResponse, error) { return c.GetTaskWithContext(ctx, c.NewApiGetTaskRequest(indexName, taskID), opts...) }, @@ -490,7 +488,7 @@ func (c *APIClient) WaitForApiKeyWithContext( return nil, &errs.WaitKeyUpdateError{} } - return RetryUntil( + return utils.RetryUntil( func() (*GetApiKeyResponse, error) { return c.GetApiKeyWithContext(ctx, c.NewApiGetApiKeyRequest(key), opts...) }, @@ -548,7 +546,7 @@ func (c *APIClient) WaitForApiKeyWithContext( ) } - return RetryUntil( + return utils.RetryUntil( func() (*GetApiKeyResponse, error) { return c.GetApiKeyWithContext(ctx, c.NewApiGetApiKeyRequest(key), opts...) }, @@ -573,4 +571,4 @@ func (c *APIClient) WaitForApiKeyWithContext( ) } -{{/isSearchClient}} \ No newline at end of file +{{/isSearchClient}} diff --git a/templates/go/client.mustache b/templates/go/client.mustache index fe89b90461..64b6424440 100644 --- a/templates/go/client.mustache +++ b/templates/go/client.mustache @@ -2,28 +2,29 @@ package {{packageName}} import ( - "bytes" - "compress/gzip" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "log" - "net/http" - "net/http/httputil" - "net/url" - "reflect" - "regexp" - "runtime" - "strings" - "time" + "bytes" + "compress/gzip" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "log" + "net/http" + "net/http/httputil" + "net/url" + "reflect" + "regexp" + "runtime" + "strings" + "slices" + "time" "github.com/go-playground/validator/v10" - "github.com/algolia/algoliasearch-client-go/v4/algolia/call" - "github.com/algolia/algoliasearch-client-go/v4/algolia/compression" - "github.com/algolia/algoliasearch-client-go/v4/algolia/internal/transport" + "github.com/algolia/algoliasearch-client-go/v4/algolia/call" + "github.com/algolia/algoliasearch-client-go/v4/algolia/compression" + "github.com/algolia/algoliasearch-client-go/v4/algolia/transport" ) var jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`) @@ -37,31 +38,33 @@ type APIClient struct { } // NewClient creates a new API client with {{#hasRegionalHost}}appID, apiKey and region.{{/hasRegionalHost}}{{^hasRegionalHost}}appID and apiKey.{{/hasRegionalHost}} -func NewClient(appID, apiKey string{{#hasRegionalHost}}, region Region{{/hasRegionalHost}}) *APIClient { +func NewClient(appID, apiKey string{{#hasRegionalHost}}, region Region{{/hasRegionalHost}}) (*APIClient, error) { return NewClientWithConfig(Configuration{ - AppID: appID, - ApiKey: apiKey,{{#hasRegionalHost}} - Region: region,{{/hasRegionalHost}} - DefaultHeader: make(map[string]string), - UserAgent: getUserAgent(), - Debug: false, - Requester: newDefaultRequester(), + Configuration: transport.Configuration{ + AppID: appID, + ApiKey: apiKey, + DefaultHeader: make(map[string]string), + UserAgent: getUserAgent(), + Debug: false, + Requester: transport.NewDefaultRequester(nil), + },{{#hasRegionalHost}} + Region: region,{{/hasRegionalHost}} }) } // NewClientWithConfig creates a new API client with the given configuration to fully customize the client behaviour. -func NewClientWithConfig(cfg Configuration) *APIClient { +func NewClientWithConfig(cfg Configuration) (*APIClient, error) { var hosts []*transport.StatefulHost if cfg.AppID == "" { - panic("appID is required") + return nil, errors.New("`appId` is missing.") } if cfg.ApiKey == "" { - panic("apiKey is required") + return nil, errors.New("`apiKey` is missing.") } if len(cfg.Hosts) == 0 { {{#hasRegionalHost}} - if cfg.Region == "" { - panic("region is required") + if {{^fallbackToAliasHost}}cfg.Region == "" || {{/fallbackToAliasHost}}(cfg.Region != "" && !slices.Contains(allowedRegions[:], string(cfg.Region))) { + return nil, fmt.Errorf("`region` {{^fallbackToAliasHost}}is required and {{/fallbackToAliasHost}}must be one of the following: %s", strings.Join(allowedRegions[:], ", ")) }{{/hasRegionalHost}} hosts = getDefaultHosts({{#hasRegionalHost}}cfg.Region{{/hasRegionalHost}}{{^hasRegionalHost}}cfg.AppID{{/hasRegionalHost}}) } else { @@ -70,7 +73,7 @@ func NewClientWithConfig(cfg Configuration) *APIClient { } } if cfg.Requester == nil { - cfg.Requester = newDefaultRequester() + cfg.Requester = transport.NewDefaultRequester(&cfg.ConnectTimeout) } if cfg.UserAgent == "" { cfg.UserAgent = getUserAgent() @@ -84,21 +87,20 @@ func NewClientWithConfig(cfg Configuration) *APIClient { cfg.Requester, cfg.ReadTimeout, cfg.WriteTimeout, + cfg.ConnectTimeout, cfg.Compression, ), - } + }, nil } {{#hasRegionalHost}} func getDefaultHosts(r Region) []*transport.StatefulHost { - hosts := []*transport.StatefulHost{} - switch r { - case {{#allowedRegions}}{{#lambda.uppercase}}{{.}}{{/lambda.uppercase}}{{^-last}},{{/-last}}{{/allowedRegions}}: - hosts = append(hosts, transport.NewStatefulHost(strings.ReplaceAll("{{{regionalHost}}}", "{region}", string(r)), call.IsReadWrite)){{#fallbackToAliasHost}} - default: - hosts = append(hosts, transport.NewStatefulHost("{{{hostWithFallback}}}", call.IsReadWrite)){{/fallbackToAliasHost}} - } - return hosts + {{#fallbackToAliasHost}} + if r == "" { + return []*transport.StatefulHost{transport.NewStatefulHost("{{{hostWithFallback}}}", call.IsReadWrite)} + }{{/fallbackToAliasHost}} + + return []*transport.StatefulHost{transport.NewStatefulHost(strings.ReplaceAll("{{{regionalHost}}}", "{region}", string(r)), call.IsReadWrite)} } {{/hasRegionalHost}} {{^hasRegionalHost}} @@ -118,7 +120,7 @@ func getDefaultHosts(appID string) []*transport.StatefulHost { } {{/hasRegionalHost}} func getUserAgent() string { - return fmt.Sprintf("Algolia for Go ({{{packageVersion}}}); Go (%s); {{#lambda.titlecase}}{{client}}{{/lambda.titlecase}} ({{{packageVersion}}})", runtime.Version()) + return fmt.Sprintf("Algolia for Go ({{{packageVersion}}}); Go (%s); {{#lambda.titlecase}}{{#lambda.camelcase}}{{client}}{{/lambda.camelcase}}{{/lambda.titlecase}} ({{{packageVersion}}})", runtime.Version()) } // parameterToString convert any parameters to string. @@ -138,7 +140,7 @@ func (c *APIClient) AddDefaultHeader(key string, value string) { } // callAPI do the request. -func (c *APIClient) callAPI(request *http.Request, kind call.Kind) (*http.Response, error) { +func (c *APIClient) callAPI(request *http.Request, useReadTransporter bool) (*http.Response, error) { if c.cfg.Debug { dump, err := httputil.DumpRequestOut(request, true) if err != nil { @@ -147,7 +149,12 @@ func (c *APIClient) callAPI(request *http.Request, kind call.Kind) (*http.Respon log.Printf("\n%s\n", string(dump)) } - resp, err := c.transport.Request(request.Context(), request, kind) + callKind := call.Write + if useReadTransporter || request.Method == http.MethodGet { + callKind = call.Read + } + + resp, err := c.transport.Request(request.Context(), request, callKind) if err != nil { return nil, err } diff --git a/templates/go/configuration.mustache b/templates/go/configuration.mustache index 89a5805709..40acb4a052 100644 --- a/templates/go/configuration.mustache +++ b/templates/go/configuration.mustache @@ -2,31 +2,12 @@ package {{packageName}} import ( - "net/http" - "time" - - "github.com/algolia/algoliasearch-client-go/v4/algolia/compression" + "github.com/algolia/algoliasearch-client-go/v4/algolia/transport" ) -type Requester interface { - Request(*http.Request) (*http.Response, error) -} - -type defaultRequester struct { - client *http.Client -} - -func newDefaultRequester() *defaultRequester { - return &defaultRequester{ - client: http.DefaultClient, - } -} - -func (r *defaultRequester) Request(req *http.Request) (*http.Response, error) { - return r.client.Do(req) -} - {{#hasRegionalHost}} +var allowedRegions = [...]string{ {{#allowedRegions}}"{{.}}",{{/allowedRegions}} } + type Region string const ( @@ -38,16 +19,7 @@ const ( // Configuration stores the configuration of the API client type Configuration struct { - AppID string - ApiKey string{{#hasRegionalHost}} - Region Region{{/hasRegionalHost}} - - Hosts []string `json:"host,omitempty"` - DefaultHeader map[string]string `json:"defaultHeader,omitempty"` - UserAgent string `json:"userAgent,omitempty"` - Debug bool `json:"debug,omitempty"` - Requester Requester - ReadTimeout time.Duration - WriteTimeout time.Duration - Compression compression.Compression + transport.Configuration + + {{#hasRegionalHost}}Region Region{{/hasRegionalHost}} } diff --git a/templates/go/model.mustache b/templates/go/model.mustache index ddb2b21ceb..31013c6f94 100644 --- a/templates/go/model.mustache +++ b/templates/go/model.mustache @@ -5,6 +5,7 @@ package {{packageName}} import ( "encoding/json" "fmt" + "github.com/algolia/algoliasearch-client-go/v4/algolia/utils" {{#imports}} "{{import}}" {{/imports}} diff --git a/templates/go/tests/client/createClient.mustache b/templates/go/tests/client/createClient.mustache new file mode 100644 index 0000000000..5784c72c5d --- /dev/null +++ b/templates/go/tests/client/createClient.mustache @@ -0,0 +1,9 @@ +cfg = {{clientPrefix}}.Configuration{ + Configuration: transport.Configuration{ + AppID: "{{parametersWithDataTypeMap.appId.value}}", + ApiKey: "{{parametersWithDataTypeMap.apiKey.value}}", + Requester: echo, + },{{#hasRegionalHost}}{{#parametersWithDataTypeMap.region.value}} + Region: {{clientPrefix}}.Region("{{parametersWithDataTypeMap.region.value}}"),{{/parametersWithDataTypeMap.region.value}}{{/hasRegionalHost}} +} +client, err = {{clientPrefix}}.NewClientWithConfig(cfg) \ No newline at end of file diff --git a/templates/go/tests/client/method.mustache b/templates/go/tests/client/method.mustache new file mode 100644 index 0000000000..bc18a4d692 --- /dev/null +++ b/templates/go/tests/client/method.mustache @@ -0,0 +1,5 @@ +_, err = client.{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}(client.NewApi{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}Request( + {{#parametersWithDataType}}{{#required}}{{> tests/generateParams}},{{/required}}{{/parametersWithDataType}} + ){{#parametersWithDataType}}{{^required}}.With{{#lambda.pascalcase}}{{{key}}}{{/lambda.pascalcase}}({{> tests/generateParams}}){{/required}}{{/parametersWithDataType}}{{#requestOptions}}, + {{#queryParameters.parametersWithDataType}}{{clientPrefix}}.QueryParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/queryParameters.parametersWithDataType}}{{#headers.parametersWithDataType}}{{clientPrefix}}.HeaderParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/headers.parametersWithDataType}} + {{/requestOptions}}) \ No newline at end of file diff --git a/templates/go/tests/client/step.mustache b/templates/go/tests/client/step.mustache new file mode 100644 index 0000000000..854dc9aaf7 --- /dev/null +++ b/templates/go/tests/client/step.mustache @@ -0,0 +1,6 @@ +{{#isCreateClient}} +{{> tests/client/createClient}} +{{/isCreateClient}} +{{#isMethod}} +{{> tests/client/method}} +{{/isMethod}} \ No newline at end of file diff --git a/templates/go/tests/client/suite.mustache b/templates/go/tests/client/suite.mustache new file mode 100644 index 0000000000..83088cf29a --- /dev/null +++ b/templates/go/tests/client/suite.mustache @@ -0,0 +1,74 @@ +package client + +import ( + "encoding/json" + "net/url" + "testing" + "regexp" + + "github.com/kinbiko/jsonassert" + "github.com/stretchr/testify/require" + + "gotests/tests" + + "github.com/algolia/algoliasearch-client-go/v4/algolia/{{clientImport}}" + "github.com/algolia/algoliasearch-client-go/v4/algolia/transport" +) + +func create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t *testing.T) (*{{clientPrefix}}.APIClient, *tests.EchoRequester) { + echo := &tests.EchoRequester{} + cfg := {{clientPrefix}}.Configuration{ + Configuration: transport.Configuration{ + AppID: "appID", + ApiKey: "apiKey", + Requester: echo, + },{{#hasRegionalHost}} + Region: {{clientPrefix}}.{{#lambda.uppercase}}{{defaultRegion}}{{/lambda.uppercase}},{{/hasRegionalHost}} + } + client, err := {{clientPrefix}}.NewClientWithConfig(cfg) + require.NoError(t, err) + + return client, echo +} + +{{#blocksClient}} +{{#tests}} +func Test{{#lambda.titlecase}}{{clientPrefix}}{{testType}}{{/lambda.titlecase}}{{testIndex}}(t *testing.T) { + var err error + {{#autoCreateClient}} + client, echo := create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client(t) + _ = echo + {{/autoCreateClient}} + {{^autoCreateClient}} + echo := &tests.EchoRequester{} + var client *{{clientPrefix}}.APIClient + var cfg {{clientPrefix}}.Configuration + _ = client + {{/autoCreateClient}} + {{#steps}} + {{#isError}} + {{> tests/client/step}} + require.EqualError(t, err, "{{{expectedError}}}") + {{/isError}} + {{^isError}} + require.NoError(t, err) + {{> tests/client/step}} + {{#match}} + {{#testUserAgent}} + require.Regexp(t, regexp.MustCompile(`{{{match}}}`), echo.Header.Get("User-Agent")) + {{/testUserAgent}} + {{#testTimeouts}} + require.Equal(t, int64({{{match.parametersWithDataTypeMap.connectTimeout.value}}}), echo.ConnectTimeout.Milliseconds()) + require.Equal(t, int64({{{match.parametersWithDataTypeMap.responseTimeout.value}}}), echo.Timeout.Milliseconds()) + {{/testTimeouts}} + {{#testHost}} + require.Equal(t, "{{{match}}}", echo.Host) + {{/testHost}} + {{/match}} + {{/isError}} + {{/steps}} +} + +{{/tests}} +{{/blocksClient}} + diff --git a/templates/go/tests/common.mustache b/templates/go/tests/common.mustache deleted file mode 100644 index aecf989767..0000000000 --- a/templates/go/tests/common.mustache +++ /dev/null @@ -1,35 +0,0 @@ -package tests - -import ( - "bytes" - "io" - "net/http" - "net/url" -) - -type echoRequester struct { - path string - method string - body *string - header http.Header - query url.Values -} - -func (e *echoRequester) Request(req *http.Request) (*http.Response, error) { - e.path = req.URL.Path - e.method = req.Method - e.header = req.Header - e.query = req.URL.Query() - if req.Body != nil { - body, _ := io.ReadAll(req.Body) - strBody := string(body) - e.body = &strBody - } else { - e.body = nil - } - - return &http.Response{ - StatusCode: 200, - Body: io.NopCloser(bytes.NewBufferString("")), - }, nil -} diff --git a/templates/go/tests/generateInnerParams.mustache b/templates/go/tests/generateInnerParams.mustache index efed30d218..bdf1c1e804 100644 --- a/templates/go/tests/generateInnerParams.mustache +++ b/templates/go/tests/generateInnerParams.mustache @@ -1,3 +1,3 @@ -{{#isNull}}null{{/isNull}}{{#isString}}"{{{value}}}"{{/isString}}{{#isInteger}}{{{value}}}{{/isInteger}}{{#isLong}}{{{value}}}{{/isLong}}{{#isDouble}}{{{value}}}{{/isDouble}}{{#isBoolean}}{{{value}}}{{/isBoolean}}{{#isEnum}}{{clientPrefix}}.{{objectName}}("{{{value}}}"){{/isEnum}}{{#isArray}} +{{#isNull}}{{#inClientTest}}tests.ZeroValue[{{#isNullObject}}*{{clientPrefix}}.{{/isNullObject}}{{objectName}}](){{/inClientTest}}{{^inClientTest}}nil{{/inClientTest}}{{/isNull}}{{#isString}}"{{{value}}}"{{/isString}}{{#isInteger}}{{{value}}}{{/isInteger}}{{#isLong}}{{{value}}}{{/isLong}}{{#isDouble}}{{{value}}}{{/isDouble}}{{#isBoolean}}{{{value}}}{{/isBoolean}}{{#isEnum}}{{clientPrefix}}.{{objectName}}("{{{value}}}"){{/isEnum}}{{#isArray}} {{> tests/arrayType}}{ {{#value}}{{#isObject}}*{{/isObject}}{{#oneOfModel}}{{^isObject}}*{{/isObject}}{{/oneOfModel}}{{> tests/generateParams}},{{/value}} }{{/isArray}}{{#isObject}} {{clientPrefix}}.NewEmpty{{objectName}}(){{#value}}{{#isAdditionalProperty}}.SetAdditionalProperty("{{{key}}}", {{> tests/generateParams}}){{/isAdditionalProperty}}{{^isAdditionalProperty}}.Set{{#lambda.pascalcase}}{{{key}}}{{/lambda.pascalcase}}({{> tests/generateParams}}){{/isAdditionalProperty}}{{/value}}{{/isObject}}{{#isFreeFormObject}}{{#isAnyType}}map[string]any{ {{#value}}{{#entrySet}}"{{{key}}}": "{{{value}}}",{{/entrySet}}{{/value}} }{{/isAnyType}}{{^isAnyType}}{{> tests/mapType}}{ {{#value}}"{{{key}}}": {{#oneOfModel}}{{^isObject}}*{{/isObject}}{{/oneOfModel}}{{#isObject}}*{{/isObject}}{{> tests/generateParams}},{{/value}} }{{/isAnyType}}{{/isFreeFormObject}} \ No newline at end of file diff --git a/templates/go/tests/requests/requests.mustache b/templates/go/tests/requests/requests.mustache index c527bc0369..74b4ad44c9 100644 --- a/templates/go/tests/requests/requests.mustache +++ b/templates/go/tests/requests/requests.mustache @@ -1,4 +1,4 @@ -package tests +package requests import ( "encoding/json" @@ -8,21 +8,23 @@ import ( "github.com/kinbiko/jsonassert" "github.com/stretchr/testify/require" + "gotests/tests" + "github.com/algolia/algoliasearch-client-go/v4/algolia/{{clientImport}}" + "github.com/algolia/algoliasearch-client-go/v4/algolia/transport" ) -func create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client() (*{{clientPrefix}}.APIClient, *echoRequester) { - echo := &echoRequester{} +func create{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}Client() (*{{clientPrefix}}.APIClient, *tests.EchoRequester) { + echo := &tests.EchoRequester{} cfg := {{clientPrefix}}.Configuration{ - AppID: "appID", - ApiKey: "apiKey",{{#hasRegionalHost}} + Configuration: transport.Configuration{ + AppID: "appID", + ApiKey: "apiKey", + Requester: echo, + },{{#hasRegionalHost}} Region: {{clientPrefix}}.{{#lambda.uppercase}}{{defaultRegion}}{{/lambda.uppercase}},{{/hasRegionalHost}} - Requester: echo, } - client := {{clientPrefix}}.NewClientWithConfig(cfg) - - // so that the linter doesn't complain - _ = jsonassert.New(nil) + client, _ := {{clientPrefix}}.NewClientWithConfig(cfg) return client, echo } @@ -42,33 +44,33 @@ func Test{{#lambda.titlecase}}{{clientPrefix}}{{/lambda.titlecase}}_{{#lambda.ti expectedPath, err := url.QueryUnescape("{{{request.path}}}") require.NoError(t, err) - require.Equal(t, expectedPath, echo.path) - require.Equal(t, "{{{request.method}}}", echo.method) + require.Equal(t, expectedPath, echo.Path) + require.Equal(t, "{{{request.method}}}", echo.Method) {{#request.body}} ja := jsonassert.New(t) - ja.Assertf(*echo.body, `{{{request.body}}}`) + ja.Assertf(*echo.Body, `{{{request.body}}}`) {{/request.body}} {{^request.body}} {{#assertNullBody}} - require.Nil(t, echo.body) + require.Nil(t, echo.Body) {{/assertNullBody}} {{^assertNullBody}} - require.Empty(t, echo.body); + require.Empty(t, echo.Body); {{/assertNullBody}} {{/request.body}} {{#request.headers}} headers := map[string]string{} require.NoError(t, json.Unmarshal([]byte(`{{{.}}}`), &headers)) for k, v := range headers { - require.Equal(t, v, echo.header.Get(k)) + require.Equal(t, v, echo.Header.Get(k)) } {{/request.headers}} {{#request.queryParameters}} queryParams := map[string]string{} require.NoError(t, json.Unmarshal([]byte(`{{{.}}}`), &queryParams)) for k, v := range queryParams { - require.Equal(t, v, echo.query.Get(k)) + require.Equal(t, v, echo.Query.Get(k)) } {{/request.queryParameters}} }) diff --git a/templates/go/utils.mustache b/templates/go/utils.mustache deleted file mode 100644 index 8d2980e636..0000000000 --- a/templates/go/utils.mustache +++ /dev/null @@ -1,376 +0,0 @@ -{{>partial_header}} -package {{packageName}} - -import ( - "encoding/json" - "reflect" - "time" - - "github.com/algolia/algoliasearch-client-go/v4/algolia/internal/errs" -) - -// PtrBool is a helper routine that returns a pointer to given boolean value. -func PtrBool(v bool) *bool { return &v } - -// PtrInt is a helper routine that returns a pointer to given integer value. -func PtrInt(v int) *int { return &v } - -// PtrInt32 is a helper routine that returns a pointer to given integer value. -func PtrInt32(v int32) *int32 { return &v } - -// PtrInt64 is a helper routine that returns a pointer to given integer value. -func PtrInt64(v int64) *int64 { return &v } - -// PtrFloat32 is a helper routine that returns a pointer to given float value. -func PtrFloat32(v float32) *float32 { return &v } - -// PtrFloat64 is a helper routine that returns a pointer to given float value. -func PtrFloat64(v float64) *float64 { return &v } - -// PtrString is a helper routine that returns a pointer to given string value. -func PtrString(v string) *string { return &v } - -// PtrTime is helper routine that returns a pointer to given Time value. -func PtrTime(v time.Time) *time.Time { return &v } - -type NullableBool struct { - value *bool - isSet bool -} - -func (v NullableBool) Get() *bool { - return v.value -} - -func (v *NullableBool) Set(val *bool) { - v.value = val - v.isSet = true -} - -func (v NullableBool) IsSet() bool { - return v.isSet -} - -func (v *NullableBool) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableBool(val *bool) *NullableBool { - return &NullableBool{value: val, isSet: true} -} - -func (v NullableBool) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableBool) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableInt struct { - value *int - isSet bool -} - -func (v NullableInt) Get() *int { - return v.value -} - -func (v *NullableInt) Set(val *int) { - v.value = val - v.isSet = true -} - -func (v NullableInt) IsSet() bool { - return v.isSet -} - -func (v *NullableInt) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableInt(val *int) *NullableInt { - return &NullableInt{value: val, isSet: true} -} - -func (v NullableInt) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableInt) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableInt32 struct { - value *int32 - isSet bool -} - -func (v NullableInt32) Get() *int32 { - return v.value -} - -func (v *NullableInt32) Set(val *int32) { - v.value = val - v.isSet = true -} - -func (v NullableInt32) IsSet() bool { - return v.isSet -} - -func (v *NullableInt32) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableInt32(val *int32) *NullableInt32 { - return &NullableInt32{value: val, isSet: true} -} - -func (v NullableInt32) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableInt32) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableInt64 struct { - value *int64 - isSet bool -} - -func (v NullableInt64) Get() *int64 { - return v.value -} - -func (v *NullableInt64) Set(val *int64) { - v.value = val - v.isSet = true -} - -func (v NullableInt64) IsSet() bool { - return v.isSet -} - -func (v *NullableInt64) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableInt64(val *int64) *NullableInt64 { - return &NullableInt64{value: val, isSet: true} -} - -func (v NullableInt64) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableInt64) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableFloat32 struct { - value *float32 - isSet bool -} - -func (v NullableFloat32) Get() *float32 { - return v.value -} - -func (v *NullableFloat32) Set(val *float32) { - v.value = val - v.isSet = true -} - -func (v NullableFloat32) IsSet() bool { - return v.isSet -} - -func (v *NullableFloat32) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableFloat32(val *float32) *NullableFloat32 { - return &NullableFloat32{value: val, isSet: true} -} - -func (v NullableFloat32) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableFloat32) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableFloat64 struct { - value *float64 - isSet bool -} - -func (v NullableFloat64) Get() *float64 { - return v.value -} - -func (v *NullableFloat64) Set(val *float64) { - v.value = val - v.isSet = true -} - -func (v NullableFloat64) IsSet() bool { - return v.isSet -} - -func (v *NullableFloat64) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableFloat64(val *float64) *NullableFloat64 { - return &NullableFloat64{value: val, isSet: true} -} - -func (v NullableFloat64) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableFloat64) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableString struct { - value *string - isSet bool -} - -func (v NullableString) Get() *string { - return v.value -} - -func (v *NullableString) Set(val *string) { - v.value = val - v.isSet = true -} - -func (v NullableString) IsSet() bool { - return v.isSet -} - -func (v *NullableString) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableString(val *string) *NullableString { - return &NullableString{value: val, isSet: true} -} - -func (v NullableString) MarshalJSON() ([]byte, error) { - return json.Marshal(v.value) -} - -func (v *NullableString) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -type NullableTime struct { - value *time.Time - isSet bool -} - -func (v NullableTime) Get() *time.Time { - return v.value -} - -func (v *NullableTime) Set(val *time.Time) { - v.value = val - v.isSet = true -} - -func (v NullableTime) IsSet() bool { - return v.isSet -} - -func (v *NullableTime) Unset() { - v.value = nil - v.isSet = false -} - -func NewNullableTime(val *time.Time) *NullableTime { - return &NullableTime{value: val, isSet: true} -} - -func (v NullableTime) MarshalJSON() ([]byte, error) { - return v.value.MarshalJSON() -} - -func (v *NullableTime) UnmarshalJSON(src []byte) error { - v.isSet = true - return json.Unmarshal(src, &v.value) -} - -// isNilorEmpty checks if an input is nil or empty -func isNilorEmpty(i any) bool { - if i == nil { - return true - } - switch reflect.TypeOf(i).Kind() { - case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: - return reflect.ValueOf(i).IsNil() - case reflect.Bool: - return false - default: - return reflect.ValueOf(i).IsZero() - } -} - -func RetryUntil[T any]( - retry func() (*T, error), - until func(*T, error) bool, - maxRetries *int, - initialDelay *time.Duration, - maxDelay *time.Duration, -) (*T, error) { - if maxRetries == nil { - maxRetries = new(int) - *maxRetries = 50 - } - - if initialDelay == nil { - initialDelay = new(time.Duration) - *initialDelay = 200 * time.Millisecond - } - - if maxDelay == nil { - maxDelay = new(time.Duration) - *maxDelay = 5 * time.Second - } - - for i := 0; i < *maxRetries; i++ { - res, err := retry() - - if ok := until(res, err); ok { - return res, nil - } - - time.Sleep(*initialDelay) - *initialDelay *= 2 - if *initialDelay > *maxDelay { - *initialDelay = *maxDelay - } - } - - return nil, &errs.WaitError{} -} \ No newline at end of file diff --git a/templates/ruby/snippets/method.mustache b/templates/ruby/snippets/method.mustache index f8dc72be88..f7c4b91df9 100644 --- a/templates/ruby/snippets/method.mustache +++ b/templates/ruby/snippets/method.mustache @@ -10,7 +10,7 @@ def snippet_for_{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}} client = Algolia::{{#lambda.pascalcase}}{{{client}}}{{/lambda.pascalcase}}.create('YOUR_APP_ID','YOUR_API_KEY'{{#hasRegionalHost}},'YOUR_APP_ID_REGION'{{/hasRegionalHost}}) # Call the API - resp = client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}({{#parametersWithDataType}}{{> tests/requests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) + resp = client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}({{#parametersWithDataType}}{{> tests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) # use the class directly puts resp @@ -20,4 +20,4 @@ def snippet_for_{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}} end {{/snippet}} -{{/blocksRequests}} \ No newline at end of file +{{/blocksRequests}} diff --git a/templates/ruby/tests/client/method.mustache b/templates/ruby/tests/client/method.mustache index 869c0a6e14..4ad1c2829d 100644 --- a/templates/ruby/tests/client/method.mustache +++ b/templates/ruby/tests/client/method.mustache @@ -1 +1 @@ -{{^isError}}req = {{/isError}}client.{{#lambda.snakecase}}{{path}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/requests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) \ No newline at end of file +{{^isError}}req = {{/isError}}client.{{#lambda.snakecase}}{{path}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) \ No newline at end of file diff --git a/templates/ruby/tests/generateParams.mustache b/templates/ruby/tests/generateParams.mustache new file mode 100644 index 0000000000..091edc8bb0 --- /dev/null +++ b/templates/ruby/tests/generateParams.mustache @@ -0,0 +1 @@ +{{#useAnonymousKey}}{{#lambda.escapeRubyKeywords}}{{{key}}}{{/lambda.escapeRubyKeywords}}: {{/useAnonymousKey}}{{#isNull}}nil, {{/isNull}}{{#isString}}"{{{value}}}", {{/isString}}{{#isInteger}}{{{value}}}, {{/isInteger}}{{#isLong}}{{{value}}}, {{/isLong}}{{#isDouble}}{{{value}}}, {{/isDouble}}{{#isBoolean}}{{{value}}}, {{/isBoolean}} {{#isEnum}}'{{{value}}}', {{/isEnum}}{{#isArray}} [ {{#value}}{{> tests/generateParams}}{{/value}} ], {{/isArray}}{{#isObject}} {{{objectName}}}.new({{#value}}{{> tests/generateParams}}{{/value}}), {{/isObject}}{{#isFreeFormObject}} {{#isAnyType}} { {{#value}}{{#entrySet}}'{{{key}}}':"{{{value}}}"{{^-last}},{{/-last}}{{/entrySet}}{{/value}} }, {{/isAnyType}} {{^isAnyType}} { {{#value}}{{> tests/generateParams}}{{/value}} }, {{/isAnyType}} {{/isFreeFormObject}} \ No newline at end of file diff --git a/templates/ruby/tests/requests/generateParams.mustache b/templates/ruby/tests/requests/generateParams.mustache deleted file mode 100644 index 75573c77d0..0000000000 --- a/templates/ruby/tests/requests/generateParams.mustache +++ /dev/null @@ -1 +0,0 @@ -{{#useAnonymousKey}}{{#lambda.escapeRubyKeywords}}{{{key}}}{{/lambda.escapeRubyKeywords}}: {{/useAnonymousKey}}{{#isNull}}nil, {{/isNull}}{{#isString}}"{{{value}}}", {{/isString}}{{#isInteger}}{{{value}}}, {{/isInteger}}{{#isLong}}{{{value}}}, {{/isLong}}{{#isDouble}}{{{value}}}, {{/isDouble}}{{#isBoolean}}{{{value}}}, {{/isBoolean}} {{#isEnum}}'{{{value}}}', {{/isEnum}}{{#isArray}} [ {{#value}}{{> tests/requests/generateParams}}{{/value}} ], {{/isArray}}{{#isObject}} {{{objectName}}}.new({{#value}}{{> tests/requests/generateParams}}{{/value}}), {{/isObject}}{{#isFreeFormObject}} {{#isAnyType}} { {{#value}}{{#entrySet}}'{{{key}}}':"{{{value}}}"{{^-last}},{{/-last}}{{/entrySet}}{{/value}} }, {{/isAnyType}} {{^isAnyType}} { {{#value}}{{> tests/requests/generateParams}}{{/value}} }, {{/isAnyType}} {{/isFreeFormObject}} \ No newline at end of file diff --git a/templates/ruby/tests/requests/requests.mustache b/templates/ruby/tests/requests/requests.mustache index 66a4eb8a6a..fee28461c8 100644 --- a/templates/ruby/tests/requests/requests.mustache +++ b/templates/ruby/tests/requests/requests.mustache @@ -28,7 +28,7 @@ class Test{{#lambda.pascalcase}}{{{client}}}{{/lambda.pascalcase}} < Test::Unit: {{#tests}} # {{{testName}}} def test_{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}{{testIndex}} - req = @client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/requests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) + req = @client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) {{#request}} assert_equal(:{{#lambda.lowercase}}{{method}}{{/lambda.lowercase}}, req.method) @@ -44,13 +44,13 @@ class Test{{#lambda.pascalcase}}{{{client}}}{{/lambda.pascalcase}} < Test::Unit: {{/request}} {{#response}} - res = @e2e_client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/requests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) + res = @e2e_client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}_with_http_info({{#parametersWithDataType}}{{> tests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) {{#statusCode}} assert_equal(res.status, {{statusCode}}) {{/statusCode}} {{#body}} - res = @e2e_client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}({{#parametersWithDataType}}{{> tests/requests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) + res = @e2e_client.{{#lambda.snakecase}}{{method}}{{/lambda.snakecase}}({{#parametersWithDataType}}{{> tests/generateParams}}{{/parametersWithDataType}}{{#hasRequestOptions}}{ {{#requestOptions.headers.parameters}}:header_params => JSON.parse('{{{.}}}', :symbolize_names => true),{{/requestOptions.headers.parameters}}{{#requestOptions.queryParameters.parameters}}:query_params => JSON.parse('{{{.}}}', :symbolize_names => true){{/requestOptions.queryParameters.parameters}} }{{/hasRequestOptions}}) expected_body = JSON.parse(%q({{{.}}})) assert_equal(expected_body, union(expected_body, JSON.parse(res.to_json))) {{/body}} diff --git a/tests/output/go/.golangci.yml b/tests/output/go/.golangci.yml new file mode 100644 index 0000000000..8dc91b9adb --- /dev/null +++ b/tests/output/go/.golangci.yml @@ -0,0 +1,10 @@ +linters: + disable: + - ineffassign + - staticcheck +service: + golangci-lint-version: 1.55.2 + +run: + concurrency: 2 + timeout: 10m diff --git a/tests/output/go/go.mod b/tests/output/go/go.mod index 9cb3540199..d1ea385140 100644 --- a/tests/output/go/go.mod +++ b/tests/output/go/go.mod @@ -1,6 +1,6 @@ -module tests +module gotests -go 1.19 +go 1.21 replace github.com/algolia/algoliasearch-client-go/v4 v4.0.0 => ../../../clients/algoliasearch-client-go diff --git a/tests/output/go/tests/echo.go b/tests/output/go/tests/echo.go new file mode 100644 index 0000000000..dcb2067fc1 --- /dev/null +++ b/tests/output/go/tests/echo.go @@ -0,0 +1,47 @@ +package tests + +import ( + "bytes" + "io" + "net/http" + "net/url" + "time" +) + +type EchoRequester struct { + Host string + Path string + Method string + Body *string + Header http.Header + Query url.Values + Timeout time.Duration + ConnectTimeout time.Duration +} + +func (e *EchoRequester) Request(req *http.Request, timeout time.Duration, connectTimeout time.Duration) (*http.Response, error) { + e.Host = req.URL.Host + e.Path = req.URL.Path + e.Method = req.Method + e.Header = req.Header + e.Query = req.URL.Query() + e.Timeout = timeout + e.ConnectTimeout = connectTimeout + if req.Body != nil { + body, _ := io.ReadAll(req.Body) + strBody := string(body) + e.Body = &strBody + } else { + e.Body = nil + } + + return &http.Response{ + StatusCode: 200, + Body: io.NopCloser(bytes.NewBufferString("")), + }, nil +} + +func ZeroValue[T any]() T { + var v T + return v +} diff --git a/website/docs/clients/guides/copy-or-move-index-rules-settings-synonyms.mdx b/website/docs/clients/guides/copy-or-move-index-rules-settings-synonyms.mdx index 4119fca128..4027df99d6 100644 --- a/website/docs/clients/guides/copy-or-move-index-rules-settings-synonyms.mdx +++ b/website/docs/clients/guides/copy-or-move-index-rules-settings-synonyms.mdx @@ -85,7 +85,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) operationIndexRequest := searchClient.NewApiOperationIndexRequest( indexName, @@ -259,7 +259,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) operationIndexRequest := searchClient.NewApiOperationIndexRequest( indexName, @@ -400,7 +400,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) operationIndexRequest := searchClient.NewApiOperationIndexRequest( indexName, diff --git a/website/docs/clients/guides/customized-client-usage.mdx b/website/docs/clients/guides/customized-client-usage.mdx index 841e6275f5..7617654754 100644 --- a/website/docs/clients/guides/customized-client-usage.mdx +++ b/website/docs/clients/guides/customized-client-usage.mdx @@ -67,7 +67,7 @@ var client = SearchClient( If you enable the `debug` property of the Go API client, it will print the request and response to the standard output. ```go -searchClient := search.NewClientWithConfig(search.Configuration{ +searchClient, _ := search.NewClientWithConfig(search.Configuration{ AppID: "", ApiKey: "", Debug: true, @@ -216,7 +216,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) searchClient.Search( searchClient.NewApiSearchRequest( @@ -341,7 +341,7 @@ import ( "github.com/algolia/algoliasearch-client-go/v4/algolia/search" ) -searchClient := search.NewClientWithConfig(search.Configuration{ +searchClient, _ := search.NewClientWithConfig(search.Configuration{ AppID: appID, ApiKey: apiKey, Hosts: nil, @@ -471,7 +471,7 @@ func (r *MyCustomRequester) Request(req *http.Request) (*http.Response, error) { return r.client.Do(req) } -searchClient := search.NewClientWithConfig(search.Configuration{ +searchClient, _ := search.NewClientWithConfig(search.Configuration{ AppID: appID, ApiKey: apiKey, Hosts: nil, diff --git a/website/docs/clients/guides/delete-objects.mdx b/website/docs/clients/guides/delete-objects.mdx index 7222c49f94..290cd073fb 100644 --- a/website/docs/clients/guides/delete-objects.mdx +++ b/website/docs/clients/guides/delete-objects.mdx @@ -107,7 +107,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) objectIDs := []string{"1", "2", "3", "4", "5"} batchRequests := make([]search.BatchRequest, 0, len(objectIDs)) diff --git a/website/docs/clients/guides/filtering-your-search.mdx b/website/docs/clients/guides/filtering-your-search.mdx index cbbef897f4..2ef3641aa2 100644 --- a/website/docs/clients/guides/filtering-your-search.mdx +++ b/website/docs/clients/guides/filtering-your-search.mdx @@ -97,7 +97,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.SetSettings(searchClient.NewApiSetSettingsRequest( indexName, @@ -354,7 +354,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) // Only "Scarlett Johansson" actor results, err := searchClient.Search( @@ -575,7 +575,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) // Only "Scarlett Johansson" actor results, err := searchClient.Search( diff --git a/website/docs/clients/guides/manage-dictionary-entries.mdx b/website/docs/clients/guides/manage-dictionary-entries.mdx index 587481387f..ef84e32585 100644 --- a/website/docs/clients/guides/manage-dictionary-entries.mdx +++ b/website/docs/clients/guides/manage-dictionary-entries.mdx @@ -136,7 +136,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.BatchDictionaryEntries( searchClient.NewApiBatchDictionaryEntriesRequest( @@ -307,7 +307,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.BatchDictionaryEntries( searchClient.NewApiBatchDictionaryEntriesRequest( @@ -431,7 +431,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.BatchDictionaryEntries( searchClient.NewApiBatchDictionaryEntriesRequest( @@ -563,7 +563,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.BatchDictionaryEntries( searchClient.NewApiBatchDictionaryEntriesRequest( diff --git a/website/docs/clients/guides/replace-all-rules-synonyms.mdx b/website/docs/clients/guides/replace-all-rules-synonyms.mdx index 1d80f58e48..f00cfac194 100644 --- a/website/docs/clients/guides/replace-all-rules-synonyms.mdx +++ b/website/docs/clients/guides/replace-all-rules-synonyms.mdx @@ -80,7 +80,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.SaveRules( searchClient.NewApiSaveRulesRequest( @@ -183,7 +183,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.SaveSynonyms( searchClient.NewApiSaveSynonymsRequest( diff --git a/website/docs/clients/guides/retrieving-facets.mdx b/website/docs/clients/guides/retrieving-facets.mdx index caff2ba167..c7854b14c5 100644 --- a/website/docs/clients/guides/retrieving-facets.mdx +++ b/website/docs/clients/guides/retrieving-facets.mdx @@ -171,7 +171,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) results, err := searchClient.Search( searchClient.NewApiSearchRequest( @@ -203,7 +203,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) results, err := searchClient.Search( searchClient.NewApiSearchRequest( diff --git a/website/docs/clients/guides/send-data-to-algolia.mdx b/website/docs/clients/guides/send-data-to-algolia.mdx index 86e302fb39..6cf7bb8a0d 100644 --- a/website/docs/clients/guides/send-data-to-algolia.mdx +++ b/website/docs/clients/guides/send-data-to-algolia.mdx @@ -75,7 +75,7 @@ import ( "github.com/algolia/algoliasearch-client-go/v4/algolia/search" ) -searchClient := search.NewClient("", "") +searchClient, _ := search.NewClient("", "") ``` @@ -258,7 +258,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) actors := []map[string]interface{}{ {"name": "Tom Cruise"}, diff --git a/website/docs/clients/guides/wait-for-a-task-to-finish.mdx b/website/docs/clients/guides/wait-for-a-task-to-finish.mdx index 8d0ae2c461..0859c6d88e 100644 --- a/website/docs/clients/guides/wait-for-a-task-to-finish.mdx +++ b/website/docs/clients/guides/wait-for-a-task-to-finish.mdx @@ -164,7 +164,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) response, err := searchClient.SaveObject( searchClient.NewApiSaveObjectRequest( diff --git a/website/docs/clients/guides/wait-for-api-key-to-be-valid.mdx b/website/docs/clients/guides/wait-for-api-key-to-be-valid.mdx index 4ced4b6a01..d38fb66050 100644 --- a/website/docs/clients/guides/wait-for-api-key-to-be-valid.mdx +++ b/website/docs/clients/guides/wait-for-api-key-to-be-valid.mdx @@ -206,7 +206,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) apiKeyStruct := search.NewApiKey([]search.Acl{"search"}) diff --git a/website/docs/clients/installation.mdx b/website/docs/clients/installation.mdx index 53c5b7593e..5801dc7dea 100644 --- a/website/docs/clients/installation.mdx +++ b/website/docs/clients/installation.mdx @@ -356,7 +356,7 @@ import ( func main() { // Instantiate the client - searchClient := search.NewClient("", "") + searchClient, _ := search.NewClient("", "") // Add a new record to your Algolia index. response, err := searchClient.AddOrUpdateObject( diff --git a/website/docs/clients/migration-guides/go.md b/website/docs/clients/migration-guides/go.md index 8dac60b3bc..8f1e235924 100644 --- a/website/docs/clients/migration-guides/go.md +++ b/website/docs/clients/migration-guides/go.md @@ -17,7 +17,7 @@ indexName := "" appID := "" apiKey := "" -searchClient := search.NewClient(appID, apiKey) +searchClient, _ := search.NewClient(appID, apiKey) results, err := searchClient.Search( searchClient.NewApiSearchRequest( diff --git a/website/docs/contributing/setup-repository.md b/website/docs/contributing/setup-repository.md index 12951fa3b3..61960ccdb6 100644 --- a/website/docs/contributing/setup-repository.md +++ b/website/docs/contributing/setup-repository.md @@ -39,6 +39,11 @@ The swift images takes a really long time to build (~5 minutes) because of swift ::: +## Tooling + +Install the CLI tool by following the instructions at the top of [scripts/install.sh](https://github.com/algolia/api-clients-automation/blob/main/scripts/install.sh) to acces `apic` from your terminal, with bash autocompletion. +You can run `apic help` to check if it's working properly. + #### Clean > Stops all containers and clean the images