Skip to content

Commit b2c8b31

Browse files
alexmarkovCommit Queue
authored and
Commit Queue
committed
[tests] Fix flaky standalone/io/http_auth_digest_test
This test has a few independent calls to asyncExpectThrows which uses asyncStart/asyncEnd. However, multiple top-level asyncStart/asyncEnd are not allowed, which causes the following flaky error: ``` Unhandled exception: Exception: Fatal: asyncStart() was called even though we are done with testing.. This is most likely a bug in your test. #0 asyncStart (package:expect/async_helper.dart:53) #1 asyncExpectThrows (package:expect/async_helper.dart:140) #2 testMalformedAuthenticateHeaderWithAuthHandler.<anonymous closure> (file:///b/s/w/ir/cache/builder/sdk/tests/standalone/io/http_auth_digest_test.dart:345) #3 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:951) #4 Future._propagateToListeners (dart:async/future_impl.dart:980) #5 Future._completeWithValue (dart:async/future_impl.dart:723) #6 Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:807) #7 _microtaskLoop (dart:async/schedule_microtask.dart:40) #8 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49) #9 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:128) #10 _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:195) --- Re-run this test: python3 tools/test.py -n vm-aot-ubsan-linux-release-x64 standalone/io/http_auth_digest_test ``` This change attempts to fix this by adding a top-level asyncStart/asyncEnd and also asyncStart/asyncEnd to the server start/shutdown to enclose each test case into asyncStart/asyncEnd and avoid printing "unittest-suite-success" marker before all test cases are finished. TEST=standalone/io/http_auth_digest_test Change-Id: I950e7c6c09f5c2144da874ab3be3cd3a130d3790 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/411086 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent a647f0e commit b2c8b31

File tree

1 file changed

+120
-69
lines changed

1 file changed

+120
-69
lines changed

tests/standalone/io/http_auth_digest_test.dart

Lines changed: 120 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ class Server {
1717
int nonceCount = 0; // Counter of use of current nonce.
1818
var ha1;
1919

20-
static Future<Server> start(String? algorithm, String? qop,
21-
{int? nonceStaleAfter, bool useNextNonce = false}) {
20+
static Future<Server> start(
21+
String? algorithm,
22+
String? qop, {
23+
int? nonceStaleAfter,
24+
bool useNextNonce = false,
25+
}) {
26+
asyncStart();
2227
return new Server()._start(algorithm, qop, nonceStaleAfter, useNextNonce);
2328
}
2429

25-
Future<Server> _start(String? serverAlgorithm, String? serverQop,
26-
int? nonceStaleAfter, bool useNextNonce) {
30+
Future<Server> _start(
31+
String? serverAlgorithm,
32+
String? serverQop,
33+
int? nonceStaleAfter,
34+
bool useNextNonce,
35+
) {
2736
Set ncs = new Set();
2837
// Calculate ha1.
2938
String realm = "test";
@@ -41,8 +50,10 @@ class Server {
4150
if (request.uri.path == "/malformedAuthenticate") {
4251
request.response.statusCode = HttpStatus.unauthorized;
4352
// This authenticate header is malformed because of missing commas
44-
request.response.headers.set(HttpHeaders.wwwAuthenticateHeader,
45-
'Digest realm="$realm" nonce="$nonce" domain="/digest/"');
53+
request.response.headers.set(
54+
HttpHeaders.wwwAuthenticateHeader,
55+
'Digest realm="$realm" nonce="$nonce" domain="/digest/"',
56+
);
4657
request.response.close();
4758
return;
4859
}
@@ -66,11 +77,15 @@ class Server {
6677
var response = request.response;
6778
if (request.headers[HttpHeaders.authorizationHeader] != null) {
6879
Expect.equals(
69-
1, request.headers[HttpHeaders.authorizationHeader]!.length);
80+
1,
81+
request.headers[HttpHeaders.authorizationHeader]!.length,
82+
);
7083
String authorization =
7184
request.headers[HttpHeaders.authorizationHeader]![0];
72-
HeaderValue header =
73-
HeaderValue.parse(authorization, parameterSeparator: ",");
85+
HeaderValue header = HeaderValue.parse(
86+
authorization,
87+
parameterSeparator: ",",
88+
);
7489
if (header.value.toLowerCase() == "basic") {
7590
sendUnauthorizedResponse(response);
7691
} else if (!useNextNonce && nonceCount == nonceStaleAfter) {
@@ -111,16 +126,20 @@ class Server {
111126
digest = md5.convert("$ha1:${nonce}:$ha2".codeUnits);
112127
} else {
113128
digest = md5.convert(
114-
"$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits);
129+
"$ha1:${nonce}:${nc}:${cnonce}:${qop}:$ha2".codeUnits,
130+
);
115131
}
116132
Expect.equals(
117-
hex.encode(digest.bytes), header.parameters["response"]);
133+
hex.encode(digest.bytes),
134+
header.parameters["response"],
135+
);
118136

119137
successCount++;
120138
nonceCount++;
121139

122140
// Add a bogus Authentication-Info for testing.
123-
var info = 'rspauth="77180d1ab3d6c9de084766977790f482", '
141+
var info =
142+
'rspauth="77180d1ab3d6c9de084766977790f482", '
124143
'cnonce="8f971178", '
125144
'nc=000002c74, '
126145
'qop=auth';
@@ -142,6 +161,7 @@ class Server {
142161

143162
void shutdown() {
144163
server.close();
164+
asyncEnd();
145165
}
146166

147167
int get port => server.port;
@@ -152,27 +172,34 @@ void testNoCredentials(String? algorithm, String? qop) {
152172
HttpClient client = new HttpClient();
153173

154174
// Add digest credentials which does not match the path requested.
155-
client.addCredentials(Uri.parse("http://127.0.0.1:${server.port}/xxx"),
156-
"test", new HttpClientDigestCredentials("dart", "password"));
175+
client.addCredentials(
176+
Uri.parse("http://127.0.0.1:${server.port}/xxx"),
177+
"test",
178+
new HttpClientDigestCredentials("dart", "password"),
179+
);
157180

158181
// Add basic credentials for the path requested.
159-
client.addCredentials(Uri.parse("http://127.0.0.1:${server.port}/digest"),
160-
"test", new HttpClientBasicCredentials("dart", "password"));
182+
client.addCredentials(
183+
Uri.parse("http://127.0.0.1:${server.port}/digest"),
184+
"test",
185+
new HttpClientBasicCredentials("dart", "password"),
186+
);
161187

162188
Future makeRequest(Uri url) {
163189
return client
164190
.getUrl(url)
165191
.then((HttpClientRequest request) => request.close())
166192
.then((HttpClientResponse response) {
167-
Expect.equals(HttpStatus.unauthorized, response.statusCode);
168-
return response.fold(null, (x, y) {});
169-
});
193+
Expect.equals(HttpStatus.unauthorized, response.statusCode);
194+
return response.fold(null, (x, y) {});
195+
});
170196
}
171197

172198
var futures = <Future>[];
173199
for (int i = 0; i < 5; i++) {
174200
futures.add(
175-
makeRequest(Uri.parse("http://127.0.0.1:${server.port}/digest")));
201+
makeRequest(Uri.parse("http://127.0.0.1:${server.port}/digest")),
202+
);
176203
}
177204
Future.wait(futures).then((_) {
178205
server.shutdown();
@@ -190,14 +217,17 @@ void testCredentials(String? algorithm, String? qop) {
190217
.getUrl(url)
191218
.then((HttpClientRequest request) => request.close())
192219
.then((HttpClientResponse response) {
193-
Expect.equals(HttpStatus.ok, response.statusCode);
194-
Expect.equals(1, response.headers["Authentication-Info"]?.length);
195-
return response.fold(null, (x, y) {});
196-
});
220+
Expect.equals(HttpStatus.ok, response.statusCode);
221+
Expect.equals(1, response.headers["Authentication-Info"]?.length);
222+
return response.fold(null, (x, y) {});
223+
});
197224
}
198225

199-
client.addCredentials(Uri.parse("http://127.0.0.1:${server.port}/digest"),
200-
"test", new HttpClientDigestCredentials("dart", "password"));
226+
client.addCredentials(
227+
Uri.parse("http://127.0.0.1:${server.port}/digest"),
228+
"test",
229+
new HttpClientDigestCredentials("dart", "password"),
230+
);
201231

202232
var futures = <Future>[];
203233
for (int i = 0; i < 2; i++) {
@@ -223,9 +253,10 @@ void testAuthenticateCallback(String? algorithm, String? qop) {
223253
final completer = new Completer<bool>();
224254
new Timer(const Duration(milliseconds: 10), () {
225255
client.addCredentials(
226-
Uri.parse("http://127.0.0.1:${server.port}/digest"),
227-
"test",
228-
new HttpClientDigestCredentials("dart", "password"));
256+
Uri.parse("http://127.0.0.1:${server.port}/digest"),
257+
"test",
258+
new HttpClientDigestCredentials("dart", "password"),
259+
);
229260
completer.complete(true);
230261
});
231262
return completer.future;
@@ -236,16 +267,17 @@ void testAuthenticateCallback(String? algorithm, String? qop) {
236267
.getUrl(url)
237268
.then((HttpClientRequest request) => request.close())
238269
.then((HttpClientResponse response) {
239-
Expect.equals(HttpStatus.ok, response.statusCode);
240-
Expect.equals(1, response.headers["Authentication-Info"]?.length);
241-
return response.fold(null, (x, y) {});
242-
});
270+
Expect.equals(HttpStatus.ok, response.statusCode);
271+
Expect.equals(1, response.headers["Authentication-Info"]?.length);
272+
return response.fold(null, (x, y) {});
273+
});
243274
}
244275

245276
var futures = <Future>[];
246277
for (int i = 0; i < 5; i++) {
247278
futures.add(
248-
makeRequest(Uri.parse("http://127.0.0.1:${server.port}/digest")));
279+
makeRequest(Uri.parse("http://127.0.0.1:${server.port}/digest")),
280+
);
249281
}
250282
Future.wait(futures).then((_) {
251283
server.shutdown();
@@ -263,10 +295,10 @@ void testStaleNonce() {
263295
.getUrl(url)
264296
.then((HttpClientRequest request) => request.close())
265297
.then((HttpClientResponse response) {
266-
Expect.equals(HttpStatus.ok, response.statusCode);
267-
Expect.equals(1, response.headers["Authentication-Info"]?.length);
268-
return response.fold(null, (x, y) {});
269-
});
298+
Expect.equals(HttpStatus.ok, response.statusCode);
299+
Expect.equals(1, response.headers["Authentication-Info"]?.length);
300+
return response.fold(null, (x, y) {});
301+
});
270302
}
271303

272304
Uri uri = Uri.parse("http://127.0.0.1:${server.port}/digest");
@@ -278,28 +310,29 @@ void testStaleNonce() {
278310
.then((_) => makeRequest(uri))
279311
.then((_) => makeRequest(uri))
280312
.then((_) {
281-
Expect.equals(2, server.unauthCount);
282-
Expect.equals(4, server.successCount);
283-
server.shutdown();
284-
client.close();
285-
});
313+
Expect.equals(2, server.unauthCount);
314+
Expect.equals(4, server.successCount);
315+
server.shutdown();
316+
client.close();
317+
});
286318
});
287319
}
288320

289321
void testNextNonce() {
290-
Server.start("MD5", "auth", nonceStaleAfter: 2, useNextNonce: true)
291-
.then((server) {
322+
Server.start("MD5", "auth", nonceStaleAfter: 2, useNextNonce: true).then((
323+
server,
324+
) {
292325
HttpClient client = new HttpClient();
293326

294327
Future makeRequest(Uri url) {
295328
return client
296329
.getUrl(url)
297330
.then((HttpClientRequest request) => request.close())
298331
.then((HttpClientResponse response) {
299-
Expect.equals(HttpStatus.ok, response.statusCode);
300-
Expect.equals(1, response.headers["Authentication-Info"]?.length);
301-
return response.fold(null, (x, y) {});
302-
});
332+
Expect.equals(HttpStatus.ok, response.statusCode);
333+
Expect.equals(1, response.headers["Authentication-Info"]?.length);
334+
return response.fold(null, (x, y) {});
335+
});
303336
}
304337

305338
Uri uri = Uri.parse("http://127.0.0.1:${server.port}/digest");
@@ -311,19 +344,20 @@ void testNextNonce() {
311344
.then((_) => makeRequest(uri))
312345
.then((_) => makeRequest(uri))
313346
.then((_) {
314-
Expect.equals(1, server.unauthCount);
315-
Expect.equals(4, server.successCount);
316-
server.shutdown();
317-
client.close();
318-
});
347+
Expect.equals(1, server.unauthCount);
348+
Expect.equals(4, server.successCount);
349+
server.shutdown();
350+
client.close();
351+
});
319352
});
320353
}
321354

322355
void testMalformedAuthenticateHeaderNoAuthHandler() {
323356
Server.start('MD5', 'auth').then((server) async {
324357
HttpClient client = new HttpClient();
325358
final uri = Uri.parse(
326-
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate');
359+
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate',
360+
);
327361

328362
// Request should resolve normally if no authentication is configured
329363
await client.getUrl(uri).then((request) => request.close());
@@ -337,13 +371,15 @@ void testMalformedAuthenticateHeaderWithAuthHandler() {
337371
Server.start('MD5', 'auth').then((server) async {
338372
HttpClient client = new HttpClient();
339373
final uri = Uri.parse(
340-
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate');
374+
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate',
375+
);
341376

342377
// Request should throw an exception if the authenticate handler is set
343378
client.authenticate =
344379
(Uri url, String scheme, String? realm) async => false;
345380
await asyncExpectThrows<HttpException>(
346-
client.getUrl(uri).then((request) => request.close()));
381+
client.getUrl(uri).then((request) => request.close()),
382+
);
347383

348384
server.shutdown();
349385
client.close();
@@ -354,13 +390,18 @@ void testMalformedAuthenticateHeaderWithCredentials() {
354390
Server.start('MD5', 'auth').then((server) async {
355391
HttpClient client = new HttpClient();
356392
final uri = Uri.parse(
357-
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate');
393+
'http://${InternetAddress.loopbackIPv4.address}:${server.port}/malformedAuthenticate',
394+
);
358395

359396
// Request should throw an exception if credentials have been added
360397
client.addCredentials(
361-
uri, 'realm', HttpClientDigestCredentials('dart', 'password'));
398+
uri,
399+
'realm',
400+
HttpClientDigestCredentials('dart', 'password'),
401+
);
362402
await asyncExpectThrows<HttpException>(
363-
client.getUrl(uri).then((request) => request.close()));
403+
client.getUrl(uri).then((request) => request.close()),
404+
);
364405

365406
server.shutdown();
366407
client.close();
@@ -396,19 +437,25 @@ void testLocalServerDigest() {
396437
.getUrl(Uri.parse("http://127.0.0.1/digest/test"))
397438
.then((HttpClientRequest request) => request.close())
398439
.then((HttpClientResponse response) {
399-
count++;
400-
if (count % 100 == 0) print(count);
401-
Expect.equals(HttpStatus.ok, response.statusCode);
402-
return response.fold(null, (x, y) {});
403-
});
440+
count++;
441+
if (count % 100 == 0) print(count);
442+
Expect.equals(HttpStatus.ok, response.statusCode);
443+
return response.fold(null, (x, y) {});
444+
});
404445
}
405446

406-
client.addCredentials(Uri.parse("http://127.0.0.1/digest"), "test",
407-
new HttpClientDigestCredentials("dart", "password"));
447+
client.addCredentials(
448+
Uri.parse("http://127.0.0.1/digest"),
449+
"test",
450+
new HttpClientDigestCredentials("dart", "password"),
451+
);
408452

409453
client.authenticate = (url, scheme, realm) {
410-
client.addCredentials(Uri.parse("http://127.0.0.1/digest"), "test",
411-
new HttpClientDigestCredentials("dart", "password"));
454+
client.addCredentials(
455+
Uri.parse("http://127.0.0.1/digest"),
456+
"test",
457+
new HttpClientDigestCredentials("dart", "password"),
458+
);
412459
return new Future.value(true);
413460
};
414461

@@ -420,6 +467,8 @@ void testLocalServerDigest() {
420467
}
421468

422469
main() {
470+
asyncStart();
471+
423472
testNoCredentials(null, null);
424473
testNoCredentials("MD5", null);
425474
testNoCredentials("MD5", "auth");
@@ -439,4 +488,6 @@ main() {
439488
// These teste are not normally run. They can be used for locally
440489
// testing with another web server (e.g. Apache).
441490
//testLocalServerDigest();
491+
492+
asyncEnd();
442493
}

0 commit comments

Comments
 (0)