Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/com/sun/jndi/ldap/LdapTimeoutTest.java
41153 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 /test/lib
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.test.lib.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 (var 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
starting.completeAsync(() -> null);
287
}
288
289
public CompletableFuture<Void> starting() {
290
return starting.copy();
291
}
292
}
293
294
static class BindableButNotReadableServer extends TestServer {
295
296
BindableButNotReadableServer() throws IOException { }
297
298
private static final byte[] bindResponse = {
299
0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
300
0x01, 0x00, 0x04, 0x00, 0x04, 0x00
301
};
302
303
@Override
304
protected void handleRequest(Socket socket,
305
LdapMessage msg,
306
OutputStream out)
307
throws IOException {
308
switch (msg.getOperation()) {
309
case BIND_REQUEST:
310
out.write(bindResponse);
311
out.flush();
312
default:
313
break;
314
}
315
}
316
}
317
318
static class NotBindableServer extends TestServer {
319
320
NotBindableServer() throws IOException { }
321
322
@Override
323
protected void beforeConnectionHandled(Socket socket) {
324
try {
325
TimeUnit.DAYS.sleep(Integer.MAX_VALUE);
326
} catch (InterruptedException e) {
327
Thread.currentThread().interrupt();
328
}
329
}
330
}
331
332
// ------ timeouts check utilities ------
333
334
/*
335
* Asserts that the specified executable yields a result or an exception
336
* within the specified time frame. Interrupts the executable
337
* unconditionally.
338
*
339
* If the executable yields a result or an exception within the specified
340
* time frame, the result will be returned and the exception will be
341
* rethrown respectively in a transparent fashion as if the executable was
342
* executed directly.
343
*/
344
public static <T> T assertCompletion(long loMillis,
345
long hiMillis,
346
Callable<T> code)
347
throws Throwable {
348
if (loMillis < 0 || hiMillis < 0 || loMillis > hiMillis) {
349
throw new IllegalArgumentException("loMillis=" + loMillis +
350
", hiMillis=" + hiMillis);
351
}
352
Objects.requireNonNull(code);
353
354
// this queue acts both as an exchange point and a barrier
355
SynchronousQueue<Long> startTime = new SynchronousQueue<>();
356
357
Callable<T> wrappedTask = () -> {
358
// by the time this value reaches the "stopwatch" thread it might be
359
// well outdated and that's okay, we will adjust the wait time
360
startTime.put(System.nanoTime());
361
return code.call();
362
};
363
364
FutureTask<T> task = new FutureTask<>(wrappedTask);
365
Thread t = new Thread(task);
366
t.start();
367
368
final long startNanos;
369
try {
370
startNanos = startTime.take(); // (1) wait for the initial time mark
371
} catch (Throwable e) {
372
t.interrupt();
373
throw e;
374
}
375
376
final long waitTime = hiMillis -
377
NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
378
379
try {
380
T r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
381
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
382
if (elapsed < loMillis || elapsed > hiMillis) {
383
throw new RuntimeException(format(
384
"After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
385
}
386
return r;
387
} catch (ExecutionException e) {
388
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
389
if (elapsed < loMillis || elapsed > hiMillis) {
390
throw new RuntimeException(format(
391
"After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
392
}
393
throw e.getCause();
394
} catch (TimeoutException e) {
395
// We trust timed get not to throw TimeoutException prematurely
396
// (i.e. before the wait time elapses)
397
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
398
throw new RuntimeException(format(
399
"After %s ms. (waitTime %s ms.) is incomplete", elapsed, waitTime));
400
} finally {
401
t.interrupt();
402
}
403
}
404
405
/*
406
* Asserts that the specified executable yields no result and no exception
407
* for at least the specified amount of time. Interrupts the executable
408
* unconditionally.
409
*/
410
public static void assertIncompletion(long millis, Callable<?> code)
411
throws Exception
412
{
413
if (millis < 0) {
414
throw new IllegalArgumentException("millis=" + millis);
415
}
416
Objects.requireNonNull(code);
417
418
// this queue acts both as an exchange point and a barrier
419
SynchronousQueue<Long> startTime = new SynchronousQueue<>();
420
421
Callable<?> wrappedTask = () -> {
422
// by the time this value reaches the "stopwatch" thread it might be
423
// well outdated and that's okay, we will adjust the wait time
424
startTime.put(System.nanoTime());
425
return code.call();
426
};
427
428
FutureTask<?> task = new FutureTask<>(wrappedTask);
429
Thread t = new Thread(task);
430
t.start();
431
432
final long startNanos;
433
try {
434
startNanos = startTime.take(); // (1) wait for the initial time mark
435
} catch (Throwable e) {
436
t.interrupt();
437
throw e;
438
}
439
440
final long waitTime = millis -
441
NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
442
443
try {
444
Object r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
445
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
446
if (elapsed < waitTime) {
447
throw new RuntimeException(format(
448
"After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
449
}
450
} catch (ExecutionException e) {
451
long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
452
if (elapsed < waitTime) {
453
throw new RuntimeException(format(
454
"After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
455
}
456
} catch (TimeoutException expected) {
457
} finally {
458
t.interrupt();
459
}
460
}
461
462
// ------ miscellaneous utilities ------
463
464
private static String urlTo(TestServer server) {
465
String hostAddress = server.getInetAddress().getHostAddress();
466
String addr;
467
if (hostAddress.contains(":")) { // IPv6
468
addr = '[' + hostAddress + ']';
469
} else { // IPv4
470
addr = hostAddress;
471
}
472
return "ldap://" + addr + ":" + server.getPort();
473
}
474
475
/*
476
* A diagnostic aid that might help with debugging timeout issues. The idea
477
* is to continuously measure accuracy and responsiveness of the system that
478
* runs this test. If the system is overwhelmed (with something else), it
479
* might affect the test run. At the very least we will have traces of that
480
* in the logs.
481
*
482
* This utility does not automatically scale up test timeouts, it simply
483
* gathers information.
484
*/
485
private static void startAuxiliaryDiagnosticOutput() {
486
System.out.printf("Starting diagnostic output (probe)%n");
487
Thread t = new Thread(() -> {
488
for (int i = 0; ; i = ((i % 20) + 1)) {
489
// 500, 1_000, 1_500, ..., 9_500, 10_000, 500, 1_000, ...
490
long expected = i * 500;
491
long start = System.nanoTime();
492
try {
493
MILLISECONDS.sleep(expected);
494
} catch (InterruptedException e) {
495
return;
496
}
497
long stop = System.nanoTime();
498
long actual = NANOSECONDS.toMillis(stop - start);
499
System.out.printf("(probe) expected [ms.]: %s, actual [ms.]: %s%n",
500
expected, actual);
501
502
}
503
}, "probe");
504
t.setDaemon(true);
505
t.start();
506
}
507
}
508
509