Skip to content

Commit ec3f8c8

Browse files
committed
feat(cts): generate tests for helpers
1 parent 072c38b commit ec3f8c8

File tree

38 files changed

+218
-107
lines changed

38 files changed

+218
-107
lines changed

clients/algoliasearch-client-csharp/algoliasearch/Models/Common/SecuredApiKeyRestrictionHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Algolia.Search.Models.Search;
99
/// <summary>
1010
/// Secured Api Key restrictions
1111
/// </summary>
12-
public partial class SecuredAPIKeyRestrictions
12+
public partial class SecuredApiKeyRestrictions
1313
{
1414

1515
/// <summary>

clients/algoliasearch-client-csharp/algoliasearch/Utils/SearchClientExtensions.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -273,20 +273,20 @@ public string GenerateSecuredApiKey(string parentApiKey, SecuredAPIKeyRestrictio
273273

274274

275275
/// <summary>
276-
/// Get the remaining validity of a key generated by `GenerateSecuredApiKeys`.
276+
/// Get the remaining validity of a key generated by `GenerateSecuredApiKey`.
277277
/// </summary>
278278
/// <param name="securedAPIKey">The secured API Key</param>
279279
/// <returns></returns>
280280
/// <exception cref="ArgumentNullException"></exception>
281281
/// <exception cref="AlgoliaException"></exception>
282282
public TimeSpan GetSecuredApiKeyRemainingValidity(string securedAPIKey)
283283
{
284-
if (string.IsNullOrWhiteSpace(securedAPIKey))
284+
if (string.IsNullOrWhiteSpace(securedApiKey))
285285
{
286-
throw new ArgumentNullException(nameof(securedAPIKey));
286+
throw new ArgumentNullException(nameof(securedApiKey));
287287
}
288288

289-
var decodedKey = Encoding.UTF8.GetString(Convert.FromBase64String(securedAPIKey));
289+
var decodedKey = Encoding.UTF8.GetString(Convert.FromBase64String(securedApiKey));
290290

291291
var regex = new Regex(@"validUntil=\d+");
292292
var matches = regex.Matches(decodedKey);

clients/algoliasearch-client-javascript/packages/client-common/src/transporter/helpers.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,14 @@ export function serializeUrl(
4242
}
4343

4444
export function serializeQueryParameters(parameters: QueryParameters): string {
45-
const isObjectOrArray = (value: any): boolean =>
46-
Object.prototype.toString.call(value) === '[object Object]' ||
47-
Object.prototype.toString.call(value) === '[object Array]';
48-
4945
return Object.keys(parameters)
46+
.filter((key) => parameters[key] !== undefined)
47+
.sort()
5048
.map(
5149
(key) =>
5250
`${key}=${encodeURIComponent(
53-
isObjectOrArray(parameters[key])
54-
? JSON.stringify(parameters[key])
51+
Object.prototype.toString.call(parameters[key]) === '[object Array]'
52+
? parameters[key].join(',')
5553
: parameters[key]
5654
).replaceAll('+', '%20')}`
5755
)

clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/extensions/SearchClient.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,13 +335,13 @@ public suspend fun <T> SearchClient.replaceAllObjects(
335335
/**
336336
* Generate a virtual API Key without any call to the server.
337337
*
338-
* @param parentAPIKey API key to generate from.
338+
* @param parentApiKey API key to generate from.
339339
* @param restriction Restriction to add the key
340340
* @throws Exception if an error occurs during the encoding
341341
*/
342-
public fun SearchClient.generateSecuredApiKey(parentAPIKey: String, restriction: SecuredAPIKeyRestrictions): String {
342+
public fun SearchClient.generateSecuredApiKey(parentApiKey: String, restriction: SecuredApiKeyRestrictions): String {
343343
val restrictionString = buildRestrictionString(restriction)
344-
val hash = encodeKeySHA256(parentAPIKey, restrictionString)
344+
val hash = encodeKeySHA256(parentApiKey, restrictionString)
345345
return "$hash$restrictionString".encodeBase64()
346346
}
347347

@@ -350,7 +350,7 @@ public fun SearchClient.generateSecuredApiKey(parentAPIKey: String, restriction:
350350
*
351351
* @param apiKey The secured API Key to check.
352352
* @return Duration left before the secured API key expires.
353-
* @throws IllegalArgumentException if [apiKey] doesn't have a [SecuredAPIKeyRestrictions.validUntil].
353+
* @throws IllegalArgumentException if [apiKey] doesn't have a [SecuredApiKeyRestrictions.validUntil].
354354
*/
355355
public fun securedApiKeyRemainingValidity(apiKey: String): Duration {
356356
val decoded = apiKey.decodeBase64String()

clients/algoliasearch-client-kotlin/client/src/commonMain/kotlin/com/algolia/client/extensions/internal/SearchClient.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ package com.algolia.client.extensions.internal
22

33
import com.algolia.client.api.SearchClient
44
import com.algolia.client.model.search.SearchParamsObject
5-
import com.algolia.client.model.search.SecuredAPIKeyRestrictions
5+
import com.algolia.client.model.search.SecuredApiKeyRestrictions
66
import io.ktor.http.*
77
import kotlinx.serialization.json.JsonArray
88
import kotlinx.serialization.json.jsonObject
99
import kotlinx.serialization.json.jsonPrimitive
1010

1111
/**
12-
* Builds a restriction string based on provided [SecuredAPIKeyRestrictions].
12+
* Builds a restriction string based on provided [SecuredApiKeyRestrictions].
1313
*/
14-
internal fun SearchClient.buildRestrictionString(restriction: SecuredAPIKeyRestrictions): String {
14+
internal fun SearchClient.buildRestrictionString(restriction: SecuredApiKeyRestrictions): String {
1515
return Parameters.build {
1616
restriction.searchParams?.let { searchParams ->
1717
val json = options.json.encodeToJsonElement(SearchParamsObject.serializer(), searchParams).jsonObject

clients/algoliasearch-client-kotlin/client/src/commonTest/kotlin/com/algolia/client/TestSecureApiKey.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.algolia.client
22

33
import com.algolia.client.api.SearchClient
4-
import com.algolia.client.extensions.SecuredAPIKeyRestrictions
4+
import com.algolia.client.extensions.SecuredApiKeyRestrictions
55
import com.algolia.client.extensions.generateSecuredApiKey
66
import com.algolia.client.extensions.securedApiKeyRemainingValidity
77
import com.algolia.client.model.search.SearchParamsObject
@@ -14,14 +14,14 @@ class TestSecureApiKey {
1414

1515
@Test
1616
fun securedApiKey() {
17-
val parentAPIKey = "SearchOnlyApiKeyKeptPrivate"
18-
val restriction = SecuredAPIKeyRestrictions(
17+
val parentApiKey = "SearchOnlyApiKeyKeptPrivate"
18+
val restriction = SecuredApiKeyRestrictions(
1919
query = SearchParamsObject(filters = "_tags:user_42"),
2020
validUntil = Clock.System.now() + 2.days,
2121
)
2222

2323
val client = SearchClient("appId", "apiKey")
24-
val securedApiKey = client.generateSecuredApiKey(parentAPIKey, restriction)
24+
val securedApiKey = client.generateSecuredApiKey(parentApiKey, restriction)
2525
val validity = securedApiKeyRemainingValidity(securedApiKey)
2626
assertTrue { validity > 1.days }
2727
}

clients/algoliasearch-client-python/algoliasearch/http/serializer.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from json import dumps
22
from typing import Any, Dict
3+
from urllib.parse import urlencode
34

45
PRIMITIVE_TYPES = (float, bool, bytes, str, int)
56

@@ -12,21 +13,28 @@ class QueryParametersSerializer:
1213
query_parameters: Dict[str, Any] = {}
1314

1415
def parse(self, value) -> Any:
15-
if isinstance(value, dict):
16-
return dumps(value)
17-
elif isinstance(value, list):
16+
if isinstance(value, list):
1817
return ",".join([self.parse(item) for item in value])
18+
elif isinstance(value, dict):
19+
return dumps(value)
1920
elif isinstance(value, bool):
2021
return "true" if value else "false"
2122
else:
2223
return str(value)
2324

25+
def encoded(self) -> str:
26+
return urlencode(dict(sorted(self.query_parameters.items(), key=lambda val: val[0]))).replace("+", "%20")
27+
2428
def __init__(self, query_parameters: Dict[str, Any]) -> None:
2529
self.query_parameters = {}
2630
if query_parameters is None:
2731
return
2832
for key, value in query_parameters.items():
29-
self.query_parameters[key] = self.parse(value)
33+
if isinstance(value, dict):
34+
for dkey, dvalue in value.items():
35+
self.query_parameters[dkey] = self.parse(dvalue)
36+
else:
37+
self.query_parameters[key] = self.parse(value)
3038

3139

3240
def bodySerializer(obj: Any) -> dict:

clients/algoliasearch-client-swift/Sources/Search/Extra/SearchClientExtension.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -517,18 +517,18 @@ public extension SearchClient {
517517
/// - returns: String?
518518
func generateSecuredApiKey(
519519
parentApiKey: String,
520-
with restriction: SecuredAPIKeyRestrictions = SecuredAPIKeyRestrictions()
520+
with restriction: SecuredApiKeyRestrictions = SecuredApiKeyRestrictions()
521521
) throws -> String? {
522522
let queryParams = try restriction.toURLEncodedString()
523523
let hash = queryParams.hmac256(withKey: parentApiKey)
524524
return "\(hash)\(queryParams)".data(using: .utf8)?.base64EncodedString()
525525
}
526526

527527
/// Get the remaining validity of a secured API key
528-
/// - parameter securedAPIKey: The secured API key
528+
/// - parameter securedApiKey: The secured API key
529529
/// - returns: TimeInterval?
530-
func getSecuredApiKeyRemainingValidity(for securedAPIKey: String) -> TimeInterval? {
531-
guard let rawDecodedAPIKey = String(data: Data(base64Encoded: securedAPIKey) ?? Data(), encoding: .utf8),
530+
func getSecuredApiKeyRemainingValidity(for securedApiKey: String) -> TimeInterval? {
531+
guard let rawDecodedAPIKey = String(data: Data(base64Encoded: securedApiKey) ?? Data(), encoding: .utf8),
532532
!rawDecodedAPIKey.isEmpty else {
533533
return nil
534534
}

clients/algoliasearch-client-swift/Sources/Search/Extra/SecuredApiKeyRestrictionExtension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#endif
44
import Foundation
55

6-
public extension SecuredAPIKeyRestrictions {
6+
public extension SecuredApiKeyRestrictions {
77
func toURLEncodedString() throws -> String {
88
var queryDictionary: [String: Any] = [:]
99

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,18 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
9393
}
9494
stepOut.put("stepTemplate", "tests/client/method.mustache");
9595
stepOut.put("isMethod", true); // TODO: remove once dart and kotlin are converted
96+
stepOut.put("isHelper", (boolean) ope.vendorExtensions.getOrDefault("x-helper", false));
97+
stepOut.put("hasOperationParams", ope.hasParams);
9698
}
9799

98100
stepOut.put("object", step.object);
99101
stepOut.put("path", step.path);
100102

101-
Map<String, Object> requestOptions = new HashMap<>();
102-
paramsType.enhanceParameters(step.requestOptions, requestOptions);
103-
stepOut.put("requestOptions", requestOptions);
103+
if (step.requestOptions != null) {
104+
Map<String, Object> requestOptions = new HashMap<>();
105+
paramsType.enhanceParameters(step.requestOptions, requestOptions);
106+
stepOut.put("requestOptions", requestOptions);
107+
}
104108

105109
if (step.path != null && CUSTOM_METHODS.contains(step.path)) {
106110
stepOut.put("isCustom", true);
@@ -148,10 +152,11 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
148152
stepOut.put("expectedError", step.expected.error.replace(step.path, Helpers.toPascalCase(step.path)));
149153
}
150154
} else if (step.expected.match != null) {
151-
if (step.expected.match instanceof Map) {
152-
Map<String, Object> match = new HashMap<>();
153-
paramsType.enhanceParameters((Map<String, Object>) step.expected.match, match);
154-
stepOut.put("match", match);
155+
Map<String, Object> matchMap = new HashMap<>();
156+
if (step.expected.match instanceof Map match) {
157+
paramsType.enhanceParameters(match, matchMap);
158+
stepOut.put("match", matchMap);
159+
stepOut.put("matchIsObject", true);
155160
} else {
156161
stepOut.put("match", step.expected.match);
157162
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ private String languageCased() {
7070
}
7171

7272
private String injectVariables(String json) {
73-
long threeDays = 3 * 24 * 60 * 60 * 1000;
73+
long day = 24 * 60 * 60 * 1000;
7474
json =
7575
json
7676
.replace("${{languageCased}}", languageCased())
7777
.replace("${{clientPascalCase}}", Helpers.capitalize(Helpers.camelize(client)))
78-
.replace("\"${{nowRounded}}\"", String.valueOf(Math.round(System.currentTimeMillis() / threeDays) * threeDays));
78+
.replace("\"${{nowRounded}}\"", String.valueOf(Math.round(System.currentTimeMillis() / (3 * day)) * 3 * day));
7979

8080
if (!language.equals("javascript") && !"true".equals(System.getenv("CI"))) {
8181
// hack for docker on mac, the `network=host` does not work so we need to use

playground/csharp/Playground/Playgrounds/Search.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ await PlaygroundHelper.Start("Deleting API Key", async () =>
201201

202202
Console.WriteLine("--- Generate Secured API Keys `GenerateSecuredApiKeys` ---");
203203
var generateSecuredApiKeys = _client.GenerateSecuredApiKey(_configuration.SearchApiKey,
204-
new SecuredAPIKeyRestrictions
204+
new SecuredApiKeyRestrictions
205205
{
206206
RestrictIndices = [DefaultIndex],
207207
});

playground/swift/playground/playground/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ guard let apiKey = Bundle.main.infoDictionary?["ALGOLIA_ADMIN_KEY"] as? String e
1818
}
1919

2020
guard applicationID != "" && apiKey != "" else {
21-
fatalError("AppID and APIKey must be filled in your Info.plist file")
21+
fatalError("AppID and ApiKey must be filled in your Info.plist file")
2222
}
2323

2424
struct Contact: Codable {

specs/search/helpers/generateSecuredApiKey.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ method:
3131
description: Restrictions to add to the API key.
3232
required: true
3333
schema:
34-
$ref: '#/securedAPIKeyRestrictions'
34+
$ref: '#/securedApiKeyRestrictions'
3535
responses:
3636
'200':
3737
description: OK
@@ -42,7 +42,7 @@ method:
4242
'400':
4343
$ref: '../../common/responses/IndexNotFound.yml'
4444

45-
securedAPIKeyRestrictions:
45+
securedApiKeyRestrictions:
4646
type: object
4747
additionalProperties: false
4848
properties:

templates/csharp/tests/client/suite.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ public void Dispose()
5656
Assert.Equal("{{{match}}}", result.Host);
5757
{{/testHost}}
5858
{{#testResponse}}
59+
{{#matchIsObject}}
5960
JsonAssert.EqualOverrideDefault("{{#lambda.escapeQuotes}}{{{match.parameters}}}{{/lambda.escapeQuotes}}", JsonSerializer.Serialize(res, JsonConfig.Options), new JsonDiffConfig(false));
61+
{{/matchIsObject}}
62+
{{^matchIsObject}}
63+
Assert.Equal("{{{match}}}", res);
64+
{{/matchIsObject}}
6065
{{/testResponse}}
6166
{{/match}}
6267
{{/isError}}

templates/dart/tests/client/method.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ try {
66
);
77
{{#match}}
88
{{#testResponse}}
9+
{{#matchIsObject}}
910
expectBody(res, """{{{match.parameters}}}""");
11+
{{/matchIsObject}}
12+
{{^matchIsObject}}
13+
expect(res, """{{match}}""");
14+
{{/matchIsObject}}
1015
{{/testResponse}}
1116
{{/match}}
1217
} on InterceptionException catch (_) {

templates/go/api.mustache

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"crypto/sha256"
2020
"encoding/base64"
2121
"encoding/hex"
22+
"sort"
2223
{{/isSearchClient}}
2324

2425
"github.com/algolia/algoliasearch-client-go/v4/algolia/utils"
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
{{^useEchoRequester}}res, err := {{/useEchoRequester}}{{#useEchoRequester}}_, err = {{/useEchoRequester}}client.{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}(client.NewApi{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}Request(
1+
{{^useEchoRequester}}res, err := {{/useEchoRequester}}{{#useEchoRequester}}_, err = {{/useEchoRequester}}client.{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}({{^isHelper}}client.NewApi{{#lambda.titlecase}}{{path}}{{/lambda.titlecase}}Request({{/isHelper}}
22
{{#parametersWithDataType}}{{#required}}{{> tests/generateParams}},{{/required}}{{/parametersWithDataType}}
3-
){{#parametersWithDataType}}{{^required}}.With{{#lambda.pascalcase}}{{{key}}}{{/lambda.pascalcase}}({{> tests/generateParams}}){{/required}}{{/parametersWithDataType}}{{#requestOptions}},
3+
{{^isHelper}}){{#parametersWithDataType}}{{^required}}.With{{#lambda.pascalcase}}{{{key}}}{{/lambda.pascalcase}}({{> tests/generateParams}}){{/required}}{{/parametersWithDataType}}{{/isHelper}}{{#isHelper}}{{#parametersWithDataType}}{{^required}}{{> tests/generateParams}},{{/required}}{{/parametersWithDataType}}{{/isHelper}}{{#requestOptions}}{{#hasOperationParams}},{{/hasOperationParams}}
44
{{#queryParameters.parametersWithDataType}}{{clientPrefix}}.QueryParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/queryParameters.parametersWithDataType}}{{#headers.parametersWithDataType}}{{clientPrefix}}.HeaderParamOption("{{{key}}}", {{> tests/generateInnerParams}}),{{/headers.parametersWithDataType}}
55
{{/requestOptions}})

templates/go/tests/client/suite.mustache

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,19 +58,24 @@ func Test{{#lambda.titlecase}}{{clientPrefix}}{{testType}}{{/lambda.titlecase}}{
5858
require.NoError(t, err)
5959
{{#match}}
6060
{{#testUserAgent}}
61-
require.Regexp(t, regexp.MustCompile(`{{{match}}}`), echo.Header.Get("User-Agent"))
61+
require.Regexp(t, regexp.MustCompile(`{{{match}}}`), echo.Header.Get("User-Agent"))
6262
{{/testUserAgent}}
6363
{{#testTimeouts}}
64-
require.Equal(t, int64({{{match.parametersWithDataTypeMap.connectTimeout.value}}}), echo.ConnectTimeout.Milliseconds())
65-
require.Equal(t, int64({{{match.parametersWithDataTypeMap.responseTimeout.value}}}), echo.Timeout.Milliseconds())
64+
require.Equal(t, int64({{{match.parametersWithDataTypeMap.connectTimeout.value}}}), echo.ConnectTimeout.Milliseconds())
65+
require.Equal(t, int64({{{match.parametersWithDataTypeMap.responseTimeout.value}}}), echo.Timeout.Milliseconds())
6666
{{/testTimeouts}}
6767
{{#testHost}}
68-
require.Equal(t, "{{{match}}}", echo.Host)
68+
require.Equal(t, "{{{match}}}", echo.Host)
6969
{{/testHost}}
7070
{{#testResponse}}
71-
rawBody, err := json.Marshal(res)
72-
require.NoError(t, err)
73-
require.JSONEq(t, `{{{match.parameters}}}`, string(rawBody))
71+
{{#matchIsObject}}
72+
rawBody, err := json.Marshal(res)
73+
require.NoError(t, err)
74+
require.JSONEq(t, `{{{match.parameters}}}`, string(rawBody))
75+
{{/matchIsObject}}
76+
{{^matchIsObject}}
77+
require.Equal(t, `{{{match}}}`, res)
78+
{{/matchIsObject}}
7479
{{/testResponse}}
7580
{{/match}}
7681
{{/isError}}

templates/java/tests/client/suite.mustache

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,12 @@ class {{client}}ClientTests {
7777
assertEquals("{{{match}}}", result.host);
7878
{{/testHost}}
7979
{{#testResponse}}
80+
{{#matchIsObject}}
8081
assertDoesNotThrow(() -> JSONAssert.assertEquals("{{#lambda.escapeQuotes}}{{{match.parameters}}}{{/lambda.escapeQuotes}}", json.writeValueAsString(res), JSONCompareMode.STRICT));
82+
{{/matchIsObject}}
83+
{{^matchIsObject}}
84+
assertEquals("{{{match}}}", res);
85+
{{/matchIsObject}}
8186
{{/testResponse}}
8287
{{/match}}
8388
{{/isError}}

templates/javascript/clients/client/api/helpers.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,4 +382,4 @@ async replaceAllObjects(
382382
});
383383

384384
return { copyOperationResponse, batchResponses, moveOperationResponse };
385-
},
385+
},

templates/javascript/clients/client/model/clientMethodProps.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export type GenerateSecuredApiKeyOptions = {
111111
/**
112112
* A set of properties defining the restrictions of the secured API key.
113113
*/
114-
restrictions?: SecuredAPIKeyRestrictions;
114+
restrictions?: SecuredApiKeyRestrictions;
115115
}
116116

117117
export type GetSecuredApiKeyRemainingValidityOptions = {

0 commit comments

Comments
 (0)