/* * Copyright (c) 2013-2014, Pierre Laporte * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this work; if not, see <http://www.gnu.org/licenses/>. */ package fr.pingtimeout.tyrion.util; import fr.pingtimeout.tyrion.model.*; import org.assertj.core.api.Assertions; import org.junit.Ignore; import org.junit.Test; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.CountDownLatch; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.extractProperty; public class EventsHolderSingletonTest { @Test public void test_record_new_entering() { // Given Object lock = new Object(); EventsHolderSingleton eventsHolder = EventsHolderSingleton.INSTANCE; Thread accessor = Thread.currentThread(); CriticalSectionEvent criticalSectionEvent = new CriticalSectionEntering(accessor, lock); // When eventsHolder.recordNewEntering(accessor, lock); // Then assertThat(eventsHolder.getAndClearEventsListOf(accessor.getId())) .usingElementComparator(new CriticalSectionEventsWithoutTime()) .containsOnly(criticalSectionEvent); } @Test public void test_record_new_entry() { // Given Object lock = new Object(); EventsHolderSingleton eventsHolder = EventsHolderSingleton.INSTANCE; Thread accessor = Thread.currentThread(); CriticalSectionEvent criticalSectionEvent = new CriticalSectionEntered(accessor, lock); // When eventsHolder.recordNewEntry(accessor, lock); // Then assertThat(eventsHolder.getAndClearEventsListOf(accessor.getId())) .usingElementComparator(new CriticalSectionEventsWithoutTime()) .containsOnly(criticalSectionEvent); } @Test public void test_record_new_exit() { // Given Object lock = new Object(); EventsHolderSingleton eventsHolder = EventsHolderSingleton.INSTANCE; Thread accessor = Thread.currentThread(); CriticalSectionEvent criticalSectionEvent = new CriticalSectionExit(accessor, lock); // When eventsHolder.recordNewExit(accessor, lock); // Then assertThat(eventsHolder.getAndClearEventsListOf(accessor.getId())) .usingElementComparator(new CriticalSectionEventsWithoutTime()) .containsOnly(criticalSectionEvent); } @Test @Ignore public void test_record_entries_and_exit_multithreaded() throws InterruptedException { // Given final Object lock = new Object(); final CountDownLatch startSignal = new CountDownLatch(1); final int numberOfThreads = 1000; final CountDownLatch doneSignal = new CountDownLatch(numberOfThreads); final EventsHolderSingleton eventsHolder = EventsHolderSingleton.INSTANCE; final Collection<Thread> threads = new ArrayList<>(numberOfThreads); for (int i = 0; i < numberOfThreads; i++) { Thread thread = new Thread(new Record2NewEntriesAndExit(startSignal, eventsHolder, lock, doneSignal)); threads.add(thread); thread.start(); } // When startSignal.countDown(); doneSignal.await(); // Then final List<Long> expectedThreadIds = extractProperty("id", Long.class).from(threads); final Set<Long> threadIds = eventsHolder.getThreadIds(); final CriticalSectionEventsWithoutTime eventsWithoutTime = new CriticalSectionEventsWithoutTime(); assertThat(threadIds).containsAll(expectedThreadIds); for (Thread thread : threads) { CriticalSectionEvent criticalSectionEnter = new CriticalSectionEntered(thread, lock); CriticalSectionEvent criticalSectionExit = new CriticalSectionExit(thread, lock); assertThat(eventsHolder.getAndClearEventsListOf(thread.getId())) .usingElementComparator(eventsWithoutTime) .containsOnly(criticalSectionEnter, criticalSectionExit); } } } class Record2NewEntriesAndExit implements Runnable { protected final CountDownLatch startSignal; protected final EventsHolderSingleton eventsHolder; protected final Object lock; protected final CountDownLatch doneSignal; Record2NewEntriesAndExit(CountDownLatch startSignal, EventsHolderSingleton eventsHolder, Object lock, CountDownLatch doneSignal) { this.startSignal = startSignal; this.eventsHolder = eventsHolder; this.lock = lock; this.doneSignal = doneSignal; } @Override public void run() { try { startSignal.await(); record2EnterAndExit(); doneSignal.countDown(); } catch (InterruptedException e) { e.printStackTrace(); Assertions.fail(e.getMessage()); } } protected void record2EnterAndExit() { eventsHolder.recordNewEntry(Thread.currentThread(), lock); eventsHolder.recordNewEntry(Thread.currentThread(), lock); eventsHolder.recordNewExit(Thread.currentThread(), lock); eventsHolder.recordNewExit(Thread.currentThread(), lock); } }