doc: Update user guide for changes to event table
[deliverable/tracecompass.git] / org.eclipse.tracecompass.common.core.tests / src / org / eclipse / tracecompass / common / core / tests / collect / BufferedBlockingQueueTest.java
CommitLineData
9d979fda
MK
1/*******************************************************************************
2 * Copyright (c) 2015 Ericsson
3 *
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *
9 * Contributors:
10 * Matthew Khouzam - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.tracecompass.common.core.tests.collect;
14
15import static org.eclipse.tracecompass.common.core.NonNullUtils.nullToEmptyString;
16import static org.junit.Assert.assertEquals;
17import static org.junit.Assert.assertFalse;
18import static org.junit.Assert.assertTrue;
19
47c79d9f
AM
20import java.util.Collection;
21import java.util.Deque;
d6e2666b 22import java.util.HashSet;
9d979fda
MK
23import java.util.LinkedList;
24import java.util.Random;
d6e2666b 25import java.util.Set;
9d979fda
MK
26import java.util.concurrent.Callable;
27import java.util.concurrent.ExecutionException;
28import java.util.concurrent.ExecutorService;
29import java.util.concurrent.Executors;
30import java.util.concurrent.Future;
31import java.util.concurrent.TimeUnit;
32
33import org.eclipse.tracecompass.common.core.NonNullUtils;
34import org.eclipse.tracecompass.common.core.collect.BufferedBlockingQueue;
35import org.junit.Before;
36import org.junit.Rule;
37import org.junit.Test;
38import org.junit.rules.TestRule;
39import org.junit.rules.Timeout;
40
47c79d9f
AM
41import com.google.common.collect.HashMultiset;
42import com.google.common.collect.Iterators;
43
9d979fda
MK
44/**
45 * Test suite for the {@link BufferedBlockingQueue}
46 */
47public class BufferedBlockingQueueTest {
48
49 /** Timeout the tests after 2 minutes */
50 @Rule
51 public TestRule timeoutRule = new Timeout(120000);
52
47c79d9f
AM
53 private static final String testString = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +
54 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" +
55 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
56
9d979fda
MK
57 private BufferedBlockingQueue<Character> charQueue;
58
59 /**
60 * Test setup
61 */
62 @Before
63 public void init() {
64 charQueue = new BufferedBlockingQueue<>(15, 15);
65 }
66
67 /**
68 * Test inserting one element and removing it.
69 */
70 @Test
71 public void testSingleInsertion() {
72 Character element = 'x';
73 charQueue.put(element);
74 charQueue.flushInputBuffer();
75
76 Character out = charQueue.take();
77 assertEquals(element, out);
78 }
79
80 /**
81 * Test insertion of elements that fit into the input buffer.
82 */
83 @Test
84 public void testSimpleInsertion() {
85 String string = "Hello world!";
86 for (char elem : string.toCharArray()) {
87 charQueue.put(elem);
88 }
89 charQueue.flushInputBuffer();
90
91 StringBuilder sb = new StringBuilder();
92 while (!charQueue.isEmpty()) {
93 sb.append(charQueue.take());
94 }
95 assertEquals(string, sb.toString());
96 }
97
98 /**
99 * Test insertion of elements that will require more than one input buffer.
100 */
101 @Test
102 public void testLargeInsertion() {
103 String string = testString.substring(0, 222);
104 for (char elem : string.toCharArray()) {
105 charQueue.put(elem);
106 }
107 charQueue.flushInputBuffer();
108
109 StringBuilder sb = new StringBuilder();
110 while (!charQueue.isEmpty()) {
111 sb.append(charQueue.take());
112 }
113 assertEquals(string, sb.toString());
114 }
115
116 /**
117 * Test the state of the {@link BufferedBlockingQueue#isEmpty()} method at
118 * various moments.
119 */
120 @Test
121 public void testIsEmpty() {
122 BufferedBlockingQueue<String> stringQueue = new BufferedBlockingQueue<>(15, 15);
123 assertTrue(stringQueue.isEmpty());
124
125 stringQueue.put("Hello");
126 assertFalse(stringQueue.isEmpty());
127
128 stringQueue.flushInputBuffer();
129 assertFalse(stringQueue.isEmpty());
130
131 stringQueue.flushInputBuffer();
132 assertFalse(stringQueue.isEmpty());
133
134 stringQueue.flushInputBuffer();
135 stringQueue.take();
136 assertTrue(stringQueue.isEmpty());
137
138 stringQueue.flushInputBuffer();
139 assertTrue(stringQueue.isEmpty());
140 }
141
142 /**
143 * Write random data in and read it, several times.
144 */
145 @Test
146 public void testOddInsertions() {
147 BufferedBlockingQueue<Object> objectQueue = new BufferedBlockingQueue<>(15, 15);
148 LinkedList<Object> expectedValues = new LinkedList<>();
149 Random rnd = new Random();
150 rnd.setSeed(123);
151
152 for (int i = 0; i < 10; i++) {
153 /*
154 * The queue's total size is 225 (15x15). We must make sure to not
155 * fill it up here!
156 */
157 for (int j = 0; j < 50; j++) {
158 Integer testInt = NonNullUtils.checkNotNull(rnd.nextInt());
159 Long testLong = NonNullUtils.checkNotNull(rnd.nextLong());
160 Double testDouble = NonNullUtils.checkNotNull(rnd.nextDouble());
161 Double testGaussian = NonNullUtils.checkNotNull(rnd.nextGaussian());
162
163 expectedValues.add(testInt);
164 expectedValues.add(testLong);
165 expectedValues.add(testDouble);
166 expectedValues.add(testGaussian);
167 objectQueue.put(testInt);
168 objectQueue.put(testLong);
169 objectQueue.put(testDouble);
170 objectQueue.put(testGaussian);
171 }
172 objectQueue.flushInputBuffer();
173
174 while (!expectedValues.isEmpty()) {
175 Object expected = expectedValues.removeFirst();
176 Object actual = objectQueue.take();
177 assertEquals(expected, actual);
178 }
179 }
180 }
181
182 /**
183 * Read with a producer and a consumer
184 *
185 * @throws InterruptedException
186 * The test was interrupted
187 */
188 @Test
189 public void testMultiThread() throws InterruptedException {
190 /* A character not found in the test string */
191 final Character lastElement = '%';
192
193 Thread producer = new Thread() {
194 @Override
195 public void run() {
196 for (char c : testString.toCharArray()) {
197 charQueue.put(c);
198 }
199 charQueue.put(lastElement);
200 charQueue.flushInputBuffer();
201 }
202 };
203 producer.start();
204
205 Thread consumer = new Thread() {
206 @Override
207 public void run() {
208 Character s = charQueue.take();
209 while (!s.equals(lastElement)) {
210 s = charQueue.take();
211 }
212 }
213 };
214 consumer.start();
215
216 consumer.join();
217 producer.join();
218 }
219
47c79d9f
AM
220 /**
221 * Test the contents returned by {@link BufferedBlockingQueue#iterator()}.
222 *
223 * The test is sequential, because the iterator has no guarantee wrt to its
224 * contents when run concurrently.
225 */
226 @Test
227 public void testIteratorContents() {
228 Deque<Character> expected = new LinkedList<>();
229
230 /* Iterator should be empty initially */
231 assertFalse(charQueue.iterator().hasNext());
232
233 /* Insert the first 50 elements */
234 for (int i = 0; i < 50; i++) {
235 char c = testString.charAt(i);
236 charQueue.put(c);
237 expected.addFirst(c);
238 }
239 LinkedList<Character> actual = new LinkedList<>();
240 Iterators.addAll(actual, charQueue.iterator());
241 assertSameElements(expected, actual);
242
243 /*
244 * Insert more elements, flush the input buffer (should not affect the
245 * iteration).
246 */
247 for (int i = 50; i < 60; i++) {
248 char c = testString.charAt(i);
249 charQueue.put(c);
250 charQueue.flushInputBuffer();
251 expected.addFirst(c);
252 }
253 actual = new LinkedList<>();
254 Iterators.addAll(actual, charQueue.iterator());
255 assertSameElements(expected, actual);
256
257 /* Consume the 30 last elements from the queue */
258 for (int i = 0; i < 30; i++) {
259 charQueue.take();
260 expected.removeLast();
261 }
262 actual = new LinkedList<>();
263 Iterators.addAll(actual, charQueue.iterator());
264 assertSameElements(expected, actual);
265
266 /* Now empty the queue */
267 while (!charQueue.isEmpty()) {
268 charQueue.take();
269 expected.removeLast();
270 }
271 assertFalse(charQueue.iterator().hasNext());
272 }
273
274 /**
275 * Utility method to verify that two collections contain the exact same
276 * elements, not necessarily in the same iteration order.
277 *
278 * {@link Collection#equals} requires the iteration order to be the same,
279 * which we do not want here.
280 *
281 * Using a {@link Set} or {@link Collection#containsAll} is not sufficient
282 * either, because those will throw away duplicate elements.
283 */
284 private static <T> void assertSameElements(Collection<T> c1, Collection<T> c2) {
285 assertEquals(HashMultiset.create(c1), HashMultiset.create(c2));
286 }
287
9d979fda 288 /**
d6e2666b
AM
289 * Test iterating on the queue while a producer and a consumer threads are
290 * using it. The iteration should not affect the elements taken by the
291 * consumer.
9d979fda
MK
292 *
293 * @throws InterruptedException
294 * The test was interrupted
295 * @throws ExecutionException
296 * If one of the sub-threads throws an exception, which should
297 * not happen
298 */
299 @Test
d6e2666b
AM
300 public void testConcurrentIteration() throws InterruptedException, ExecutionException {
301 final BufferedBlockingQueue<String> queue = new BufferedBlockingQueue<>(15, 15);
9d979fda 302
d6e2666b 303 ExecutorService pool = Executors.newFixedThreadPool(3);
9d979fda
MK
304
305 final String poisonPill = "That's all folks!";
9d979fda
MK
306
307 Runnable producer = new Runnable() {
308 @Override
309 public void run() {
310 for (int i = 0; i < testString.length(); i++) {
d6e2666b 311 queue.put(nullToEmptyString(String.valueOf(testString.charAt(i))));
9d979fda 312 }
d6e2666b
AM
313 queue.put(poisonPill);
314 queue.flushInputBuffer();
9d979fda
MK
315 }
316 };
317
318 Callable<String> consumer = new Callable<String>() {
319 @Override
320 public String call() {
321 StringBuilder sb = new StringBuilder();
d6e2666b 322 String s = queue.take();
9d979fda
MK
323 while (!s.equals(poisonPill)) {
324 sb.append(s);
d6e2666b 325 s = queue.take();
9d979fda
MK
326 }
327 return sb.toString();
328 }
329 };
330
331 Runnable inquisitor = new Runnable() {
332 @Override
333 public void run() {
d6e2666b
AM
334 for (int i = 0; i < 10; i++) {
335 final Set<String> results = new HashSet<>();
9d979fda
MK
336 /*
337 * The interest of this test is here: we are iterating on
338 * the queue while it is being used.
339 */
d6e2666b
AM
340 for (String input : queue) {
341 results.add(input);
9d979fda
MK
342 }
343 }
9d979fda
MK
344 }
345 };
346
347 pool.submit(producer);
348 pool.submit(inquisitor);
349 Future<String> message = pool.submit(consumer);
9d979fda
MK
350
351 pool.shutdown();
352 pool.awaitTermination(2, TimeUnit.MINUTES);
353
354 assertEquals(testString, message.get());
9d979fda
MK
355 }
356
47c79d9f
AM
357
358}
This page took 0.041932 seconds and 5 git commands to generate.