diff options
author | 2015-09-09 22:15:21 -0700 | |
---|---|---|
committer | 2015-09-09 22:15:21 -0700 | |
commit | 13d05bc8458758ee39cb829098241e89616717ee (patch) | |
tree | 22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/utils/misc/src/test/java/org/onlab/util | |
parent | 6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff) |
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/utils/misc/src/test/java/org/onlab/util')
14 files changed, 1477 insertions, 0 deletions
diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java new file mode 100644 index 00000000..02f0deb1 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/AbstractAccumulatorTest.java @@ -0,0 +1,184 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Ignore; +import org.junit.Test; + +import java.util.List; +import java.util.Timer; +import java.util.stream.IntStream; + +import static org.junit.Assert.*; +import static org.onlab.junit.TestTools.assertAfter; +import static org.onlab.junit.TestTools.delay; + +/** + * Tests the operation of the accumulator. + */ +public class AbstractAccumulatorTest { + + private final Timer timer = new Timer(); + + @Test + public void basics() throws Exception { + TestAccumulator accumulator = new TestAccumulator(); + assertEquals("incorrect timer", timer, accumulator.timer()); + assertEquals("incorrect max events", 5, accumulator.maxItems()); + assertEquals("incorrect max ms", 100, accumulator.maxBatchMillis()); + assertEquals("incorrect idle ms", 70, accumulator.maxIdleMillis()); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void eventTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.add(new TestItem("a")); + accumulator.add(new TestItem("b")); + accumulator.add(new TestItem("c")); + accumulator.add(new TestItem("d")); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("e")); + delay(20); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "abcde", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void timeTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.add(new TestItem("a")); + delay(30); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("b")); + delay(30); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("c")); + delay(30); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("d")); + delay(60); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "abcd", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void idleTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.add(new TestItem("a")); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("b")); + delay(80); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "ab", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void readyIdleTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.ready = false; + accumulator.add(new TestItem("a")); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("b")); + delay(80); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.ready = true; + delay(80); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "ab", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void readyLongTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.ready = false; + delay(120); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.add(new TestItem("a")); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.ready = true; + delay(80); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "a", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void readyMaxTrigger() { + TestAccumulator accumulator = new TestAccumulator(); + accumulator.ready = false; + accumulator.add(new TestItem("a")); + accumulator.add(new TestItem("b")); + accumulator.add(new TestItem("c")); + accumulator.add(new TestItem("d")); + accumulator.add(new TestItem("e")); + accumulator.add(new TestItem("f")); + assertTrue("should not have fired yet", accumulator.batch.isEmpty()); + accumulator.ready = true; + accumulator.add(new TestItem("g")); + delay(5); + assertFalse("should have fired", accumulator.batch.isEmpty()); + assertEquals("incorrect batch", "abcdefg", accumulator.batch); + } + + @Ignore("FIXME: timing sensitive test failing randomly.") + @Test + public void stormTest() { + TestAccumulator accumulator = new TestAccumulator(); + IntStream.range(0, 1000).forEach(i -> accumulator.add(new TestItem("#" + i))); + assertAfter(100, () -> assertEquals("wrong item count", 1000, accumulator.itemCount)); + assertEquals("wrong batch count", 200, accumulator.batchCount); + } + + private class TestItem { + private final String s; + + public TestItem(String s) { + this.s = s; + } + } + + private class TestAccumulator extends AbstractAccumulator<TestItem> { + + String batch = ""; + boolean ready = true; + int batchCount = 0; + int itemCount = 0; + + protected TestAccumulator() { + super(timer, 5, 100, 70); + } + + @Override + public void processItems(List<TestItem> items) { + batchCount++; + itemCount += items.size(); + for (TestItem item : items) { + batch += item.s; + } + } + + @Override + public boolean isReady() { + return ready; + } + } + +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java new file mode 100644 index 00000000..a3baf06c --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BandwidthTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; + +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; +import static org.junit.Assert.assertThat; + +/** + * Unit tests for Bandwidth. + */ +public class BandwidthTest { + + private final Bandwidth small = Bandwidth.kbps(100.0); + private final Bandwidth large = Bandwidth.mbps(1.0); + + /** + * Tests equality of Bandwidth instances. + */ + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(Bandwidth.kbps(1000.0), Bandwidth.kbps(1000.0), Bandwidth.mbps(1.0)) + .addEqualityGroup(Bandwidth.gbps(1.0)) + .testEquals(); + } + + /** + * Tests add operation of two Bandwidths. + */ + @Test + public void testAdd() { + Bandwidth expected = Bandwidth.kbps(1100.0); + + assertThat(small.add(large), is(expected)); + } + + /** + * Tests subtract operation of two Bandwidths. + */ + @Test + public void testSubtract() { + Bandwidth expected = Bandwidth.kbps(900.0); + + assertThat(large.subtract(small), is(expected)); + } + + /** + * Tests if the first object is less than the second object. + */ + @Test + public void testLessThan() { + assertThat(small, is(lessThan(large))); + assertThat(small.isLessThan(large), is(true)); + } + + /** + * Tests if the first object is greater than the second object. + */ + @Test + public void testGreaterThan() { + assertThat(large, is(greaterThan(small))); + assertThat(large.isGreaterThan(small), is(true)); + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java new file mode 100644 index 00000000..2d8b688e --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BlockingBooleanTest.java @@ -0,0 +1,210 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.apache.commons.lang.mutable.MutableBoolean; +import org.junit.Ignore; +import org.junit.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.*; + +/** + * Tests of the BlockingBoolean utility. + */ +public class BlockingBooleanTest { + + private static final int TIMEOUT = 100; //ms + + @Test + public void basics() { + BlockingBoolean b = new BlockingBoolean(false); + assertEquals(false, b.get()); + b.set(true); + assertEquals(true, b.get()); + b.set(true); + assertEquals(true, b.get()); + b.set(false); + assertEquals(false, b.get()); + } + + private void waitChange(boolean value, int numThreads) { + BlockingBoolean b = new BlockingBoolean(!value); + + CountDownLatch latch = new CountDownLatch(numThreads); + ExecutorService exec = Executors.newFixedThreadPool(numThreads); + for (int i = 0; i < numThreads; i++) { + exec.submit(() -> { + try { + b.await(value); + latch.countDown(); + } catch (InterruptedException e) { + fail(); + } + }); + } + b.set(value); + try { + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + exec.shutdown(); + } + + @Test + public void waitTrueChange() { + waitChange(true, 4); + } + + @Test + public void waitFalseChange() { + waitChange(false, 4); + } + + @Test + public void waitSame() { + BlockingBoolean b = new BlockingBoolean(true); + + CountDownLatch latch = new CountDownLatch(1); + ExecutorService exec = Executors.newSingleThreadExecutor(); + exec.submit(() -> { + try { + b.await(true); + latch.countDown(); + } catch (InterruptedException e) { + fail(); + } + }); + try { + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + exec.shutdown(); + } + + @Test + public void someWait() { + BlockingBoolean b = new BlockingBoolean(false); + + int numThreads = 4; + CountDownLatch sameLatch = new CountDownLatch(numThreads / 2); + CountDownLatch waitLatch = new CountDownLatch(numThreads / 2); + + ExecutorService exec = Executors.newFixedThreadPool(numThreads); + for (int i = 0; i < numThreads; i++) { + final boolean value = (i % 2 == 1); + exec.submit(() -> { + try { + b.await(value); + if (value) { + waitLatch.countDown(); + } else { + sameLatch.countDown(); + } + } catch (InterruptedException e) { + fail(); + } + }); + } + try { + assertTrue(sameLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + assertEquals(waitLatch.getCount(), numThreads / 2); + } catch (InterruptedException e) { + fail(); + } + b.set(true); + try { + assertTrue(waitLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + exec.shutdown(); + } + + @Test + public void waitTimeout() { + BlockingBoolean b = new BlockingBoolean(true); + + CountDownLatch latch = new CountDownLatch(1); + ExecutorService exec = Executors.newSingleThreadExecutor(); + exec.submit(() -> { + try { + if (!b.await(false, 1, TimeUnit.NANOSECONDS)) { + latch.countDown(); + } else { + fail(); + } + } catch (InterruptedException e) { + fail(); + } + }); + try { + assertTrue(latch.await(TIMEOUT, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + exec.shutdown(); + + } + + @Test + @Ignore + public void samePerf() { + int iters = 10_000; + + BlockingBoolean b1 = new BlockingBoolean(false); + long t1 = System.nanoTime(); + for (int i = 0; i < iters; i++) { + b1.set(false); + } + long t2 = System.nanoTime(); + MutableBoolean b2 = new MutableBoolean(false); + for (int i = 0; i < iters; i++) { + b2.setValue(false); + } + long t3 = System.nanoTime(); + System.out.println((t2 - t1) + " " + (t3 - t2) + " " + ((t2 - t1) <= (t3 - t2))); + } + + @Test + @Ignore + public void changePerf() { + int iters = 10_000; + + BlockingBoolean b1 = new BlockingBoolean(false); + boolean v = true; + long t1 = System.nanoTime(); + for (int i = 0; i < iters; i++) { + b1.set(v); + v = !v; + } + long t2 = System.nanoTime(); + MutableBoolean b2 = new MutableBoolean(false); + for (int i = 0; i < iters; i++) { + b2.setValue(v); + v = !v; + } + long t3 = System.nanoTime(); + System.out.println((t2 - t1) + " " + (t3 - t2) + " " + ((t2 - t1) <= (t3 - t2))); + } + +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java new file mode 100644 index 00000000..c6132de1 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/BoundedThreadPoolTest.java @@ -0,0 +1,227 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import com.google.common.collect.Lists; +import org.junit.Test; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.*; +import static org.onlab.util.BoundedThreadPool.*; +import static org.onlab.util.Tools.namedThreads; + +/** + * Test of BoundedThreadPool. + */ +public final class BoundedThreadPoolTest { + + @Test + public void simpleJob() { + final Thread myThread = Thread.currentThread(); + final AtomicBoolean sameThread = new AtomicBoolean(true); + final CountDownLatch latch = new CountDownLatch(1); + + BoundedThreadPool exec = newSingleThreadExecutor(namedThreads("test")); + exec.submit(() -> { + sameThread.set(myThread.equals(Thread.currentThread())); + latch.countDown(); + }); + + try { + assertTrue("Job not run", latch.await(100, TimeUnit.MILLISECONDS)); + assertFalse("Runnable used caller thread", sameThread.get()); + } catch (InterruptedException e) { + fail(); + } finally { + exec.shutdown(); + } + + // TODO perhaps move to tearDown + try { + assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + fail(); + } + } + + private List<CountDownLatch> fillExecutor(BoundedThreadPool exec) { + int numThreads = exec.getMaximumPoolSize(); + List<CountDownLatch> latches = Lists.newArrayList(); + final CountDownLatch started = new CountDownLatch(numThreads); + List<CountDownLatch> finished = Lists.newArrayList(); + + // seed the executor's threads + for (int i = 0; i < numThreads; i++) { + final CountDownLatch latch = new CountDownLatch(1); + final CountDownLatch fin = new CountDownLatch(1); + latches.add(latch); + finished.add(fin); + exec.submit(() -> { + try { + started.countDown(); + latch.await(); + fin.countDown(); + } catch (InterruptedException e) { + fail(); + } + }); + } + try { + assertTrue(started.await(100, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + // fill the queue + CountDownLatch startedBlocked = new CountDownLatch(1); + while (exec.getQueue().remainingCapacity() > 0) { + final CountDownLatch latch = new CountDownLatch(1); + latches.add(latch); + exec.submit(() -> { + try { + startedBlocked.countDown(); + latch.await(); + } catch (InterruptedException e) { + fail(); + } + }); + } + + latches.remove(0).countDown(); // release one of the executors + // ... we need to do this because load is recomputed when jobs are taken + // Note: For this to work, 1 / numThreads must be less than the load threshold (0.2) + + // verify that the old job has terminated + try { + assertTrue("Job didn't finish", + finished.remove(0).await(100, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + + // verify that a previously blocked thread has started + try { + assertTrue(startedBlocked.await(10, TimeUnit.MILLISECONDS)); + } catch (InterruptedException e) { + fail(); + } + + + // add another job to fill the queue + final CountDownLatch latch = new CountDownLatch(1); + latches.add(latch); + exec.submit(() -> { + try { + latch.await(); + } catch (InterruptedException e) { + fail(); + } + }); + assertEquals(exec.getQueue().size(), maxQueueSize); + + return latches; + } + + @Test + public void releaseOneThread() { + maxQueueSize = 10; + BoundedThreadPool exec = newFixedThreadPool(4, namedThreads("test")); + List<CountDownLatch> latches = fillExecutor(exec); + + CountDownLatch myLatch = new CountDownLatch(1); + ExecutorService myExec = Executors.newSingleThreadExecutor(); + Future<Thread> expected = myExec.submit(Thread::currentThread); + + assertEquals(exec.getQueue().size(), maxQueueSize); + long start = System.nanoTime(); + Future<Thread> actual = myExec.submit(() -> { + return exec.submit(() -> { + myLatch.countDown(); + return Thread.currentThread(); + }).get(); + }); + + try { + assertFalse("Thread should still be blocked", + myLatch.await(10, TimeUnit.MILLISECONDS)); + + latches.remove(0).countDown(); // release the first thread + assertFalse("Thread should still be blocked", + myLatch.await(10, TimeUnit.MILLISECONDS)); + latches.remove(0).countDown(); // release the second thread + + assertTrue("Thread should be unblocked", + myLatch.await(10, TimeUnit.MILLISECONDS)); + long delta = System.nanoTime() - start; + double load = exec.getQueue().size() / (double) maxQueueSize; + assertTrue("Load is greater than threshold", load <= 0.8); + assertTrue("Load is less than threshold", load >= 0.6); + assertEquals("Work done on wrong thread", expected.get(), actual.get()); + assertTrue("Took more than one second", delta < Math.pow(10, 9)); + } catch (InterruptedException | ExecutionException e) { + fail(); + } finally { + latches.forEach(CountDownLatch::countDown); + exec.shutdown(); + } + + // TODO perhaps move to tearDown + try { + assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + fail(); + } + + } + + @Test + public void highLoadTimeout() { + maxQueueSize = 10; + BoundedThreadPool exec = newFixedThreadPool(2, namedThreads("test")); + List<CountDownLatch> latches = fillExecutor(exec); + + // true if the job is executed and it is done on the test thread + final AtomicBoolean sameThread = new AtomicBoolean(false); + final Thread myThread = Thread.currentThread(); + long start = System.nanoTime(); + exec.submit(() -> { + sameThread.set(myThread.equals(Thread.currentThread())); + }); + + long delta = System.nanoTime() - start; + assertEquals(maxQueueSize, exec.getQueue().size()); + assertTrue("Work done on wrong thread (or didn't happen)", sameThread.get()); + assertTrue("Took less than one second. Actual: " + delta / 1_000_000.0 + "ms", + delta > Math.pow(10, 9)); + assertTrue("Took more than two seconds", delta < 2 * Math.pow(10, 9)); + latches.forEach(CountDownLatch::countDown); + exec.shutdown(); + + // TODO perhaps move to tearDown + try { + assertTrue(exec.awaitTermination(1, TimeUnit.SECONDS)); + } catch (InterruptedException e) { + fail(); + } + } +}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java new file mode 100644 index 00000000..e3a5e945 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ByteArraySizeHashPrinterTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onlab.util; + +import static org.junit.Assert.*; + +import java.util.Arrays; + +import org.junit.Test; + +/** + * Test cases for byte[] pretty printer. + */ +public class ByteArraySizeHashPrinterTest { + + /** + * Test method for {@link org.onlab.util.ByteArraySizeHashPrinter#toString()}. + */ + @Test + public void testToStringNull() { + final byte[] none = null; + + assertEquals("byte[]{null}", String.valueOf(ByteArraySizeHashPrinter.of(none))); + assertNull(ByteArraySizeHashPrinter.orNull(none)); + } + + /** + * Test method for {@link org.onlab.util.ByteArraySizeHashPrinter#toString()}. + */ + @Test + public void testToString() { + final byte[] some = new byte[] {2, 5, 0, 1 }; + final String expected = "byte[]{length=" + some.length + ", hash=" + Arrays.hashCode(some) + "}"; + + assertEquals(expected, String.valueOf(ByteArraySizeHashPrinter.of(some))); + assertNotNull(ByteArraySizeHashPrinter.orNull(some)); + } + +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java new file mode 100644 index 00000000..d30e1b59 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/CounterTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2014 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.onlab.junit.TestTools.delay; + +/** + * Tests of the Counter utility. + */ +public class CounterTest { + + @Test + public void basics() { + Counter tt = new Counter(); + assertEquals("incorrect number of bytes", 0L, tt.total()); + assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); + tt.add(1234567890L); + assertEquals("incorrect number of bytes", 1234567890L, tt.total()); + assertTrue("incorrect throughput", 1234567890.0 < tt.throughput()); + delay(1500); + tt.add(1L); + assertEquals("incorrect number of bytes", 1234567891L, tt.total()); + assertTrue("incorrect throughput", 1234567891.0 > tt.throughput()); + tt.reset(); + assertEquals("incorrect number of bytes", 0L, tt.total()); + assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); + } + + @Test + public void freeze() { + Counter tt = new Counter(); + tt.add(123L); + assertEquals("incorrect number of bytes", 123L, tt.total()); + delay(1000); + tt.freeze(); + tt.add(123L); + assertEquals("incorrect number of bytes", 123L, tt.total()); + + double d = tt.duration(); + double t = tt.throughput(); + assertEquals("incorrect duration", d, tt.duration(), 0.0001); + assertEquals("incorrect throughput", t, tt.throughput(), 0.0001); + assertEquals("incorrect number of bytes", 123L, tt.total()); + } + + @Test + public void reset() { + Counter tt = new Counter(); + tt.add(123L); + assertEquals("incorrect number of bytes", 123L, tt.total()); + + double d = tt.duration(); + double t = tt.throughput(); + assertEquals("incorrect duration", d, tt.duration(), 0.0001); + assertEquals("incorrect throughput", t, tt.throughput(), 0.0001); + assertEquals("incorrect number of bytes", 123L, tt.total()); + + tt.reset(); + assertEquals("incorrect throughput", 0.0, tt.throughput(), 0.0001); + assertEquals("incorrect number of bytes", 0, tt.total()); + } + + @Test + public void syntheticTracker() { + Counter tt = new Counter(5000, 1000, 6000); + assertEquals("incorrect duration", 1, tt.duration(), 0.1); + assertEquals("incorrect throughput", 1000, tt.throughput(), 1.0); + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java new file mode 100644 index 00000000..727c0f73 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/FrequencyTest.java @@ -0,0 +1,107 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import com.google.common.testing.EqualsTester; +import org.junit.Test; +import org.onlab.junit.ImmutableClassChecker; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.lessThan; + +public class FrequencyTest { + + private final Frequency frequency1 = Frequency.ofMHz(1000); + private final Frequency sameFrequency1 = Frequency.ofMHz(1000); + private final Frequency frequency2 = Frequency.ofGHz(1000); + private final Frequency sameFrequency2 = Frequency.ofGHz(1000); + private final Frequency moreSameFrequency2 = Frequency.ofTHz(1); + private final Frequency frequency3 = Frequency.ofTHz(193.1); + private final Frequency sameFrequency3 = Frequency.ofGHz(193100); + + /** + * Tests immutability of Frequency. + */ + @Test + public void testImmutability() { + ImmutableClassChecker.assertThatClassIsImmutable(Frequency.class); + } + + /** + * Tests equality of Frequency instances. + */ + @Test + public void testEquality() { + new EqualsTester() + .addEqualityGroup(frequency1, sameFrequency1) + .addEqualityGroup(frequency2, sameFrequency2, moreSameFrequency2) + .addEqualityGroup(frequency3, sameFrequency3) + .testEquals(); + } + + /** + * Tests the first object is less than the second object. + */ + @Test + public void testLessThan() { + assertThat(frequency1, is(lessThan(frequency2))); + assertThat(frequency1.isLessThan(frequency2), is(true)); + } + + @Test + public void testGreaterThan() { + assertThat(frequency2, is(greaterThan(frequency1))); + assertThat(frequency2.isGreaterThan(frequency1), is(true)); + } + + /** + * Tests add operation of two Frequencies. + */ + @Test + public void testAdd() { + Frequency low = Frequency.ofMHz(100); + Frequency high = Frequency.ofGHz(1); + Frequency expected = Frequency.ofMHz(1100); + + assertThat(low.add(high), is(expected)); + } + + /** + * Tests subtract operation of two Frequencies. + */ + @Test + public void testSubtract() { + Frequency high = Frequency.ofGHz(1); + Frequency low = Frequency.ofMHz(100); + Frequency expected = Frequency.ofMHz(900); + + assertThat(high.subtract(low), is(expected)); + } + + /** + * Tests multiply operation of Frequency. + */ + @Test + public void testMultiply() { + Frequency frequency = Frequency.ofMHz(1000); + long factor = 5; + Frequency expected = Frequency.ofGHz(5); + + assertThat(frequency.multiply(5), is(expected)); + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java new file mode 100644 index 00000000..5be1cda4 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/GroupedThreadFactoryTest.java @@ -0,0 +1,53 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Test; +import org.onlab.junit.TestTools; + +import static org.junit.Assert.*; + +/** + * Tests of the group thread factory. + */ +public class GroupedThreadFactoryTest { + + @Test + public void basics() { + GroupedThreadFactory a = GroupedThreadFactory.groupedThreadFactory("foo"); + GroupedThreadFactory b = GroupedThreadFactory.groupedThreadFactory("foo"); + assertSame("factories should be same", a, b); + + assertTrue("wrong toString", a.toString().contains("foo")); + Thread t = a.newThread(() -> TestTools.print("yo")); + assertSame("wrong group", a.threadGroup(), t.getThreadGroup()); + } + + @Test + public void hierarchical() { + GroupedThreadFactory a = GroupedThreadFactory.groupedThreadFactory("foo/bar"); + GroupedThreadFactory b = GroupedThreadFactory.groupedThreadFactory("foo/goo"); + GroupedThreadFactory p = GroupedThreadFactory.groupedThreadFactory("foo"); + + assertSame("groups should be same", p.threadGroup(), a.threadGroup().getParent()); + assertSame("groups should be same", p.threadGroup(), b.threadGroup().getParent()); + + assertEquals("wrong name", "foo/bar", a.threadGroup().getName()); + assertEquals("wrong name", "foo/goo", b.threadGroup().getName()); + assertEquals("wrong name", "foo", p.threadGroup().getName()); + } + +}
\ No newline at end of file diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java new file mode 100644 index 00000000..27652123 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/HexStringTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2014 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Test; + +import com.esotericsoftware.minlog.Log; + +import junit.framework.TestCase; + +/** + * Test of the Hexstring. + * + */ + +public class HexStringTest extends TestCase { + + @Test + public void testMarshalling() throws Exception { + String dpidStr = "00:00:00:23:20:2d:16:71"; + long dpid = HexString.toLong(dpidStr); + String testStr = HexString.toHexString(dpid); + TestCase.assertEquals(dpidStr, testStr); + } + + @Test + public void testToLong() { + String dpidStr = "3e:1f:01:fc:72:8c:63:31"; + long valid = 0x3e1f01fc728c6331L; + long testLong = HexString.toLong(dpidStr); + TestCase.assertEquals(valid, testLong); + } + + @Test + public void testToLongMSB() { + String dpidStr = "ca:7c:5e:d1:64:7a:95:9b"; + long valid = -3856102927509056101L; + long testLong = HexString.toLong(dpidStr); + TestCase.assertEquals(valid, testLong); + } + + @Test + public void testToLongError() { + String dpidStr = "09:08:07:06:05:04:03:02:01"; + try { + HexString.toLong(dpidStr); + fail("HexString.toLong() should have thrown a NumberFormatException"); + } catch (NumberFormatException expected) { + Log.info("HexString.toLong() have thrown a NumberFormatException"); + } + } + + @Test + public void testToStringBytes() { + byte[] dpid = {0, 0, 0, 0, 0, 0, 0, -1 }; + String valid = "00:00:00:00:00:00:00:ff"; + String testString = HexString.toHexString(dpid); + TestCase.assertEquals(valid, testString); + } + + @Test + public void testFromHexStringError() { + String invalidStr = "00:00:00:00:00:00:ffff"; + try { + HexString.fromHexString(invalidStr); + fail("HexString.fromHexString() should have thrown a NumberFormatException"); + } catch (NumberFormatException expected) { + Log.info("HexString.toLong() have thrown a NumberFormatException"); + } + } +} + diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java new file mode 100644 index 00000000..9758511f --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/PositionalParameterStringFormatterTest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onlab.util; + +import static org.junit.Assert.*; +import static org.onlab.util.PositionalParameterStringFormatter.format; + +import org.junit.Test; + +public class PositionalParameterStringFormatterTest { + + @Test + public void testFormat0() { + String fmt = "Some string 1 2 3"; + assertEquals("Some string 1 2 3", format(fmt)); + } + + @Test + public void testFormat1() { + String fmt = "Some string {} 2 3"; + assertEquals("Some string 1 2 3", format(fmt, 1)); + } + + @Test + public void testFormat2() { + String fmt = "Some string {} 2 {}"; + assertEquals("Some string 1 2 3", format(fmt, 1, "3")); + } + + @Test + public void testFormatNull() { + String fmt = "Some string {} 2 {}"; + assertEquals("Some string 1 2 null", format(fmt, 1, null)); + } + + @Test + public void testFormatExtraBracket() { + String fmt = "Some string {} 2 {}"; + assertEquals("Some string 1 2 {}", format(fmt, 1)); + } + + @Test + public void testFormatMissingBracket() { + String fmt = "Some string 1 2 3"; + assertEquals("Some string 1 2 3", format(fmt, 7)); + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java new file mode 100644 index 00000000..4b08d2fc --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/RetryingFunctionTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for RetryingFunction. + * + */ +public class RetryingFunctionTest { + + private int round; + + @Before + public void setUp() { + round = 1; + } + + @After + public void tearDown() { + round = 0; + } + + @Test(expected = RetryableException.class) + public void testNoRetries() { + new RetryingFunction<>(this::succeedAfterOneFailure, RetryableException.class, 0, 10).apply(null); + } + + @Test + public void testSuccessAfterOneRetry() { + new RetryingFunction<>(this::succeedAfterOneFailure, RetryableException.class, 1, 10).apply(null); + } + + @Test(expected = RetryableException.class) + public void testFailureAfterOneRetry() { + new RetryingFunction<>(this::succeedAfterTwoFailures, RetryableException.class, 1, 10).apply(null); + } + + @Test + public void testFailureAfterTwoRetries() { + new RetryingFunction<>(this::succeedAfterTwoFailures, RetryableException.class, 2, 10).apply(null); + } + + @Test(expected = NonRetryableException.class) + public void testFailureWithNonRetryableFailure() { + new RetryingFunction<>(this::failCompletely, RetryableException.class, 2, 10).apply(null); + } + + private String succeedAfterOneFailure(String input) { + if (round++ <= 1) { + throw new RetryableException(); + } else { + return "pass"; + } + } + + private String succeedAfterTwoFailures(String input) { + if (round++ <= 2) { + throw new RetryableException(); + } else { + return "pass"; + } + } + + private String failCompletely(String input) { + if (round++ <= 1) { + throw new NonRetryableException(); + } else { + return "pass"; + } + } + + private class RetryableException extends RuntimeException { + } + + private class NonRetryableException extends RuntimeException { + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java new file mode 100644 index 00000000..1730ca1f --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SharedExecutorsTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Test; + +import java.util.concurrent.ExecutorService; + +import static org.junit.Assert.*; + +/** + * Tests of the SharedExecutors Test. + */ +public class SharedExecutorsTest { + + @Test + public void singleThread() { + ExecutorService a = SharedExecutors.getSingleThreadExecutor(); + assertNotNull("ExecutorService must not be null", a); + ExecutorService b = SharedExecutors.getSingleThreadExecutor(); + assertSame("factories should be same", a, b); + + } + + @Test + public void poolThread() { + ExecutorService a = SharedExecutors.getPoolThreadExecutor(); + assertNotNull("ExecutorService must not be null", a); + ExecutorService b = SharedExecutors.getPoolThreadExecutor(); + assertSame("factories should be same", a, b); + + } + + @Test + public void timer() { + java.util.Timer a = SharedExecutors.getTimer(); + assertNotNull("Timer must not be null", a); + java.util.Timer b = SharedExecutors.getTimer(); + assertSame("factories should be same", a, b); + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java new file mode 100644 index 00000000..c15cc8a6 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/SlidingWindowCounterTest.java @@ -0,0 +1,105 @@ +/* + * Copyright 2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Unit tests for the sliding window counter. + */ + +@Ignore("Disable these for now because of intermittent load related failures on Jenkins runs.") +public class SlidingWindowCounterTest { + + private SlidingWindowCounter counter; + + @Before + public void setUp() { + counter = new SlidingWindowCounter(2); + } + + @After + public void tearDown() { + counter.destroy(); + } + + @Test + public void testIncrementCount() { + assertEquals(0, counter.get(1)); + assertEquals(0, counter.get(2)); + counter.incrementCount(); + assertEquals(1, counter.get(1)); + assertEquals(1, counter.get(2)); + counter.incrementCount(2); + assertEquals(3, counter.get(2)); + } + + @Test + public void testSlide() { + counter.incrementCount(); + counter.advanceHead(); + assertEquals(0, counter.get(1)); + assertEquals(1, counter.get(2)); + counter.incrementCount(2); + assertEquals(2, counter.get(1)); + assertEquals(3, counter.get(2)); + } + + @Test + public void testWrap() { + counter.incrementCount(); + counter.advanceHead(); + counter.incrementCount(2); + counter.advanceHead(); + assertEquals(0, counter.get(1)); + assertEquals(2, counter.get(2)); + counter.advanceHead(); + assertEquals(0, counter.get(1)); + assertEquals(0, counter.get(2)); + + } + + @Test + public void testCornerCases() { + try { + counter.get(3); + fail("Exception should have been thrown"); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + try { + new SlidingWindowCounter(0); + fail("Exception should have been thrown"); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + + try { + new SlidingWindowCounter(-1); + fail("Exception should have been thrown"); + } catch (IllegalArgumentException e) { + assertTrue(true); + } + } +} diff --git a/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java new file mode 100644 index 00000000..56f0f957 --- /dev/null +++ b/framework/src/onos/utils/misc/src/test/java/org/onlab/util/ToolsTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2014-2015 Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onlab.util; + +import org.junit.Test; +import org.onlab.junit.TestTools; + +import java.util.concurrent.ThreadFactory; + +import static org.junit.Assert.*; +import static org.onlab.junit.TestTools.assertAfter; + +/** + * Test of the miscellaneous tools. + */ +public class ToolsTest { + + @Test + public void fromHex() throws Exception { + assertEquals(15, Tools.fromHex("0f")); + assertEquals(16, Tools.fromHex("10")); + assertEquals(65535, Tools.fromHex("ffff")); + assertEquals(4096, Tools.fromHex("1000")); + assertEquals(0xffffffffffffffffL, Tools.fromHex("ffffffffffffffff")); + } + + @Test + public void toHex() throws Exception { + assertEquals("0f", Tools.toHex(15, 2)); + assertEquals("ffff", Tools.toHex(65535, 4)); + assertEquals("1000", Tools.toHex(4096, 4)); + assertEquals("000000000000000f", Tools.toHex(15)); + assertEquals("ffffffffffffffff", Tools.toHex(0xffffffffffffffffL)); + + } + + @Test + public void namedThreads() { + ThreadFactory f = Tools.namedThreads("foo-%d"); + Thread t = f.newThread(() -> TestTools.print("yo")); + assertTrue("wrong pattern", t.getName().startsWith("foo-")); + } + + @Test + public void groupedThreads() { + ThreadFactory f = Tools.groupedThreads("foo/bar-me", "foo-%d"); + Thread t = f.newThread(() -> TestTools.print("yo")); + assertTrue("wrong pattern", t.getName().startsWith("foo-bar-me-foo-")); + assertTrue("wrong group", t.getThreadGroup().getName().equals("foo/bar-me")); + } + + @Test + public void exceptionHandler() throws InterruptedException { + ThreadFactory f = Tools.namedThreads("foo"); + Thread t = f.newThread(() -> { + throw new IllegalStateException("BOOM!"); + }); + assertNotNull("thread should have exception handler", t.getUncaughtExceptionHandler()); + t.start(); + assertAfter(100, () -> assertEquals("incorrect thread state", Thread.State.TERMINATED, t.getState())); + } + +} |