Skip to content

Commit e974ffc

Browse files
millotpFluf22
andauthored
chore(cts): assert the retry strategy error (#3405)
Co-authored-by: Thomas Raffray <[email protected]>
1 parent a2ca09b commit e974ffc

File tree

19 files changed

+141
-119
lines changed

19 files changed

+141
-119
lines changed

.github/workflows/check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ jobs:
271271
path: clients-javascript.zip
272272

273273
client_gen:
274-
timeout-minutes: 20
274+
timeout-minutes: 10
275275
runs-on: ubuntu-22.04
276276
needs:
277277
- setup

clients/algoliasearch-client-csharp/algoliasearch/Http/AlgoliaHttpRequester.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public async Task<AlgoliaHttpResponse> SendRequestAsync(Request request, TimeSpa
105105
_logger.LogWarning(ex, "Timeout while sending request");
106106
}
107107

108-
return new AlgoliaHttpResponse { IsTimedOut = true, Error = ex.ToString() };
108+
return new AlgoliaHttpResponse { IsTimedOut = true, Error = ex.Message };
109109
}
110110
catch (HttpRequestException ex)
111111
{

clients/algoliasearch-client-swift/Sources/Core/Networking/HTTP/AlgoliaError.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Foundation
1010
public enum AlgoliaError: Error, LocalizedError {
1111
case requestError(Error)
1212
case httpError(HTTPError)
13-
case noReachableHosts(intermediateErrors: [Error])
13+
case noReachableHosts(intermediateErrors: [Error], exposeIntermediateErrors: Bool)
1414
case missingData
1515
case decodingFailure(Error)
1616
case runtimeError(String)
@@ -24,8 +24,8 @@ public enum AlgoliaError: Error, LocalizedError {
2424
"Request failed: \(error.localizedDescription)"
2525
case let .httpError(error):
2626
"HTTP error: \(error)"
27-
case let .noReachableHosts(errors):
28-
"All hosts are unreachable. Intermediate errors: \(errors.map(\.localizedDescription).joined(separator: ", "))"
27+
case let .noReachableHosts(errors, exposeIntermediateErrors):
28+
"All hosts are unreachable. " + (exposeIntermediateErrors ? "Intermediate errors:\n- \(errors.map(\.localizedDescription).joined(separator: "\n- "))" : "You can use 'exposeIntermediateErrors: true' in the config to investigate.")
2929
case .missingData:
3030
"Missing response data"
3131
case .decodingFailure:

clients/algoliasearch-client-swift/Sources/Core/Networking/RetryStrategy/AlgoliaRetryStrategy.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,16 @@ class AlgoliaRetryStrategy: RetryStrategy {
4040
if !self.hosts.contains(where: { $0.supports(callType) && $0.isUp }) {
4141
self.hosts.resetAll(for: callType)
4242
}
43+
44+
var hostIterator = self.hosts
45+
.sorted { $0.lastUpdated.compare($1.lastUpdated) == .orderedAscending }
46+
.filter { $0.supports(callType) && $0.isUp }
47+
.makeIterator()
4348

4449
return HostIterator { [weak self] in
4550
guard let retryStrategy = self else { return nil }
4651
return retryStrategy.queue.sync {
47-
retryStrategy.hosts
48-
.sorted { $0.lastUpdated.compare($1.lastUpdated) == .orderedAscending }
49-
.first { $0.supports(callType) && $0.isUp }
52+
hostIterator.next()
5053
}
5154
}
5255
}

clients/algoliasearch-client-swift/Sources/Core/Networking/Transporter.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@ open class Transporter {
1515
let configuration: BaseConfiguration
1616
let retryStrategy: RetryStrategy
1717
let requestBuilder: RequestBuilder
18+
let exposeIntermediateErrors: Bool
1819

1920
public init(
2021
configuration: BaseConfiguration,
2122
retryStrategy: RetryStrategy? = nil,
22-
requestBuilder: RequestBuilder? = nil
23+
requestBuilder: RequestBuilder? = nil,
24+
exposeIntermediateErrors: Bool = false
2325
) {
2426
self.configuration = configuration
2527
self.retryStrategy = retryStrategy ?? AlgoliaRetryStrategy(configuration: configuration)
28+
self.exposeIntermediateErrors = exposeIntermediateErrors
2629

2730
guard let requestBuilder else {
2831
let sessionConfiguration: URLSessionConfiguration = .default
@@ -139,6 +142,6 @@ open class Transporter {
139142
}
140143
}
141144

142-
throw AlgoliaError.noReachableHosts(intermediateErrors: intermediateErrors)
145+
throw AlgoliaError.noReachableHosts(intermediateErrors: intermediateErrors, exposeIntermediateErrors: self.exposeIntermediateErrors)
143146
}
144147
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ class Step {
2222
class Expected {
2323

2424
public String type;
25-
public String error;
25+
public Object error;
2626
public Object match;
2727
}

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,17 @@ public void run(Map<String, CodegenModel> models, Map<String, CodegenOperation>
163163
}
164164
if (step.expected.error != null) {
165165
stepOut.put("isError", true);
166-
stepOut.put("expectedError", step.expected.error);
166+
if (step.expected.error instanceof Map errorMap) {
167+
stepOut.put("expectedError", errorMap.getOrDefault(language, "<missing error for " + language + ">"));
168+
} else {
169+
stepOut.put("expectedError", step.expected.error);
170+
}
167171
if (language.equals("go") && step.method != null) {
168172
// hack for go that use PascalCase, but just in the operationID
169-
stepOut.put("expectedError", step.expected.error.replace(step.method, Helpers.toPascalCase(step.method)));
173+
stepOut.put(
174+
"expectedError",
175+
((String) stepOut.get("expectedError")).replace(step.method, Helpers.toPascalCase(step.method))
176+
);
170177
}
171178
} else if (step.expected.match != null) {
172179
Map<String, Object> matchMap = new HashMap<>();

scripts/cli/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,12 @@ ctsCommand
160160
.description('Start the test servers in standalone mode')
161161
.action(async () => {
162162
setVerbose(true);
163-
await startTestServer();
163+
await startTestServer({
164+
benchmark: true,
165+
client: true,
166+
requests: true,
167+
e2e: true,
168+
});
164169
});
165170

166171
program

scripts/cts/runCts.ts

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getTestOutputFolder } from '../config.js';
55
import { createSpinner } from '../spinners.js';
66
import type { Language } from '../types.js';
77

8-
import { startBenchmarkServer, startTestServer } from './testServer';
8+
import { startTestServer } from './testServer';
99
import { printBenchmarkReport } from './testServer/benchmark.js';
1010
import { assertChunkWrapperValid } from './testServer/chunkWrapper.js';
1111
import { assertValidReplaceAllObjects } from './testServer/replaceAllObjects.js';
@@ -142,38 +142,30 @@ export async function runCts(
142142
clients: string[],
143143
suites: Record<CTSType, boolean>,
144144
): Promise<void> {
145-
const useTestServer = suites.client && (clients.includes('search') || clients.includes('all'));
146-
const useBenchmarkServer =
145+
const withBenchmarkServer =
147146
suites.benchmark && (clients.includes('search') || clients.includes('all'));
148-
149-
let closeTestServer: () => Promise<void> = async () => {};
150-
if (useTestServer) {
151-
closeTestServer = await startTestServer();
152-
}
153-
154-
let closeBenchmarkServer: () => Promise<void> = async () => {};
155-
if (useBenchmarkServer) {
156-
closeBenchmarkServer = await startBenchmarkServer();
157-
}
147+
const withClientServer = suites.client && (clients.includes('search') || clients.includes('all'));
148+
const closeTestServer = await startTestServer({
149+
...suites,
150+
benchmark: withBenchmarkServer,
151+
client: withClientServer,
152+
});
158153

159154
for (const lang of languages) {
160155
await runCtsOne(lang, suites);
161156
}
162157

163-
if (useTestServer) {
164-
await closeTestServer();
158+
await closeTestServer();
165159

160+
if (withClientServer) {
166161
const skip = (lang: Language): number => (languages.includes(lang) ? 1 : 0);
167162

168163
assertValidTimeouts(languages.length);
169164
assertChunkWrapperValid(languages.length - skip('dart') - skip('scala'));
170165
assertValidReplaceAllObjects(languages.length - skip('dart') - skip('scala'));
171166
assertValidWaitForApiKey(languages.length - skip('dart') - skip('scala'));
172167
}
173-
174-
if (useBenchmarkServer) {
175-
await closeBenchmarkServer();
176-
168+
if (withBenchmarkServer) {
177169
printBenchmarkReport();
178170
}
179171
}

scripts/cts/testServer/index.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import express from 'express';
44
import type { Express } from 'express';
55

66
import { createSpinner } from '../../spinners';
7+
import type { CTSType } from '../runCts';
78

89
import { benchmarkServer } from './benchmark';
910
import { chunkWrapperServer } from './chunkWrapper';
@@ -13,15 +14,28 @@ import { timeoutServer } from './timeout';
1314
import { timeoutServerBis } from './timeoutBis';
1415
import { waitForApiKeyServer } from './waitForApiKey';
1516

16-
export async function startTestServer(): Promise<() => Promise<void>> {
17-
const servers = await Promise.all([
18-
timeoutServer(),
19-
gzipServer(),
20-
timeoutServerBis(),
21-
replaceAllObjectsServer(),
22-
chunkWrapperServer(),
23-
waitForApiKeyServer(),
24-
]);
17+
export async function startTestServer(
18+
suites: Record<CTSType, boolean>,
19+
): Promise<() => Promise<void>> {
20+
const toStart: Array<Promise<Server>> = [];
21+
if (suites.client) {
22+
toStart.push(
23+
timeoutServer(),
24+
gzipServer(),
25+
timeoutServerBis(),
26+
replaceAllObjectsServer(),
27+
chunkWrapperServer(),
28+
waitForApiKeyServer(),
29+
);
30+
}
31+
if (suites.benchmark) {
32+
toStart.push(benchmarkServer());
33+
}
34+
if (toStart.length === 0) {
35+
return async () => {};
36+
}
37+
38+
const servers = await Promise.all(toStart);
2539

2640
return async () => {
2741
await Promise.all(
@@ -35,16 +49,6 @@ export async function startTestServer(): Promise<() => Promise<void>> {
3549
};
3650
}
3751

38-
export async function startBenchmarkServer(): Promise<() => Promise<void>> {
39-
const server = await benchmarkServer();
40-
41-
return async () => {
42-
await new Promise<void>((resolve) => {
43-
server.close(() => resolve());
44-
});
45-
};
46-
}
47-
4852
export async function setupServer(
4953
name: string,
5054
port: number,

0 commit comments

Comments
 (0)