Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/com/sun/jndi/ldap/LdapTimeoutTest.java
38855 views
1
/*
2
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @library /lib/testlibrary
27
* lib/
28
* @run testng/othervm LdapTimeoutTest
29
* @bug 7094377 8000487 6176036 7056489 8151678
30
* @summary Timeout tests for ldap
31
*/
32
33
import org.testng.Assert;
34
import org.testng.annotations.BeforeTest;
35
import org.testng.annotations.Test;
36
37
import javax.naming.Context;
38
import javax.naming.NamingException;
39
import javax.naming.directory.InitialDirContext;
40
import javax.naming.directory.SearchControls;
41
import java.io.IOException;
42
import java.io.OutputStream;
43
import java.net.Socket;
44
import java.util.ArrayList;
45
import java.util.Hashtable;
46
import java.util.List;
47
import java.util.Objects;
48
import java.util.concurrent.Callable;
49
import java.util.concurrent.CompletableFuture;
50
import java.util.concurrent.ExecutionException;
51
import java.util.concurrent.ExecutorService;
52
import java.util.concurrent.Executors;
53
import java.util.concurrent.Future;
54
import java.util.concurrent.FutureTask;
55
import java.util.concurrent.SynchronousQueue;
56
import java.util.concurrent.TimeUnit;
57
import java.util.concurrent.TimeoutException;
58
59
import static java.lang.String.format;
60
import static java.util.concurrent.TimeUnit.MILLISECONDS;
61
import static java.util.concurrent.TimeUnit.NANOSECONDS;
62
import static jdk.testlibrary.Utils.adjustTimeout;
63
import static org.testng.Assert.assertTrue;
64
import static org.testng.Assert.expectThrows;
65
66
public class LdapTimeoutTest {
67
68
// ------ configure test timeouts here ------
69
70
/*
71
* Practical representation of an infinite timeout.
72
*/
73
private static final long INFINITY_MILLIS = adjustTimeout(20_000);
74
/*
75
* The acceptable variation in timeout measurements.
76
*/
77
private static final long TOLERANCE = adjustTimeout( 3_500);
78
79
private static final long CONNECT_MILLIS = adjustTimeout( 3_000);
80
private static final long READ_MILLIS = adjustTimeout(10_000);
81
82
static {
83
// a series of checks to make sure this timeouts configuration is
84
// consistent and the timeouts do not overlap
85
86
assert (TOLERANCE >= 0);
87
// context creation
88
assert (2 * CONNECT_MILLIS + TOLERANCE < READ_MILLIS);
89
// context creation immediately followed by search
90
assert (2 * CONNECT_MILLIS + READ_MILLIS + TOLERANCE < INFINITY_MILLIS);
91
}
92
93
@BeforeTest
94
public void beforeTest() {
95
startAuxiliaryDiagnosticOutput();
96
}
97
98
/*
99
* These are timeout tests and they are run in parallel to reduce the total
100
* amount of run time.
101
*
102
* Currently it doesn't seem possible to instruct JTREG to run TestNG test
103
* methods in parallel. That said, this JTREG test is still
104
* a "TestNG-flavored" test for the sake of having org.testng.Assert
105
* capability.
106
*/
107
@Test
108
public void test() throws Exception {
109
List<Future<?>> futures = new ArrayList<>();
110
ExecutorService executorService = Executors.newCachedThreadPool();
111
try {
112
futures.add(executorService.submit(() -> { test1(); return null; }));
113
futures.add(executorService.submit(() -> { test2(); return null; }));
114
futures.add(executorService.submit(() -> { test3(); return null; }));
115
futures.add(executorService.submit(() -> { test4(); return null; }));
116
futures.add(executorService.submit(() -> { test5(); return null; }));
117
futures.add(executorService.submit(() -> { test6(); return null; }));
118
futures.add(executorService.submit(() -> { test7(); return null; }));
119
} finally {
120
executorService.shutdown();
121
}
122
int failedCount = 0;
123
for (Future f : futures) {
124
try {
125
f.get();
126
} catch (ExecutionException e) {
127
failedCount++;
128
e.getCause().printStackTrace(System.out);
129
}
130
}
131
if (failedCount > 0)
132
throw new RuntimeException(failedCount + " (sub)tests failed");
133
}
134
135
static void test1() throws Exception {
136
Hashtable<Object, Object> env = new Hashtable<>();
137
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
138
// Here and in the other tests it's important to close the server as
139
// calling `thread.interrupt` from assertion may not be enough
140
// (depending on where the blocking call has stuck)
141
try (TestServer server = new NotBindableServer()) {
142
env.put(Context.PROVIDER_URL, urlTo(server));
143
server.start();
144
// Here and in the other tests joining done purely to reduce timing
145
// jitter. Commenting out or removing that should not make the test
146
// incorrect. (ServerSocket can accept connection as soon as it is
147
// bound, not need to call `accept` before that.)
148
server.starting().join();
149
assertIncompletion(INFINITY_MILLIS, () -> new InitialDirContext(env));
150
}
151
}
152
153
static void test2() throws Exception {
154
Hashtable<Object, Object> env = new Hashtable<>();
155
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
156
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
157
try (TestServer server = new BindableButNotReadableServer()) {
158
env.put(Context.PROVIDER_URL, urlTo(server));
159
server.start();
160
server.starting().join();
161
InitialDirContext ctx = new InitialDirContext(env);
162
SearchControls scl = new SearchControls();
163
scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
164
assertIncompletion(INFINITY_MILLIS,
165
() -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
166
}
167
}
168
169
static void test3() throws Exception {
170
Hashtable<Object, Object> env = new Hashtable<>();
171
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
172
try (TestServer server = new BindableButNotReadableServer()) {
173
env.put(Context.PROVIDER_URL, urlTo(server));
174
server.start();
175
server.starting().join();
176
InitialDirContext ctx = new InitialDirContext(env);
177
SearchControls scl = new SearchControls();
178
scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
179
assertIncompletion(INFINITY_MILLIS,
180
() -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
181
}
182
}
183
184
static void test4() throws Exception {
185
Hashtable<Object, Object> env = new Hashtable<>();
186
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
187
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
188
env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
189
try (TestServer server = new NotBindableServer()) {
190
env.put(Context.PROVIDER_URL, urlTo(server));
191
server.start();
192
server.starting().join();
193
Assert.ThrowingRunnable completion =
194
() -> assertCompletion(CONNECT_MILLIS,
195
2 * CONNECT_MILLIS + TOLERANCE,
196
() -> new InitialDirContext(env));
197
NamingException e = expectThrows(NamingException.class, completion);
198
String msg = e.getMessage();
199
assertTrue(msg != null && msg.contains("timeout")
200
&& msg.contains(String.valueOf(CONNECT_MILLIS)),
201
msg);
202
}
203
}
204
205
static void test5() throws Exception {
206
Hashtable<Object, Object> env = new Hashtable<>();
207
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
208
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
209
env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
210
try (TestServer server = new BindableButNotReadableServer()) {
211
env.put(Context.PROVIDER_URL, urlTo(server));
212
server.start();
213
server.starting().join();
214
InitialDirContext ctx = new InitialDirContext(env);
215
SearchControls scl = new SearchControls();
216
scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
217
Assert.ThrowingRunnable completion =
218
() -> assertCompletion(READ_MILLIS,
219
READ_MILLIS + TOLERANCE,
220
() -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
221
NamingException e = expectThrows(NamingException.class, completion);
222
String msg = e.getMessage();
223
assertTrue(msg != null && msg.contains("timeout")
224
&& msg.contains(String.valueOf(READ_MILLIS)),
225
msg);
226
}
227
}
228
229
static void test6() throws Exception {
230
Hashtable<Object, Object> env = new Hashtable<>();
231
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
232
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
233
env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
234
try (TestServer server = new NotBindableServer()) {
235
env.put(Context.PROVIDER_URL, urlTo(server));
236
server.start();
237
server.starting().join();
238
Assert.ThrowingRunnable completion =
239
() -> assertCompletion(CONNECT_MILLIS,
240
2 * CONNECT_MILLIS + TOLERANCE,
241
() -> new InitialDirContext(env));
242
NamingException e = expectThrows(NamingException.class, completion);
243
String msg = e.getMessage();
244
assertTrue(msg != null && msg.contains("timeout")
245
&& msg.contains(String.valueOf(CONNECT_MILLIS)),
246
msg);
247
}
248
}
249
250
static void test7() throws Exception {
251
// 8000487: Java JNDI connection library on ldap conn is
252
// not honoring configured timeout
253
Hashtable<Object, Object> env = new Hashtable<>();
254
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
255
env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
256
env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
257
env.put(Context.SECURITY_AUTHENTICATION, "simple");
258
env.put(Context.SECURITY_PRINCIPAL, "user");
259
env.put(Context.SECURITY_CREDENTIALS, "password");
260
try (TestServer server = new NotBindableServer()) {
261
env.put(Context.PROVIDER_URL, urlTo(server));
262
server.start();
263
server.starting().join();
264
Assert.ThrowingRunnable completion =
265
() -> assertCompletion(CONNECT_MILLIS,
266
2 * CONNECT_MILLIS + TOLERANCE,
267
() -> new InitialDirContext(env));
268
NamingException e = expectThrows(NamingException.class, completion);
269
String msg = e.getMessage();
270
assertTrue(msg != null && msg.contains("timeout")
271
&& msg.contains(String.valueOf(CONNECT_MILLIS)),
272
msg);
273
}
274
}
275
276
// ------ test stub servers ------
277
278
static class TestServer extends BaseLdapServer {
279
280
private final CompletableFuture<Void> starting = new CompletableFuture<>();
281
282
TestServer() throws IOException { }
283
284
@Override
285
protected void beforeAcceptingConnections() {
286
CompletableFuture.supplyAsync(() -> null)
287
.whenComplete((input, exception) -> {
288
starting.complete(null);
289
});
290
}
291
292
public CompletableFuture<Void> starting() {
293
return starting.thenApply((x) -> x);
294
}
295
}
296
297
static class BindableButNotReadableServer extends TestServer {
298
299
BindableButNotReadableServer() throws IOException { }
300
301
private static final byte[] bindResponse = {
302
0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
303
0x01, 0x00, 0x04, 0x00, 0x04, 0x00
304
};
305
306
@Override
307
protected void handleRequest(Socket socket,
308
LdapMessage msg,
309
OutputStream out)
310
throws IOException {
311
switch (msg.getOperation()) {
312
case BIND_REQUEST:
313
out.write(bindResponse);
314
out.flush();
315
default:
316
break;
317
}
318
}
319
}
320
321
static class NotBindableServer extends TestServer {
322
323
NotBindableServer() throws IOException { }
324
325
@Override
326
protected void beforeConnectionHandled(Socket socket) {
327
try {
328
TimeUnit.DAYS.sleep(Integer.MAX_VALUE);
329
} catch (InterruptedException e) {
330
Thread.currentThread().interrupt();
331
}
332
}
333
}
334
335
// ------ timeouts check utilities ------
336
337
/*
338
* Asserts that the specified executable yields a result or an exception
339
* within the specified time frame. Interrupts the executable
340
* unconditionally.
341
*
342
* If the executable yields a result or an exception within the specified
343
* time frame, the result will be returned and the exception will be
344
* rethrown respectively in a transparent fashion as if the executable was
345
* executed directly.
346
*/
347
public static <T> T assertCompletion(long loMillis,
348
long hiMillis,
349
Callable<T> code)
350
throws Throwable {
351
if (loMillis < 0 || hiMillis < 0 || loMillis > hiMillis) {
352
throw new IllegalArgumentException("loMillis=" + loMillis +
353
", hiMillis=" + hiMillis);
354
}
355
Objects.requireNonNull(code);
356
357
// this queue acts both as an exchange point and a barrier
358
SynchronousQueue<Long> startTime = new SynchronousQueue<>();
359
360
Callable<T> wrappedTask = () -> {
361
// by the time this value reaches the "stopwatch" thread it might be
362
// well outdated and that's okay, we will adjust the wait time
363
startTime.put(System.nanoTime());
364
return code.call();
365
};
366
367
FutureTask<T> task = new FutureTask<>(wrappedTask);
368
Thread t = new Thread(task);
369
t.start();
370
371
final long startNanos;
372
try {
373
startNanos = startTime.take(); // (1) wait for the initial time mark
374
} catch (Throwable e) {
375
t.interrupt();
376
throw e;
377
}
378
379
final long waitTime = hiMillis -
380
NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
381
382
try {
383
T r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
384
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
385
if (elapsed < loMillis || elapsed > hiMillis) {
386
throw new RuntimeException(format(
387
"After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
388
}
389
return r;
390
} catch (ExecutionException e) {
391
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
392
if (elapsed < loMillis || elapsed > hiMillis) {
393
throw new RuntimeException(format(
394
"After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
395
}
396
throw e.getCause();
397
} catch (TimeoutException e) {
398
// We trust timed get not to throw TimeoutException prematurely
399
// (i.e. before the wait time elapses)
400
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
401
throw new RuntimeException(format(
402
"After %s ms. (waitTime %s ms.) is incomplete", elapsed, waitTime));
403
} finally {
404
t.interrupt();
405
}
406
}
407
408
/*
409
* Asserts that the specified executable yields no result and no exception
410
* for at least the specified amount of time. Interrupts the executable
411
* unconditionally.
412
*/
413
public static void assertIncompletion(long millis, Callable<?> code)
414
throws Exception
415
{
416
if (millis < 0) {
417
throw new IllegalArgumentException("millis=" + millis);
418
}
419
Objects.requireNonNull(code);
420
421
// this queue acts both as an exchange point and a barrier
422
SynchronousQueue<Long> startTime = new SynchronousQueue<>();
423
424
Callable<?> wrappedTask = () -> {
425
// by the time this value reaches the "stopwatch" thread it might be
426
// well outdated and that's okay, we will adjust the wait time
427
startTime.put(System.nanoTime());
428
return code.call();
429
};
430
431
FutureTask<?> task = new FutureTask<>(wrappedTask);
432
Thread t = new Thread(task);
433
t.start();
434
435
final long startNanos;
436
try {
437
startNanos = startTime.take(); // (1) wait for the initial time mark
438
} catch (Throwable e) {
439
t.interrupt();
440
throw e;
441
}
442
443
final long waitTime = millis -
444
NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
445
446
try {
447
Object r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
448
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
449
if (elapsed < waitTime) {
450
throw new RuntimeException(format(
451
"After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
452
}
453
} catch (ExecutionException e) {
454
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
455
if (elapsed < waitTime) {
456
throw new RuntimeException(format(
457
"After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
458
}
459
} catch (TimeoutException expected) {
460
} finally {
461
t.interrupt();
462
}
463
}
464
465
// ------ miscellaneous utilities ------
466
467
private static String urlTo(TestServer server) {
468
String hostAddress = server.getInetAddress().getHostAddress();
469
String addr;
470
if (hostAddress.contains(":")) { // IPv6
471
addr = '[' + hostAddress + ']';
472
} else { // IPv4
473
addr = hostAddress;
474
}
475
return "ldap://" + addr + ":" + server.getPort();
476
}
477
478
/*
479
* A diagnostic aid that might help with debugging timeout issues. The idea
480
* is to continuously measure accuracy and responsiveness of the system that
481
* runs this test. If the system is overwhelmed (with something else), it
482
* might affect the test run. At the very least we will have traces of that
483
* in the logs.
484
*
485
* This utility does not automatically scale up test timeouts, it simply
486
* gathers information.
487
*/
488
private static void startAuxiliaryDiagnosticOutput() {
489
System.out.printf("Starting diagnostic output (probe)%n");
490
Thread t = new Thread(() -> {
491
for (int i = 0; ; i = ((i % 20) + 1)) {
492
// 500, 1_000, 1_500, ..., 9_500, 10_000, 500, 1_000, ...
493
long expected = i * 500;
494
long start = System.nanoTime();
495
try {
496
MILLISECONDS.sleep(expected);
497
} catch (InterruptedException e) {
498
return;
499
}
500
long stop = System.nanoTime();
501
long actual = NANOSECONDS.toMillis(stop - start);
502
System.out.printf("(probe) expected [ms.]: %s, actual [ms.]: %s%n",
503
expected, actual);
504
505
}
506
}, "probe");
507
t.setDaemon(true);
508
t.start();
509
}
510
}
511
512