1+ package com .iluwatar .threadpool ;
2+
3+ import org .junit .Test ;
4+
5+ import java .util .ArrayList ;
6+ import java .util .List ;
7+ import java .util .Objects ;
8+ import java .util .concurrent .Callable ;
9+ import java .util .concurrent .ExecutionException ;
10+ import java .util .concurrent .ExecutorService ;
11+ import java .util .concurrent .Executors ;
12+ import java .util .concurrent .Future ;
13+ import java .util .function .Function ;
14+ import java .util .stream .Collectors ;
15+
16+ import static org .junit .Assert .assertEquals ;
17+ import static org .junit .Assert .assertNotNull ;
18+
19+ /**
20+ * Date: 12/30/15 - 18:22 PM
21+ *
22+ * @author Jeroen Meulemeester
23+ */
24+ public abstract class TaskTest <T extends Task > {
25+
26+ /**
27+ * The number of tasks used during the concurrency test
28+ */
29+ private static final int TASK_COUNT = 128 * 1024 ;
30+
31+ /**
32+ * The number of threads used during the concurrency test
33+ */
34+ private static final int THREAD_COUNT = 8 ;
35+
36+ /**
37+ * The task factory, used to create new test items
38+ */
39+ private final Function <Integer , T > factory ;
40+
41+ /**
42+ * The expected time needed to run the task 1 single time, in milli seconds
43+ */
44+ private final int expectedExecutionTime ;
45+
46+ /**
47+ * Create a new test instance
48+ *
49+ * @param factory The task factory, used to create new test items
50+ * @param expectedExecutionTime The expected time needed to run the task 1 time, in milli seconds
51+ */
52+ public TaskTest (final Function <Integer , T > factory , final int expectedExecutionTime ) {
53+ this .factory = factory ;
54+ this .expectedExecutionTime = expectedExecutionTime ;
55+ }
56+
57+ /**
58+ * Verify if the generated id is unique for each task, even if the tasks are created in separate
59+ * threads
60+ */
61+ @ Test (timeout = 10000 )
62+ public void testIdGeneration () throws Exception {
63+ final ExecutorService service = Executors .newFixedThreadPool (THREAD_COUNT );
64+
65+ final List <Callable <Integer >> tasks = new ArrayList <>();
66+ for (int i = 0 ; i < TASK_COUNT ; i ++) {
67+ tasks .add (() -> factory .apply (1 ).getId ());
68+ }
69+
70+ final List <Integer > ids = service .invokeAll (tasks )
71+ .stream ()
72+ .map (TaskTest ::get )
73+ .filter (Objects ::nonNull )
74+ .collect (Collectors .toList ());
75+
76+ service .shutdownNow ();
77+
78+ final long uniqueIdCount = ids .stream ()
79+ .distinct ()
80+ .count ();
81+
82+ assertEquals (TASK_COUNT , ids .size ());
83+ assertEquals (TASK_COUNT , uniqueIdCount );
84+
85+ }
86+
87+ /**
88+ * Verify if the time per execution of a task matches the actual time required to execute the task
89+ * a given number of times
90+ */
91+ @ Test
92+ public void testTimeMs () {
93+ for (int i = 0 ; i < 10 ; i ++) {
94+ assertEquals (this .expectedExecutionTime * i , this .factory .apply (i ).getTimeMs ());
95+ }
96+ }
97+
98+ /**
99+ * Verify if the task has some sort of {@link T#toString()}, different from 'null'
100+ */
101+ @ Test
102+ public void testToString () {
103+ assertNotNull (this .factory .apply (0 ).toString ());
104+ }
105+
106+ /**
107+ * Extract the result from a future or returns 'null' when an exception occurred
108+ *
109+ * @param future The future we want the result from
110+ * @param <O> The result type
111+ * @return The result or 'null' when a checked exception occurred
112+ */
113+ private static <O > O get (Future <O > future ) {
114+ try {
115+ return future .get ();
116+ } catch (InterruptedException | ExecutionException e ) {
117+ return null ;
118+ }
119+ }
120+
121+ }
0 commit comments