/* * -----------------------------------------------------------------------\ * PerfCake *   * Copyright (C) 2010 - 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.perfcake.message.sender; import static org.testng.Assert.*; import org.perfcake.PerfCakeException; import org.perfcake.TestSetup; import org.perfcake.scenario.Scenario; import org.perfcake.scenario.ScenarioLoader; import org.perfcake.scenario.ScenarioRetractor; import org.testng.Assert; import org.testng.annotations.Test; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** * Tests {@link org.perfcake.message.sender.MessageSenderManager}. * * @author <a href="mailto:pavel.macik@gmail.com">Pavel Macík</a> */ @Test(groups = { "unit" }) public class MessageSenderManagerTest extends TestSetup { private static final int SENDER_COUNT = 100; private static final String SENDER_CLASS_NAME = TestSender.class.getName(); private static final int THREAD_COUNT = 100; private static final int SENDER_TASK_COUNT = 2000; private static final int THREAD_SLEEP_MILLIS = 1000; private static final AtomicInteger counter = new AtomicInteger(SENDER_TASK_COUNT); @Test public void messageSenderManagerTest() throws Exception { final MessageSenderManager msm = new MessageSenderManager(); msm.setSenderPoolSize(SENDER_COUNT); msm.setSenderClass(SENDER_CLASS_NAME); msm.init(); assertTrue(msm.availableSenderCount() == SENDER_COUNT); final MessageSender[] senders = new MessageSender[SENDER_COUNT]; int i = 0; final int n = 5; for (; i < n; i++) { senders[i] = msm.acquireSender(); } assertNotNull(senders[0]); assertTrue(msm.availableSenderCount() == (SENDER_COUNT - n)); for (i = 0; i < n; i++) { msm.releaseSender(senders[i]); } assertTrue(msm.availableSenderCount() == SENDER_COUNT); for (i = 0; i < SENDER_COUNT; i++) { senders[i] = msm.acquireSender(); } assertTrue(senders[0] instanceof TestSender, "Sender is an instance of " + senders[0].getClass().getName() + ". It should be instance of " + SENDER_CLASS_NAME); assertTrue(msm.availableSenderCount() == 0); try { msm.acquireSender(); } catch (final PerfCakeException te) { assertTrue(te.getMessage().equals("MessageSender pool is empty.")); } msm.releaseAllSenders(); assertTrue(msm.availableSenderCount() == SENDER_COUNT); msm.close(); } @Test(groups = { "ueber", "performance" }) public void threadSafeTest() throws Exception { final MessageSenderManager msm = new MessageSenderManager(); msm.setSenderPoolSize(SENDER_COUNT); msm.setSenderClass(SENDER_CLASS_NAME); msm.init(); final Map<Runnable, Throwable> threads = new HashMap<Runnable, Throwable>(); final ExecutorService es = Executors.newFixedThreadPool(THREAD_COUNT); for (int i = 0; i < SENDER_TASK_COUNT; i++) { final Runnable senderTask = new SenderTask(msm, threads); threads.put(senderTask, null); es.submit(senderTask); } es.shutdown(); es.awaitTermination((long) (SENDER_TASK_COUNT * THREAD_SLEEP_MILLIS * 1.2), TimeUnit.MILLISECONDS); assertTrue(es.isTerminated()); assertTrue(es.isShutdown()); final Iterator<Runnable> it = threads.keySet().iterator(); while (it.hasNext()) { final Throwable t = threads.get(it.next()); if (t != null) { fail("One of the threads threw following exception: " + t.getMessage()); } } msm.close(); } @Test public void threadLocalUsageTest() throws PerfCakeException { final Scenario scenario = ScenarioLoader.load("test-class"); scenario.init(); scenario.run(); scenario.close(); final ScenarioRetractor retractor = new ScenarioRetractor(scenario); Map<String, Integer> counters = ((TestSender) retractor.getMessageSenderManager().acquireSender()).getLocalCounters(); int i = counters.values().stream().collect(Collectors.summingInt(it -> it)); // if all the threads used the same variable, we would end up with the same number for each thread // let's see that this is not the case Assert.assertEquals(counters.size(), 10); Assert.assertTrue(i > 9000); // we are not perfect in storing the results, the are concurrent overwrites } private static class SenderTask implements Runnable { private static final Random rnd = new Random(System.currentTimeMillis()); private final MessageSenderManager msm; private final Map<Runnable, Throwable> threads; public SenderTask(final MessageSenderManager msm, final Map<Runnable, Throwable> threads) { this.msm = msm; this.threads = threads; } @Override public void run() { try { final MessageSender sender = msm.acquireSender(); Thread.sleep(rnd.nextInt(THREAD_SLEEP_MILLIS)); msm.releaseSender(sender); counter.decrementAndGet(); } catch (final Throwable t) { threads.put(Thread.currentThread(), t); } } } }