diff --git a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/extension/package.scala b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/extension/package.scala index f6cb99b2896..371eecb653c 100644 --- a/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/extension/package.scala +++ b/clients/algoliasearch-client-scala/src/main/scala/algoliasearch/extension/package.scala @@ -308,7 +308,7 @@ package object extension { def partialUpdateObjects( indexName: String, objects: Seq[Any], - createIfNotExists: Boolean, + createIfNotExists: Boolean = false, requestOptions: Option[RequestOptions] = None )(implicit ec: ExecutionContext): Future[Seq[BatchResponse]] = { chunkedBatch( diff --git a/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java b/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java index fdb86263f0d..169fe0ecf2f 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/cts/AlgoliaCTSGenerator.java @@ -3,7 +3,6 @@ import com.algolia.codegen.cts.lambda.*; import com.algolia.codegen.cts.manager.CTSManager; import com.algolia.codegen.cts.manager.CTSManagerFactory; -import com.algolia.codegen.cts.snippets.*; import com.algolia.codegen.cts.tests.*; import com.algolia.codegen.exceptions.*; import com.algolia.codegen.utils.*; @@ -60,7 +59,7 @@ public void processOpts() { if (mode.equals("tests")) { ctsManager.addTestsSupportingFiles(supportingFiles); - testsGenerators.add(new TestsRequest(language, client, false)); + testsGenerators.add(new TestsRequest(language, client)); testsGenerators.add(new TestsClient(language, client, true)); testsGenerators.add(new TestsClient(language, client, false)); } else if (mode.equals("snippets")) { diff --git a/generators/src/main/java/com/algolia/codegen/cts/snippets/SnippetsGenerator.java b/generators/src/main/java/com/algolia/codegen/cts/snippets/SnippetsGenerator.java deleted file mode 100644 index 3c111558c54..00000000000 --- a/generators/src/main/java/com/algolia/codegen/cts/snippets/SnippetsGenerator.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.algolia.codegen.cts.snippets; - -import com.algolia.codegen.cts.tests.*; -import com.algolia.codegen.utils.*; -import java.io.File; -import java.util.*; -import org.openapitools.codegen.CodegenModel; -import org.openapitools.codegen.CodegenOperation; -import org.openapitools.codegen.SupportingFile; - -public class SnippetsGenerator extends TestsRequest { - - public SnippetsGenerator(String language, String client) { - super(language, client, true); - } - - @Override - public boolean available() { - File templates = new File("templates/" + language + "/snippets/method.mustache"); - return templates.exists(); - } - - @Override - public void addSupportingFiles(List supportingFiles, String outputFolder, String extension) { - if (!available()) { - return; - } - - extension = Helpers.getClientConfigField(language, "snippets", "extension"); - outputFolder = Helpers.getClientConfigField(language, "snippets", "outputFolder"); - - if (!outputFolder.equals("")) { - outputFolder = "/" + outputFolder + "/"; - } else { - outputFolder = "/"; - } - - supportingFiles.add( - new SupportingFile( - "snippets/method.mustache", - "snippets/" + language + outputFolder + Helpers.createClientName(client, language) + extension - ) - ); - } - - @Override - public void run(Map models, Map operations, Map bundle) throws Exception { - super.run(models, operations, bundle); - } -} 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 e4c44b90d7c..f86a43b3554 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 @@ -8,6 +8,16 @@ public class ClientTestData { public String testName; public boolean autoCreateClient = true; public List steps; + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ClientTestData {\n"); + sb.append(" testName: ").append(testName).append("\n"); + sb.append(" autoCreateClient: ").append(autoCreateClient).append("\n"); + sb.append(" steps: ").append(steps).append("\n"); + sb.append("}"); + return sb.toString(); + } } class Step { @@ -17,6 +27,18 @@ class Step { public int times; public Map parameters; public Expected expected; + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Step {\n"); + sb.append(" type: ").append(type).append("\n"); + sb.append(" method: ").append(method).append("\n"); + sb.append(" times: ").append(times).append("\n"); + sb.append(" parameters: ").append(parameters).append("\n"); + sb.append(" expected: ").append(expected).append("\n"); + sb.append("}"); + return sb.toString(); + } } class Expected { @@ -24,4 +46,14 @@ class Expected { public String type; public Object error; public Object match; + + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Expected {\n"); + sb.append(" type: ").append(type).append("\n"); + sb.append(" error: ").append(error).append("\n"); + sb.append(" match: ").append(match).append("\n"); + sb.append("}"); + return sb.toString(); + } } 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 71123200e3e..1a76d6b1a3b 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 @@ -18,11 +18,13 @@ public class ParametersWithDataType { private final Map models; private final String language; private final String client; + private final boolean prettyIndexName; - public ParametersWithDataType(Map models, String language, String client) { + public ParametersWithDataType(Map models, String language, String client, boolean prettyIndexName) { this.models = models; this.language = language; this.client = client; + this.prettyIndexName = prettyIndexName; } public void enhanceParameters(Map parameters, Map bundle) @@ -155,6 +157,11 @@ private Map traverseParams( handlePrimitive(param, testOutput, spec); } + // for snippets, we want pretty index names, unless they are already pretty + if (prettyIndexName && paramName.equals("indexName") && !((String) testOutput.get("value")).startsWith("<")) { + testOutput.put("value", ""); + } + return testOutput; } diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/RawDeserializer.java b/generators/src/main/java/com/algolia/codegen/cts/tests/RawDeserializer.java new file mode 100644 index 00000000000..739b16c2611 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/RawDeserializer.java @@ -0,0 +1,18 @@ +package com.algolia.codegen.cts.tests; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import java.io.IOException; + +// Output json to raw string with quotes +public class RawDeserializer extends JsonDeserializer { + + @Override + public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { + TreeNode tree = jp.getCodec().readTree(jp); + return tree.toString(); + } +} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/Request.java b/generators/src/main/java/com/algolia/codegen/cts/tests/Request.java index 390604eb5fe..ee379cffec1 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/Request.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/Request.java @@ -1,18 +1,10 @@ package com.algolia.codegen.cts.tests; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.TreeNode; -import com.fasterxml.jackson.databind.DeserializationContext; -import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.annotation.JsonDeserialize; -import java.io.IOException; import java.util.Map; public class Request { public String testName; - public boolean isSnippet; public Map parameters; public RequestOptions requestOptions; @@ -24,7 +16,6 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class Request {\n"); sb.append(" testName: ").append(testName).append("\n"); - sb.append(" isSnippet").append(isSnippet).append("\n"); sb.append(" parameters: ").append(parameters).append("\n"); sb.append(" requestOptions: ").append(requestOptions).append("\n"); sb.append(" request: ").append(request).append("\n"); @@ -33,75 +24,3 @@ public String toString() { return sb.toString(); } } - -class RequestOptions { - - public Map queryParameters; - public Map headers; - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class RequestOptions {\n"); - sb.append(" queryParameters: ").append(queryParameters).append("\n"); - sb.append(" headers: ").append(headers).append("\n"); - sb.append("}"); - return sb.toString(); - } -} - -class RequestProp { - - public String path; - public String method; - - @JsonDeserialize(using = RawDeserializer.class) - public String body; - - @JsonDeserialize(using = RawDeserializer.class) - public String queryParameters; - - @JsonDeserialize(using = RawDeserializer.class) - public String headers; - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class RequestProp {\n"); - sb.append(" path: ").append(path).append("\n"); - sb.append(" method: ").append(method).append("\n"); - sb.append(" body: ").append(body).append("\n"); - sb.append(" queryParameters: ").append(queryParameters).append("\n"); - sb.append(" headers: ").append(headers).append("\n"); - sb.append("}"); - return sb.toString(); - } -} - -class ResponseProp { - - public int statusCode; - - @JsonDeserialize(using = RawDeserializer.class) - public String body; - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class ResponseProp {\n"); - sb.append(" statusCode: ").append(statusCode).append("\n"); - sb.append(" body: ").append(body).append("\n"); - sb.append("}"); - return sb.toString(); - } -} - -// Output json to raw string with quotes -class RawDeserializer extends JsonDeserializer { - - @Override - public String deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - TreeNode tree = jp.getCodec().readTree(jp); - return tree.toString(); - } -} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/RequestOptions.java b/generators/src/main/java/com/algolia/codegen/cts/tests/RequestOptions.java new file mode 100644 index 00000000000..26bed532510 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/RequestOptions.java @@ -0,0 +1,19 @@ +package com.algolia.codegen.cts.tests; + +import java.util.Map; + +public class RequestOptions { + + public Map queryParameters; + public Map headers; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestOptions {\n"); + sb.append(" queryParameters: ").append(queryParameters).append("\n"); + sb.append(" headers: ").append(headers).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/RequestProp.java b/generators/src/main/java/com/algolia/codegen/cts/tests/RequestProp.java new file mode 100644 index 00000000000..a6edb26b631 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/RequestProp.java @@ -0,0 +1,31 @@ +package com.algolia.codegen.cts.tests; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +public class RequestProp { + + public String path; + public String method; + + @JsonDeserialize(using = RawDeserializer.class) + public String body; + + @JsonDeserialize(using = RawDeserializer.class) + public String queryParameters; + + @JsonDeserialize(using = RawDeserializer.class) + public String headers; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class RequestProp {\n"); + sb.append(" path: ").append(path).append("\n"); + sb.append(" method: ").append(method).append("\n"); + sb.append(" body: ").append(body).append("\n"); + sb.append(" queryParameters: ").append(queryParameters).append("\n"); + sb.append(" headers: ").append(headers).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/ResponseProp.java b/generators/src/main/java/com/algolia/codegen/cts/tests/ResponseProp.java new file mode 100644 index 00000000000..8f99f81cde2 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/ResponseProp.java @@ -0,0 +1,21 @@ +package com.algolia.codegen.cts.tests; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +public class ResponseProp { + + public int statusCode; + + @JsonDeserialize(using = RawDeserializer.class) + public String body; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ResponseProp {\n"); + sb.append(" statusCode: ").append(statusCode).append("\n"); + sb.append(" body: ").append(body).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/Snippet.java b/generators/src/main/java/com/algolia/codegen/cts/tests/Snippet.java new file mode 100644 index 00000000000..14c1213c783 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/Snippet.java @@ -0,0 +1,32 @@ +package com.algolia.codegen.cts.tests; + +import java.util.Map; + +public class Snippet { + + public String testName; + public boolean isSnippet; + + public Map parameters; + public RequestOptions requestOptions; + + public Snippet(String testName, Map parameters) { + this.testName = testName; + this.isSnippet = true; + this.parameters = parameters; + } + + public Snippet() {} + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Request {\n"); + sb.append(" testName: ").append(testName).append("\n"); + sb.append(" isSnippet").append(isSnippet).append("\n"); + sb.append(" parameters: ").append(parameters).append("\n"); + sb.append(" requestOptions: ").append(requestOptions).append("\n"); + sb.append("}"); + return sb.toString(); + } +} diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/SnippetsGenerator.java b/generators/src/main/java/com/algolia/codegen/cts/tests/SnippetsGenerator.java new file mode 100644 index 00000000000..e8166973b89 --- /dev/null +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/SnippetsGenerator.java @@ -0,0 +1,170 @@ +package com.algolia.codegen.cts.tests; + +import static org.openapitools.codegen.utils.StringUtils.camelize; + +import com.algolia.codegen.exceptions.CTSException; +import com.algolia.codegen.utils.*; +import java.io.File; +import java.util.*; +import org.apache.commons.lang3.ArrayUtils; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenResponse; +import org.openapitools.codegen.SupportingFile; + +public class SnippetsGenerator extends TestsGenerator { + + public SnippetsGenerator(String language, String client) { + super(language, client); + } + + @Override + public boolean available() { + File templates = new File("templates/" + language + "/snippets/method.mustache"); + return templates.exists(); + } + + @Override + public void addSupportingFiles(List supportingFiles, String outputFolder, String extension) { + if (!available()) { + return; + } + + extension = Helpers.getClientConfigField(language, "snippets", "extension"); + outputFolder = Helpers.getClientConfigField(language, "snippets", "outputFolder"); + + if (!outputFolder.equals("")) { + outputFolder = "/" + outputFolder + "/"; + } else { + outputFolder = "/"; + } + + supportingFiles.add( + new SupportingFile( + "snippets/method.mustache", + "snippets/" + language + outputFolder + Helpers.createClientName(client, language) + extension + ) + ); + } + + private Map loadSnippets(Map operations) throws Exception { + Map snippets = loadFullCTS(Snippet[].class); + + String clientName = client; + if (client.equals("algoliasearch")) { + clientName = "search"; + } + + // also include helpers + Map clientsTests = loadCTS("client", clientName, ClientTestData[].class); + for (Map.Entry blockEntry : clientsTests.entrySet()) { + for (ClientTestData test : blockEntry.getValue()) { + for (var step : test.steps) { + if (step.method != null && step.type.equals("method")) { + CodegenOperation ope = operations.get(step.method); + if (ope == null || !(boolean) ope.vendorExtensions.getOrDefault("x-helper", false)) { + continue; + } + Snippet newSnippet = new Snippet(test.testName, step.parameters); + Snippet[] existing = snippets.get(step.method); + if (existing == null) { + snippets.put(step.method, new Snippet[] { newSnippet }); + } else { + snippets.put(step.method, ArrayUtils.add(existing, newSnippet)); + } + } + } + } + } + + return snippets; + } + + @Override + public void run(Map models, Map operations, Map bundle) throws Exception { + Map snippets = loadSnippets(operations); + + if (this.client.equals("search")) { + bundle.put("isSearchClient", true); + } + + List blocks = new ArrayList<>(); + ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client, true); + + for (Map.Entry entry : operations.entrySet()) { + String operationId = entry.getKey(); + CodegenOperation ope = entry.getValue(); + boolean isHelper = (boolean) ope.vendorExtensions.getOrDefault("x-helper", false); + + if (!snippets.containsKey(operationId)) { + continue; + } + + List ops = Arrays.stream(snippets.get(operationId)).filter(r -> r.isSnippet).toList(); + if (ops.size() == 0) { + // default to the first test + ops = List.of(snippets.get(operationId)[0]); + } + + List> tests = new ArrayList<>(); + + for (int i = 0; i < ops.size(); i++) { + Map test = new HashMap<>(); + Snippet snippet = ops.get(i); + test.put("method", operationId); + String name = snippet.testName == null ? operationId : snippet.testName; + test.put("testName", ops.size() > 1 ? name : "default"); + test.put("description", name); + test.put("testIndex", i == 0 ? "" : i); + if (ope.returnType != null && ope.returnType.length() > 0) { + test.put("returnType", camelize(ope.returnType)); + } + + try { + test.put("isGeneric", (boolean) ope.vendorExtensions.getOrDefault("x-is-generic", false)); + test.put("isCustomRequest", Helpers.CUSTOM_METHODS.contains(ope.operationIdOriginal)); + test.put("isAsync", (boolean) ope.vendorExtensions.getOrDefault("x-asynchronous-helper", true)); + test.put("hasParams", ope.hasParams); + test.put("isHelper", isHelper); + + if (snippet.requestOptions != null) { + test.put("hasRequestOptions", true); + Map requestOptions = new HashMap<>(); + if (snippet.requestOptions.queryParameters != null) { + Map queryParameters = new HashMap<>(); + paramsType.enhanceParameters(snippet.requestOptions.queryParameters, queryParameters); + requestOptions.put("queryParameters", queryParameters); + } + if (snippet.requestOptions.headers != null) { + Map headers = new HashMap<>(); + // convert the headers to an acceptable type + paramsType.enhanceParameters(new HashMap(snippet.requestOptions.headers), headers); + requestOptions.put("headers", headers); + } + test.put("requestOptions", requestOptions); + } + + // Determines whether the endpoint is expected to return a response payload deserialized + // and therefore a variable to store it into. + test.put("hasResponsePayload", true); + + for (CodegenResponse response : ope.responses) { + if (response.code.equals("204")) { + test.put("hasResponsePayload", false); + } + } + + paramsType.enhanceParameters(snippet.parameters, test, ope); + tests.add(test); + } catch (CTSException e) { + e.setTestName((String) test.get("testName")); + throw e; + } + } + Map testObj = new HashMap<>(); + testObj.put("snippets", tests); + blocks.add(testObj); + } + bundle.put("blocksRequests", blocks); + } +} 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 d4234b44bc0..21f92a2cffc 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 @@ -1,7 +1,5 @@ package com.algolia.codegen.cts.tests; -import static com.algolia.codegen.utils.Helpers.CUSTOM_METHODS; - import com.algolia.codegen.exceptions.CTSException; import com.algolia.codegen.utils.*; import io.swagger.util.Json; @@ -61,7 +59,7 @@ public void addSupportingFiles(List supportingFiles, String outp public void run(Map models, Map operations, Map bundle) throws Exception { Map cts = loadCTS(testType, client, ClientTestData[].class); - ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client); + ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client, false); List blocks = new ArrayList<>(); for (Map.Entry blockEntry : cts.entrySet()) { @@ -121,10 +119,8 @@ public void run(Map models, Map } stepOut.put("method", step.method); + stepOut.put("isCustomRequest", step.method != null && Helpers.CUSTOM_METHODS.contains(step.method)); - if (step.method != null && CUSTOM_METHODS.contains(step.method)) { - stepOut.put("isCustomRequest", true); - } paramsType.enhanceParameters(step.parameters, stepOut, ope); // Swift is strongly-typed and compiled language, diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsGenerator.java b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsGenerator.java index a8062e9d6fe..95fcbbb89a0 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsGenerator.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsGenerator.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.apache.commons.lang3.ArrayUtils; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.SupportingFile; @@ -57,6 +58,38 @@ protected Map loadCTS(String path, String clientName, Class js return cts; } + protected Map loadFullCTS(Class jsonType) throws Exception { + String clientName = client; + // This special case allow us to read the `search` CTS to generated the tests for the + // `lite` client, which is available in Javascript and Dart + if (client.equals("algoliasearch")) { + clientName = "search"; + } + + Map baseCTS = loadCTS("requests", clientName, jsonType); + + // The algoliasearch client bundles many client and therefore should provide tests for all the + // subsequent specs + if (client.equals("algoliasearch")) { + Map recommendCTS = loadCTS("requests", "recommend", jsonType); + for (Map.Entry entry : recommendCTS.entrySet()) { + String operation = entry.getKey(); + // custom methods are common to every clients, we don't want duplicate tests + if (operation.startsWith("custom")) { + continue; + } + + if (baseCTS.containsKey(operation)) { + baseCTS.put(operation, ArrayUtils.addAll(baseCTS.get(operation), entry.getValue())); + } else { + baseCTS.put(operation, entry.getValue()); + } + } + } + + return baseCTS; + } + private String languageCased() { switch (language) { case "javascript": diff --git a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsRequest.java b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsRequest.java index 034e16cadd9..6994f0ce2c1 100644 --- a/generators/src/main/java/com/algolia/codegen/cts/tests/TestsRequest.java +++ b/generators/src/main/java/com/algolia/codegen/cts/tests/TestsRequest.java @@ -6,7 +6,6 @@ import com.algolia.codegen.utils.*; import java.io.File; import java.util.*; -import org.apache.commons.lang3.ArrayUtils; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.CodegenResponse; @@ -14,44 +13,10 @@ public class TestsRequest extends TestsGenerator { - private final boolean withSnippets; private List supportingFiles; - public TestsRequest(String language, String client, boolean withSnippets) { + public TestsRequest(String language, String client) { super(language, client); - this.withSnippets = withSnippets; - } - - protected Map loadRequestCTS() throws Exception { - String clientName = client; - // This special case allow us to read the `search` CTS to generated the tests for the - // `lite` client, which is only available in Javascript - if (client.equals("algoliasearch")) { - clientName = "search"; - } - - Map baseCTS = super.loadCTS("requests", clientName, Request[].class); - - // The algoliasearch client bundles many client and therefore should provide tests for all the - // subsequent specs - if (client.equals("algoliasearch")) { - Map recommendCTS = super.loadCTS("requests", "recommend", Request[].class); - for (Map.Entry entry : recommendCTS.entrySet()) { - String operation = entry.getKey(); - // custom methods are common to every clients, we don't want duplicate tests - if (operation.startsWith("custom")) { - continue; - } - - if (baseCTS.containsKey(operation)) { - baseCTS.put(operation, ArrayUtils.addAll(baseCTS.get(operation), entry.getValue())); - } else { - baseCTS.put(operation, entry.getValue()); - } - } - } - - return baseCTS; } @Override @@ -103,7 +68,7 @@ private String escapeBody(String body) { @Override public void run(Map models, Map operations, Map bundle) throws Exception { - Map cts = loadRequestCTS(); + Map cts = loadFullCTS(Request[].class); if (this.client.equals("search")) { bundle.put("isSearchClient", true); @@ -111,7 +76,7 @@ public void run(Map models, Map List blocks = new ArrayList<>(); List blocksE2E = new ArrayList<>(); - ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client); + ParametersWithDataType paramsType = new ParametersWithDataType(models, language, client, false); bundle.put("e2eApiKey", client.equals("monitoring") ? "MONITORING_API_KEY" : "ALGOLIA_ADMIN_KEY"); @@ -148,16 +113,13 @@ public void run(Map models, Map test.put("method", operationId); test.put("testName", req.testName == null ? operationId : req.testName); test.put("testIndex", i == 0 ? "" : i); - test.put("isSnippet", req.isSnippet); if (ope.returnType != null && ope.returnType.length() > 0) { test.put("returnType", camelize(ope.returnType)); } try { test.put("isGeneric", (boolean) ope.vendorExtensions.getOrDefault("x-is-generic", false)); - if (Helpers.CUSTOM_METHODS.contains(ope.operationIdOriginal)) { - test.put("isCustomRequest", true); - } + test.put("isCustomRequest", Helpers.CUSTOM_METHODS.contains(ope.operationIdOriginal)); if (req.request != null && !isHelper) { // We check on the spec if body parameters should be present in the CTS @@ -224,21 +186,6 @@ public void run(Map models, Map testObj.put("tests", tests); testObj.put("operationId", operationId); - if (withSnippets) { - List> snippets = tests.stream().filter(t -> (boolean) t.getOrDefault("isSnippet", false)).toList(); - if (snippets.size() == 0) { - Map snippet = tests.get(0); - snippet.put("description", snippet.get("testName")); - snippet.put("testName", "default"); - snippets = List.of(snippet); - } else { - for (Map snippet : snippets) { - snippet.put("description", snippet.get("testName")); - } - } - testObj.put("snippets", snippets); - } - blocks.add(testObj); // extract e2e diff --git a/scripts/specs/helper-snippets.ts b/scripts/specs/helper-snippets.ts deleted file mode 100644 index 251c1cea105..00000000000 --- a/scripts/specs/helper-snippets.ts +++ /dev/null @@ -1,140 +0,0 @@ -export const waitForAppTask = { - csharp: 'await client.WaitForAppTaskAsync(response.TaskID);', - dart: 'await client.waitAppTask(response.taskID);', - go: `taskResponse, err := searchClient.WaitForAppTask(response.TaskID, nil, nil, nil) -if err != nil { - panic(err) -}`, - java: 'client.waitForAppTask(response.getTaskID());', - javascript: 'await client.waitForAppTask({ taskID: response.taskID });', - kotlin: 'client.waitAppTask(response.taskID)', - php: "$client->waitForAppTask($response['taskID']);", - python: 'await client.wait_for_app_task(task_id=response.task_id)', - ruby: 'client.wait_for_app_task(response.task_id)', - scala: 'client.waitAppTask(response.getTaskID())', - swift: 'try await client.waitForAppTask(with: response.taskID)', -}; - -export const waitForApiKey = { - csharp: { - add: 'await client.WaitForApiKeyAsync(ApiKeyOperation.Add, response.Key);', - update: `await client.WaitForApiKeyAsync(ApiKeyOperation.Update, response.Key, { - Acl = new List { Enum.Parse("Search"), Enum.Parse("AddObject") }, - Validity = 300, - MaxQueriesPerIPPerHour = 100, - MaxHitsPerQuery = 20, - });`, - delete: 'await client.WaitForApiKeyAsync(ApiKeyOperation.Delete, response.Key);', - }, - dart: { - add: '', - update: '', - delete: '', - }, - go: { - add: `waitResponse, err := client.WaitForApiKey(search.API_KEY_OPERATION_ADD, response.Key, nil) -if err != nil { - panic(err) -}`, - update: `waitResponse, err := client.WaitForApiKey(search.API_KEY_OPERATION_UPDATE, response.Key, search.NewEmptyApiKey().SetAcl([]search.Acl{search.Acl("search"), search.Acl("addObject")}).SetValidity(300).SetMaxQueriesPerIPPerHour(100).SetMaxHitsPerQuery(20)) -if err != nil { - panic(err) -}`, - delete: `waitResponse, err := client.WaitForApiKey(search.API_KEY_OPERATION_DELETE, response.Key, nil) -if err != nil { - panic(err) -}`, - }, - java: { - add: 'client.waitForApiKey(ApiKeyOperation.ADD, response.Key, null)', - update: `client.waitForApiKey(ApiKeyOperation.UPDATE, response.Key, new ApiKey() - .setAcl(List.of(Acl.SEARCH, Acl.ADD_OBJECT)) - .setValidity(300) - .setMaxQueriesPerIPPerHour(100) - .setMaxHitsPerQuery(20))`, - delete: 'client.waitForApiKey(ApiKeyOperation.DELETE, response.Key, null)', - }, - javascript: { - add: 'await client.waitForApiKey({ operation: "<>", key: response.key });', - update: `await client.waitForApiKey({ operation: "<>", key: response.key, apiKey: { - acl: ['search', 'addObject'], - validity: 300, - maxQueriesPerIPPerHour: 100, - maxHitsPerQuery: 20, - }});`, - delete: 'await client.waitForApiKey({ operation: "<>", key: response.key });', - }, - kotlin: { - add: '', - update: '', - delete: '', - }, - php: { - add: "$client->waitForApiKey('<>', $response['key']);", - update: `$client->waitForApiKey('<>', $response['key'], [ - 'acl' => [ - 'search', - 'addObject', - ], - 'validity' => 300, - 'maxQueriesPerIPPerHour' => 100, - 'maxHitsPerQuery' => 20, - ]);`, - delete: "$client->waitForApiKey('<>', $response['key']);", - }, - python: { - add: 'await client.wait_for_api_key(operation="<>", key=response.key)', - update: `await client.wait_for_api_key(operation="<>", key=response.key, api_key={ - "acl": [ - "search", - "addObject", - ], - "validity": 300, - "maxQueriesPerIPPerHour": 100, - "maxHitsPerQuery": 20, - })`, - delete: 'await client.wait_for_api_key(operation="<>", key=response.key)', - }, - ruby: { - add: 'await client.wait_for_api_key(operation="<>", key=response.key)', - update: `await client.wait_for_api_key(operation="<>", key=response.key, api_key=ApiKey.new( - acl: ['search', 'addObject'], - validity: 300, - max_queries_per_ip_per_hour: 100, - max_hits_per_query: 20 - ))`, - delete: 'await client.wait_for_api_key(operation="<>", key=response.key)', - }, - scala: { - add: '', - update: '', - delete: '', - }, - swift: { - add: 'try await client.waitForApiKey(with: response.key, operation: ApiKeyOperation.add)', - update: `try await client.waitForApiKey(with: response.key, operation: ApiKeyOperation.update, apiKey: ApiKey( - acl: [Acl.search, Acl.addObject], - maxHitsPerQuery: 20, - maxQueriesPerIPPerHour: 100, - validity: 300 - ))`, - delete: 'try await client.waitForApiKey(with: response.key, operation: ApiKeyOperation.delete)', - }, -}; - -export const waitForTask = { - csharp: 'await client.WaitForTaskAsync("<>", response.TaskID);', - dart: "await client.waitTask('<>', response.taskID);", - go: `taskResponse, err := searchClient.WaitForTask("<>", response.TaskID, nil, nil, nil) -if err != nil { - panic(err) -}`, - java: 'client.waitForTask("<>", response.getTaskID());', - javascript: "await client.waitForTask({ indexName: '<>', taskID: response.taskID });", - kotlin: 'client.waitTask("<>", response.taskID)', - php: "$client->waitForTask('<>', $response['taskID']);", - python: 'await client.wait_for_task(index_name="<>", task_id=response.task_id)', - ruby: 'client.wait_for_task("<>", response.task_id)', - scala: 'client.waitTask("<>", response.getTaskID())', - swift: 'try await client.waitForTask(with: response.taskID, in: "<>")', -}; diff --git a/scripts/specs/snippets.ts b/scripts/specs/snippets.ts index 02372da5833..74f0c9532e3 100644 --- a/scripts/specs/snippets.ts +++ b/scripts/specs/snippets.ts @@ -3,8 +3,6 @@ import fsp from 'fs/promises'; import { GENERATORS, capitalize, createClientName, toAbsolutePath } from '../common.js'; import type { Language } from '../types.js'; -/* eslint import/namespace: ['error', { allowComputed: true }]*/ -import * as helperSnippets from './helper-snippets.js'; import type { CodeSamples, SnippetForMethod, SnippetSamples } from './types.js'; export function getCodeSampleLabel(language: Language): CodeSamples['label'] { @@ -20,16 +18,6 @@ export function getCodeSampleLabel(language: Language): CodeSamples['label'] { } } -function getHelperSnippet(helperName: keyof typeof helperSnippets, language: string): Record | string { - if (typeof helperSnippets[helperName][language] === 'string') { - return { - default: helperSnippets[helperName][language], - }; - } - - return helperSnippets[helperName][language]; -} - // Iterates over the snippet samples and sanitize the data to only keep the method part in order to use it in the guides. export function transformCodeSamplesToGuideMethods(snippetSamples: SnippetSamples): string { for (const [language, operationWithSample] of Object.entries(snippetSamples)) { @@ -56,11 +44,6 @@ export function transformCodeSamplesToGuideMethods(snippetSamples: SnippetSample snippetSamples[language][operation][sampleName] = callLine.replace(/\n$/, ''); } } - - // add specific helper snippets to the current language - snippetSamples[language].waitForAppTask = getHelperSnippet('waitForAppTask', language); - snippetSamples[language].waitForApiKey = getHelperSnippet('waitForApiKey', language); - snippetSamples[language].waitForTask = getHelperSnippet('waitForTask', language); } return JSON.stringify(snippetSamples, null, 2); diff --git a/templates/javascript/snippets/method.mustache b/templates/javascript/snippets/method.mustache index 2eb68823e5e..5914ded7d9b 100644 --- a/templates/javascript/snippets/method.mustache +++ b/templates/javascript/snippets/method.mustache @@ -11,7 +11,7 @@ import type { RequestOptions } from '@algolia/client-common'; // Snippet for the {{method}} method. // // {{{description}}} -export async function snippetFor{{#lambda.pascalcase}}{{method}}{{/lambda.pascalcase}}{{testIndex}}(): Promise { +export {{#isAsync}}async{{/isAsync}} function snippetFor{{#lambda.pascalcase}}{{method}}{{/lambda.pascalcase}}{{testIndex}}(): {{#isAsync}}Promise{{/isAsync}}{{^isAsync}}void{{/isAsync}} { // >SEPARATOR {{method}} {{testName}} // Initialize the client const client = {{client}}("YOUR_APP_ID", "YOUR_API_KEY", {{#hasRegionalHost}}'YOUR_APP_ID_REGION', {{/hasRegionalHost}}); diff --git a/templates/kotlin/snippets/method.mustache b/templates/kotlin/snippets/method.mustache index d3838d4dde4..3cf5c7d38a4 100644 --- a/templates/kotlin/snippets/method.mustache +++ b/templates/kotlin/snippets/method.mustache @@ -3,9 +3,11 @@ package com.algolia.snippets // >IMPORT import com.algolia.client.api.{{client}} +{{#isSearchClient}} +import com.algolia.client.extensions.* +{{/isSearchClient}} // IMPORT< import com.algolia.client.model.{{import}}.* - import kotlinx.serialization.json.* import kotlin.system.exitProcess diff --git a/templates/scala/snippets/method.mustache b/templates/scala/snippets/method.mustache index d46a00061fd..9d0c93c9d9e 100644 --- a/templates/scala/snippets/method.mustache +++ b/templates/scala/snippets/method.mustache @@ -5,6 +5,9 @@ import scala.concurrent.duration.Duration // >IMPORT import algoliasearch.api.{{client}} +{{#isSearchClient}} +import algoliasearch.extension.SearchClientExtensions +{{/isSearchClient}} // IMPORT< import algoliasearch.{{import}}.* @@ -18,6 +21,7 @@ class Snippet{{client}} { {{#blocksRequests}} {{#snippets}} + {{^isHelper}} {{! Helper tests are not supported yet}} /** Snippet for the {{method}} method. * * {{{description}}} @@ -35,6 +39,7 @@ class Snippet{{client}} { // SEPARATOR< } + {{/isHelper}} {{/snippets}} {{/blocksRequests}} } \ No newline at end of file diff --git a/templates/scala/tests/param_optional.mustache b/templates/scala/tests/param_optional.mustache index b4ec4178a6a..b352bd23420 100644 --- a/templates/scala/tests/param_optional.mustache +++ b/templates/scala/tests/param_optional.mustache @@ -1 +1 @@ -{{^required}}Some({{/required}}{{> tests/param_value}}{{^required}}){{/required}} \ No newline at end of file +{{^required}}{{^isHelper}}Some({{/isHelper}}{{#isHelper}}{{^isRoot}}Some({{/isRoot}}{{/isHelper}}{{/required}}{{> tests/param_value}}{{^required}}{{^isHelper}}){{/isHelper}}{{#isHelper}}{{^isRoot}}){{/isRoot}}{{/isHelper}}{{/required}} \ No newline at end of file