/* * Copyright 2002-2016 the original author or authors. * * 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.springframework.integration.channel; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Comparator; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; import org.springframework.integration.support.MessageBuilder; import org.springframework.messaging.Message; import org.springframework.messaging.support.GenericMessage; /** * @author Mark Fisher */ public class PriorityChannelTests { @Test public void testCapacityEnforced() { PriorityChannel channel = new PriorityChannel(3); assertTrue(channel.send(new GenericMessage<String>("test1"), 0)); assertTrue(channel.send(new GenericMessage<String>("test2"), 0)); assertTrue(channel.send(new GenericMessage<String>("test3"), 0)); assertFalse(channel.send(new GenericMessage<String>("test4"), 0)); channel.receive(0); assertTrue(channel.send(new GenericMessage<String>("test5"))); } @Test public void testDefaultComparatorWithTimestampFallback() throws Exception { PriorityChannel channel = new PriorityChannel(); for (int i = 0; i < 1000; i++) { channel.send(new GenericMessage<Integer>(i)); } for (int i = 0; i < 1000; i++) { assertEquals(i, channel.receive().getPayload()); } } @Test public void testDefaultComparator() { PriorityChannel channel = new PriorityChannel(5); Message<?> priority1 = createPriorityMessage(10); Message<?> priority2 = createPriorityMessage(7); Message<?> priority3 = createPriorityMessage(0); Message<?> priority4 = createPriorityMessage(-3); Message<?> priority5 = createPriorityMessage(-99); channel.send(priority4); channel.send(priority3); channel.send(priority5); channel.send(priority1); channel.send(priority2); assertEquals("test:10", channel.receive(0).getPayload()); assertEquals("test:7", channel.receive(0).getPayload()); assertEquals("test:0", channel.receive(0).getPayload()); assertEquals("test:-3", channel.receive(0).getPayload()); assertEquals("test:-99", channel.receive(0).getPayload()); } // although this test has no assertions it results in ConcurrentModificationException // if executed before changes for INT-2508 @Test public void testPriorityChannelWithConcurrentModification() throws Exception { final PriorityChannel channel = new PriorityChannel(); final Message<String> message = new GenericMessage<String>("hello"); for (int i = 0; i < 1000; i++) { channel.send(message); new Thread(() -> channel.receive()).start(); new Thread(() -> message.getHeaders().toString()).start(); } } @Test public void testCustomComparator() { PriorityChannel channel = new PriorityChannel(5, new StringPayloadComparator()); Message<?> messageA = new GenericMessage<String>("A"); Message<?> messageB = new GenericMessage<String>("B"); Message<?> messageC = new GenericMessage<String>("C"); Message<?> messageD = new GenericMessage<String>("D"); Message<?> messageE = new GenericMessage<String>("E"); channel.send(messageC); channel.send(messageA); channel.send(messageE); channel.send(messageD); channel.send(messageB); assertEquals("A", channel.receive(0).getPayload()); assertEquals("B", channel.receive(0).getPayload()); assertEquals("C", channel.receive(0).getPayload()); assertEquals("D", channel.receive(0).getPayload()); assertEquals("E", channel.receive(0).getPayload()); } @Test public void testWithCustomComparatorAndSequence() { PriorityChannel channel = new PriorityChannel(10, new FooHeaderComparator()); Message<?> message1 = MessageBuilder.withPayload(1).setHeader("foo", 1).build(); Message<?> message2 = MessageBuilder.withPayload(2).setHeader("foo", 1).build(); Message<?> message3 = MessageBuilder.withPayload(3).setHeader("foo", 1).build(); Message<?> message4 = MessageBuilder.withPayload(4).build(); Message<?> message5 = MessageBuilder.withPayload(5).setHeader("foo", 3).build(); Message<?> message6 = MessageBuilder.withPayload(6).setHeader("foo", 3).build(); Message<?> message7 = MessageBuilder.withPayload(7).setHeader("foo", 4).build(); Message<?> message8 = MessageBuilder.withPayload(8).setHeader("foo", 4).build(); channel.send(message1); channel.send(message2); channel.send(message3); channel.send(message4); channel.send(message5); channel.send(message6); channel.send(message7); channel.send(message8); Object receivedOne = channel.receive(0).getPayload(); Object receivedTwo = channel.receive(0).getPayload(); Object receivedThree = channel.receive(0).getPayload(); Object receivedFour = channel.receive(0).getPayload(); Object receivedFive = channel.receive(0).getPayload(); Object receivedSix = channel.receive(0).getPayload(); Object receivedSeven = channel.receive(0).getPayload(); Object receivedEight = channel.receive(0).getPayload(); assertEquals(7, receivedOne); assertEquals(8, receivedTwo); assertEquals(5, receivedThree); assertEquals(6, receivedFour); assertEquals(1, receivedFive); assertEquals(2, receivedSix); assertEquals(3, receivedSeven); assertEquals(4, receivedEight); } @Test public void testWithDefaultComparatorAndSequence() { PriorityChannel channel = new PriorityChannel(); Message<?> message1 = MessageBuilder.withPayload(1).setPriority(1).build(); Message<?> message2 = MessageBuilder.withPayload(2).setPriority(1).build(); Message<?> message3 = MessageBuilder.withPayload(3).setPriority(1).build(); Message<?> message4 = MessageBuilder.withPayload(4).setPriority(2).build(); Message<?> message5 = MessageBuilder.withPayload(5).setPriority(2).build(); Message<?> message6 = MessageBuilder.withPayload(6).build(); Message<?> message7 = MessageBuilder.withPayload(7).build(); channel.send(message1); channel.send(message2); channel.send(message3); channel.send(message4); channel.send(message5); channel.send(message6); channel.send(message7); Object receivedOne = channel.receive(0).getPayload(); Object receivedTwo = channel.receive(0).getPayload(); Object receivedThree = channel.receive(0).getPayload(); Object receivedFour = channel.receive(0).getPayload(); Object receivedFive = channel.receive(0).getPayload(); Object receivedSix = channel.receive(0).getPayload(); Object receivedSeven = channel.receive(0).getPayload(); assertEquals(4, receivedOne); assertEquals(5, receivedTwo); assertEquals(1, receivedThree); assertEquals(2, receivedFour); assertEquals(3, receivedFive); assertEquals(6, receivedSix); assertEquals(7, receivedSeven); } @Test public void testNullPriorityIsConsideredNormal() { PriorityChannel channel = new PriorityChannel(5); Message<?> highPriority = createPriorityMessage(5); Message<?> lowPriority = createPriorityMessage(-5); Message<?> nullPriority = new GenericMessage<String>("test:NULL"); channel.send(lowPriority); channel.send(highPriority); channel.send(nullPriority); assertEquals("test:5", channel.receive(0).getPayload()); assertEquals("test:NULL", channel.receive(0).getPayload()); assertEquals("test:-5", channel.receive(0).getPayload()); } @Test public void testUnboundedCapacity() { PriorityChannel channel = new PriorityChannel(); Message<?> highPriority = createPriorityMessage(5); Message<?> lowPriority = createPriorityMessage(-5); Message<?> nullPriority = new GenericMessage<String>("test:NULL"); channel.send(lowPriority); channel.send(highPriority); channel.send(nullPriority); assertEquals("test:5", channel.receive(0).getPayload()); assertEquals("test:NULL", channel.receive(0).getPayload()); assertEquals("test:-5", channel.receive(0).getPayload()); } @Test public void testTimeoutElapses() throws InterruptedException { final PriorityChannel channel = new PriorityChannel(1); final AtomicBoolean sentSecondMessage = new AtomicBoolean(false); ExecutorService executor = Executors.newSingleThreadScheduledExecutor(); channel.send(new GenericMessage<String>("test-1")); executor.execute(() -> sentSecondMessage.set(channel.send(new GenericMessage<String>("test-2"), 10))); assertFalse(sentSecondMessage.get()); executor.shutdown(); assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS)); Message<?> message1 = channel.receive(10000); assertNotNull(message1); assertEquals("test-1", message1.getPayload()); assertFalse(sentSecondMessage.get()); assertNull(channel.receive(0)); } @Test public void testTimeoutDoesNotElapse() throws InterruptedException { final PriorityChannel channel = new PriorityChannel(1); final AtomicBoolean sentSecondMessage = new AtomicBoolean(false); final CountDownLatch latch = new CountDownLatch(1); Executor executor = Executors.newSingleThreadScheduledExecutor(); channel.send(new GenericMessage<String>("test-1")); executor.execute(() -> { sentSecondMessage.set(channel.send(new GenericMessage<String>("test-2"), 3000)); latch.countDown(); }); assertFalse(sentSecondMessage.get()); Thread.sleep(500); Message<?> message1 = channel.receive(); assertNotNull(message1); assertEquals("test-1", message1.getPayload()); latch.await(1000, TimeUnit.MILLISECONDS); assertTrue(sentSecondMessage.get()); Message<?> message2 = channel.receive(); assertNotNull(message2); assertEquals("test-2", message2.getPayload()); } @Test public void testIndefiniteTimeout() throws InterruptedException { final PriorityChannel channel = new PriorityChannel(1); final AtomicBoolean sentSecondMessage = new AtomicBoolean(false); ExecutorService executor = Executors.newSingleThreadScheduledExecutor(); channel.send(new GenericMessage<String>("test-1")); executor.execute(() -> sentSecondMessage.set(channel.send(new GenericMessage<String>("test-2"), -1))); assertFalse(sentSecondMessage.get()); Thread.sleep(500); Message<?> message1 = channel.receive(1000); assertNotNull(message1); assertEquals("test-1", message1.getPayload()); executor.shutdown(); assertTrue(executor.awaitTermination(10, TimeUnit.SECONDS)); assertTrue(sentSecondMessage.get()); Message<?> message2 = channel.receive(); assertNotNull(message2); assertEquals("test-2", message2.getPayload()); } private static Message<String> createPriorityMessage(int priority) { return MessageBuilder.withPayload("test:" + priority).setPriority(priority).build(); } public static class StringPayloadComparator implements Comparator<Message<?>> { @Override public int compare(Message<?> message1, Message<?> message2) { String s1 = (String) message1.getPayload(); String s2 = (String) message2.getPayload(); return s1.compareTo(s2); } } public static class FooHeaderComparator implements Comparator<Message<?>> { @Override public int compare(Message<?> message1, Message<?> message2) { Integer foo1 = (Integer) message1.getHeaders().get("foo"); Integer foo2 = (Integer) message2.getHeaders().get("foo"); foo1 = foo1 != null ? foo1 : 0; foo2 = foo2 != null ? foo2 : 0; return foo2.compareTo(foo1); } } }