1
- using Lucene . Net . Util ;
1
+ // From Apache Harmony tests:
2
+ // https://github.com/apache/harmony/blob/trunk/classlib/modules/concurrent/src/test/java/JSR166TestCase.java
3
+ using Lucene . Net . Util ;
2
4
using System ;
5
+ using System . Collections . Generic ;
6
+ using System . Linq ;
7
+ using System . Runtime . CompilerServices ;
8
+ using System . Threading ;
9
+ using System . Threading . Tasks ;
10
+ using ThreadInterruptedException = System . Threading . ThreadInterruptedException ;
11
+
12
+ #nullable enable
3
13
4
14
namespace Lucene . Net . Support . Threading
5
15
{
@@ -20,82 +30,90 @@ namespace Lucene.Net.Support.Threading
20
30
* limitations under the License.
21
31
*/
22
32
23
- /**
24
- * Base class for JSR166 Junit TCK tests. Defines some constants,
25
- * utility methods and classes, as well as a simple framework for
26
- * helping to make sure that assertions failing in generated threads
27
- * cause the associated test that generated them to itself fail (which
28
- * JUnit does not otherwise arrange). The rules for creating such
29
- * tests are:
30
- *
31
- * <ol>
32
- *
33
- * <li> All assertions in code running in generated threads must use
34
- * the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link
35
- * #threadAssertEquals}, or {@link #threadAssertNull}, (not
36
- * <tt>fail</tt>, <tt>assertTrue</tt>, etc.) It is OK (but not
37
- * particularly recommended) for other code to use these forms too.
38
- * Only the most typically used JUnit assertion methods are defined
39
- * this way, but enough to live with.</li>
40
- *
41
- * <li> If you override {@link #setUp} or {@link #tearDown}, make sure
42
- * to invoke <tt>super.setUp</tt> and <tt>super.tearDown</tt> within
43
- * them. These methods are used to clear and check for thread
44
- * assertion failures.</li>
45
- *
46
- * <li>All delays and timeouts must use one of the constants <tt>
47
- * SHORT_DELAY_MS</tt>, <tt> SMALL_DELAY_MS</tt>, <tt> MEDIUM_DELAY_MS</tt>,
48
- * <tt> LONG_DELAY_MS</tt>. The idea here is that a SHORT is always
49
- * discriminable from zero time, and always allows enough time for the
50
- * small amounts of computation (creating a thread, calling a few
51
- * methods, etc) needed to reach a timeout point. Similarly, a SMALL
52
- * is always discriminable as larger than SHORT and smaller than
53
- * MEDIUM. And so on. These constants are set to conservative values,
54
- * but even so, if there is ever any doubt, they can all be increased
55
- * in one spot to rerun tests on slower platforms.</li>
56
- *
57
- * <li> All threads generated must be joined inside each test case
58
- * method (or <tt>fail</tt> to do so) before returning from the
59
- * method. The <tt> joinPool</tt> method can be used to do this when
60
- * using Executors.</li>
61
- *
62
- * </ol>
63
- *
64
- * <p> <b>Other notes</b>
65
- * <ul>
66
- *
67
- * <li> Usually, there is one testcase method per JSR166 method
68
- * covering "normal" operation, and then as many exception-testing
69
- * methods as there are exceptions the method can throw. Sometimes
70
- * there are multiple tests per JSR166 method when the different
71
- * "normal" behaviors differ significantly. And sometimes testcases
72
- * cover multiple methods when they cannot be tested in
73
- * isolation.</li>
74
- *
75
- * <li> The documentation style for testcases is to provide as javadoc
76
- * a simple sentence or two describing the property that the testcase
77
- * method purports to test. The javadocs do not say anything about how
78
- * the property is tested. To find out, read the code.</li>
79
- *
80
- * <li> These tests are "conformance tests", and do not attempt to
81
- * test throughput, latency, scalability or other performance factors
82
- * (see the separate "jtreg" tests for a set intended to check these
83
- * for the most central aspects of functionality.) So, most tests use
84
- * the smallest sensible numbers of threads, collection sizes, etc
85
- * needed to check basic conformance.</li>
86
- *
87
- * <li>The test classes currently do not declare inclusion in
88
- * any particular package to simplify things for people integrating
89
- * them in TCK test suites.</li>
90
- *
91
- * <li> As a convenience, the <tt>main</tt> of this class (JSR166TestCase)
92
- * runs all JSR166 unit tests.</li>
93
- *
94
- * </ul>
95
- */
33
+ /// <summary>
34
+ /// LUCENENET NOTE: This class has been adapted from the Apache Harmony
35
+ /// tests. The original javadoc is included below, and adapted where necessary.
36
+ /// <para />
37
+ ///
38
+ /// Base class for JSR166 Junit TCK tests. Defines some constants,
39
+ /// utility methods and classes, as well as a simple framework for
40
+ /// helping to make sure that assertions failing in generated threads
41
+ /// cause the associated test that generated them to itself fail (which
42
+ /// JUnit does not otherwise arrange). The rules for creating such
43
+ /// tests are:
44
+ ///
45
+ /// <list type="bullets">
46
+ ///
47
+ /// <item> All assertions in code running in generated threads must use
48
+ /// the forms <see cref="threadFail"/>, <see cref="threadAssertTrue"/>,
49
+ /// <see cref="threadAssertEquals(long,long)"/>, <see cref="threadAssertEquals(object,object)"/>
50
+ /// or <see cref="threadAssertNull"/>, (not
51
+ /// <c>fail</c>, <c>assertTrue</c>, etc.) It is OK (but not
52
+ /// particularly recommended) for other code to use these forms too.
53
+ /// Only the most typically used JUnit assertion methods are defined
54
+ /// this way, but enough to live with.</item>
55
+ ///
56
+ /// <item> If you override <see cref="SetUp"/> or <see cref="TearDown"/>, make sure
57
+ /// to invoke <c>base.SetUp</c> and <c>base.TearDown</c> within
58
+ /// them. These methods are used to clear and check for thread
59
+ /// assertion failures.</item>
60
+ ///
61
+ /// <item>All delays and timeouts must use one of the constants
62
+ /// <see cref="SHORT_DELAY_MS"/>, <see cref="SMALL_DELAY_MS"/>, <see cref="MEDIUM_DELAY_MS"/>,
63
+ /// <see cref="LONG_DELAY_MS"/>. The idea here is that a SHORT is always
64
+ /// discriminable from zero time, and always allows enough time for the
65
+ /// small amounts of computation (creating a thread, calling a few
66
+ /// methods, etc) needed to reach a timeout point. Similarly, a SMALL
67
+ /// is always discriminable as larger than SHORT and smaller than
68
+ /// MEDIUM. And so on. These constants are set to conservative values,
69
+ /// but even so, if there is ever any doubt, they can all be increased
70
+ /// in one spot to rerun tests on slower platforms.</item>
71
+ ///
72
+ /// <item> All threads generated must be joined inside each test case
73
+ /// method (or <c>fail</c> to do so) before returning from the
74
+ /// method. The <see cref="joinPool"/> method can be used to do this when
75
+ /// using Executors.</item>
76
+ ///
77
+ /// </list>
78
+ ///
79
+ /// <para />
80
+ /// <b>Other notes</b>
81
+ /// <list type="bullet">
82
+ ///
83
+ /// <item> Usually, there is one testcase method per JSR166 method
84
+ /// covering "normal" operation, and then as many exception-testing
85
+ /// methods as there are exceptions the method can throw. Sometimes
86
+ /// there are multiple tests per JSR166 method when the different
87
+ /// "normal" behaviors differ significantly. And sometimes testcases
88
+ /// cover multiple methods when they cannot be tested in
89
+ /// isolation.</item>
90
+ ///
91
+ /// <item> The documentation style for testcases is to provide as javadoc
92
+ /// a simple sentence or two describing the property that the testcase
93
+ /// method purports to test. The javadocs do not say anything about how
94
+ /// the property is tested. To find out, read the code.</item>
95
+ ///
96
+ /// <item> These tests are "conformance tests", and do not attempt to
97
+ /// test throughput, latency, scalability or other performance factors
98
+ /// (see the separate "jtreg" tests for a set intended to check these
99
+ /// for the most central aspects of functionality.) So, most tests use
100
+ /// the smallest sensible numbers of threads, collection sizes, etc
101
+ /// needed to check basic conformance.</item>
102
+ ///
103
+ /// <item>The test classes currently do not declare inclusion in
104
+ /// any particular package to simplify things for people integrating
105
+ /// them in TCK test suites.</item>
106
+ ///
107
+ /// <!-- LUCENENET: not implemented
108
+ /// <item> As a convenience, the <c>main</c> of this class (JSR166TestCase)
109
+ /// runs all JSR166 unit tests.</item>
110
+ /// -->
111
+ ///
112
+ /// </list>
113
+ /// </summary>
96
114
public class JSR166TestCase : LuceneTestCase
97
115
{
98
- ///**
116
+ // /**
99
117
// * Runs all JSR166 unit tests using junit.textui.TestRunner
100
118
// */
101
119
//public static void main(String[] args)
@@ -255,7 +273,7 @@ public void threadAssertFalse(bool b)
255
273
* If argument not null, set status to indicate current testcase
256
274
* should fail
257
275
*/
258
- public void threadAssertNull ( object x )
276
+ public void threadAssertNull ( object ? x )
259
277
{
260
278
if ( x != null )
261
279
{
@@ -281,7 +299,7 @@ public void threadAssertEquals(long x, long y)
281
299
* If arguments not equal, set status to indicate current testcase
282
300
* should fail
283
301
*/
284
- public void threadAssertEquals ( object x , object y )
302
+ public void threadAssertEquals ( object ? x , object ? y )
285
303
{
286
304
if ( x != y && ( x == null || ! x . equals ( y ) ) )
287
305
{
@@ -326,25 +344,25 @@ public void threadUnexpectedException(Exception ex)
326
344
fail ( "Unexpected exception: " + ex ) ;
327
345
}
328
346
329
- /// **
330
- // * Wait out termination of a thread pool or fail doing so
331
- // */
332
- // public void joinPool(ExecutorService exec)
333
- // {
334
- // try
335
- // {
336
- // exec.shutdown ();
337
- // assertTrue(exec.awaitTermination(LONG_DELAY_MS, TimeUnit.MILLISECONDS ));
338
- // }
339
- // catch (SecurityException ok)
340
- // {
341
- // // Allowed in case test doesn't have privs
342
- // }
343
- // catch (InterruptedException ie )
344
- // {
345
- // fail("Unexpected exception");
346
- // }
347
- // }
347
+ /**
348
+ * Wait out termination of a thread pool or fail doing so
349
+ */
350
+ public void joinPool ( TaskScheduler exec )
351
+ {
352
+ try
353
+ {
354
+ exec . Shutdown ( ) ;
355
+ assertTrue ( exec . AwaitTermination ( TimeSpan . FromMilliseconds ( LONG_DELAY_MS ) ) ) ;
356
+ }
357
+ // catch (SecurityException ok) // LUCENENET - not needed
358
+ // {
359
+ // // Allowed in case test doesn't have privs
360
+ // }
361
+ catch ( ThreadInterruptedException /*ie*/ )
362
+ {
363
+ fail ( "Unexpected exception" ) ;
364
+ }
365
+ }
348
366
349
367
350
368
/**
@@ -363,7 +381,141 @@ public void unexpectedException()
363
381
fail ( "Unexpected exception" ) ;
364
382
}
365
383
384
+ internal void ShortRunnable ( )
385
+ {
386
+ try
387
+ {
388
+ Thread . Sleep ( SHORT_DELAY_MS ) ;
389
+ }
390
+ catch ( Exception e )
391
+ {
392
+ threadUnexpectedException ( e ) ;
393
+ }
394
+ }
395
+
396
+ internal void MediumRunnable ( )
397
+ {
398
+ try
399
+ {
400
+ Thread . Sleep ( MEDIUM_DELAY_MS ) ;
401
+ }
402
+ catch ( Exception e )
403
+ {
404
+ threadUnexpectedException ( e ) ;
405
+ }
406
+ }
366
407
367
408
// LUCENENET TODO: Complete port
368
409
}
410
+
411
+ /// <summary>
412
+ /// LUCENENET specific - fake support for an API that feels like ThreadPoolExecutor.
413
+ /// </summary>
414
+ internal static class JSR166TestCaseExtensions
415
+ {
416
+ /// <summary>
417
+ /// LUCENENET specific - state to keep track of tasks.
418
+ /// <see cref="LimitedConcurrencyLevelTaskScheduler"/> removes tasks from the list when they complete,
419
+ /// so this class is needed to keep track of them.
420
+ /// </summary>
421
+ private class TaskState
422
+ {
423
+ private readonly TaskFactory _factory ;
424
+ private readonly List < Task > _tasks = new ( ) ;
425
+
426
+ public TaskState ( TaskScheduler scheduler )
427
+ {
428
+ _factory = new TaskFactory ( scheduler ) ;
429
+ }
430
+
431
+ public void NewTask ( Action action )
432
+ {
433
+ var task = _factory . StartNew ( action ) ;
434
+ _tasks . Add ( task ) ;
435
+ }
436
+
437
+ public int ActiveCount => _tasks . Count ( t => t . Status == TaskStatus . Running ) ;
438
+
439
+ public int CompletedCount => _tasks . Count ( t => t . IsCompleted ) ;
440
+
441
+ public int TaskCount => _tasks . Count ;
442
+
443
+ public bool AllCompleted => _tasks . All ( t => t . IsCompleted ) ;
444
+
445
+ public bool JoinAll ( TimeSpan timeout ) => Task . WhenAll ( _tasks ) . Wait ( timeout ) ;
446
+ }
447
+
448
+ private static readonly ConditionalWeakTable < TaskScheduler , TaskState > _taskFactories = new ( ) ;
449
+
450
+ public static void Execute ( this TaskScheduler scheduler , Action action )
451
+ {
452
+ if ( ! _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
453
+ {
454
+ state = new TaskState ( scheduler ) ;
455
+ _taskFactories . Add ( scheduler , state ) ;
456
+ }
457
+
458
+ state . NewTask ( action ) ;
459
+ }
460
+
461
+ public static bool AwaitTermination ( this TaskScheduler scheduler , TimeSpan timeout )
462
+ {
463
+ if ( _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
464
+ {
465
+ return state . JoinAll ( timeout ) ;
466
+ }
467
+
468
+ return true ;
469
+ }
470
+
471
+ public static int GetActiveCount ( this TaskScheduler scheduler )
472
+ {
473
+ if ( _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
474
+ {
475
+ // Approximate the number of running threads, which shouldn't exceed the concurrency level
476
+ return Math . Min ( scheduler . MaximumConcurrencyLevel , state . ActiveCount ) ;
477
+ }
478
+
479
+ return 0 ;
480
+ }
481
+
482
+ public static int GetCompletedTaskCount ( this TaskScheduler scheduler )
483
+ {
484
+ if ( _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
485
+ {
486
+ return state . CompletedCount ;
487
+ }
488
+
489
+ return 0 ;
490
+ }
491
+
492
+ public static int GetTaskCount ( this TaskScheduler scheduler )
493
+ {
494
+ if ( _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
495
+ {
496
+ return state . TaskCount ;
497
+ }
498
+
499
+ return 0 ;
500
+ }
501
+
502
+ public static void Shutdown ( this TaskScheduler scheduler )
503
+ {
504
+ if ( scheduler is LimitedConcurrencyLevelTaskScheduler lcl )
505
+ {
506
+ lcl . Shutdown ( ) ;
507
+ }
508
+ }
509
+
510
+ public static bool IsTerminated ( this TaskScheduler scheduler )
511
+ {
512
+ if ( scheduler is LimitedConcurrencyLevelTaskScheduler lcl
513
+ && _taskFactories . TryGetValue ( scheduler , out TaskState ? state ) )
514
+ {
515
+ return lcl . IsShutdown && state . AllCompleted ;
516
+ }
517
+
518
+ return false ; // can't be shut down, so can't be terminated
519
+ }
520
+ }
369
521
}
0 commit comments