/*
* Copyright (C) 2007 ETH Zurich
*
* This file is part of Fosstrak (www.fosstrak.org).
*
* Fosstrak is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* Fosstrak 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Fosstrak; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package org.fosstrak.ale.server.test;
import java.util.LinkedList;
import java.util.List;
import org.apache.log4j.Logger;
import org.easymock.EasyMock;
import org.fosstrak.ale.server.EventCycle;
import org.fosstrak.ale.server.ReportsGenerator;
import org.fosstrak.ale.server.Tag;
import org.fosstrak.ale.server.impl.EventCycleImpl;
import org.fosstrak.ale.server.readers.LogicalReader;
import org.fosstrak.ale.server.readers.LogicalReaderManager;
import org.fosstrak.ale.server.readers.test.TestAdaptor;
import org.fosstrak.ale.server.util.test.ECSpecValidatorTest;
import org.fosstrak.ale.util.DeserializerUtil;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReports;
import org.fosstrak.ale.xsd.ale.epcglobal.ECSpec;
import org.junit.Ignore;
import org.junit.Test;
/**
* test some concurrency issues of an event cycle. please note that this is a very very basic and stupid brute force test... may need to enhance it for future use.
* <h1>this is an integration test for now - do not run it as a standard unit test!!!</h1>
* @author swieland
*
*/
@Ignore
public class EventCycleConcurrencyTest {
/** logger. */
private static final Logger LOG = Logger.getLogger(EventCycleConcurrencyTest.class);
private Tag[] tagsAsArray;
private int tagSize;
/**
* setup:
* <ul>
* <li>one reports generator</li>
* <li>one eventcycle</li>
* <li>N receivers</li>
* <li>M senders delivering tags on random intervals</li>
* </ul>
* then let the whole setup run for a while at full speed. fail upon synchronization issues.
* @throws Exception
*/
@Test
public void testConcurrency() throws Exception {
loadTags();
ECSpec ecspec = DeserializerUtil.deserializeECSpec(ECSpecValidatorTest.class.getResourceAsStream("/ecspecs/ecSpecForConcurrencyTests.xml"));
final String logicalReaderName1 = "LogicalReader1";
LogicalReader lr1 = EasyMock.createMock(LogicalReader.class);
EasyMock.expect(lr1.getName()).andReturn(logicalReaderName1).anyTimes();
lr1.addObserver(EasyMock.isA(EventCycle.class));
EasyMock.expectLastCall().anyTimes();
EasyMock.replay(lr1);
LogicalReaderManager manager = EasyMock.createMock(LogicalReaderManager.class);
EasyMock.expect(manager.contains(logicalReaderName1)).andReturn(true).anyTimes();
EasyMock.expect(manager.getLogicalReader(logicalReaderName1)).andReturn(lr1).anyTimes();
EasyMock.replay(manager);
ReportsGenerator reportsGenerator = EasyMock.createMock(ReportsGenerator.class);
EasyMock.expect(reportsGenerator.getName()).andReturn("generator").anyTimes();
EasyMock.expect(reportsGenerator.getSpec()).andReturn(ecspec).anyTimes();
reportsGenerator.notifySubscribers(EasyMock.isA(ECReports.class), EasyMock.isA(EventCycle.class));
EasyMock.expectLastCall().anyTimes();
EasyMock.replay(reportsGenerator);
EventCycle cycle = new EventCycleImpl(reportsGenerator, manager);
// execute the event cycle scheduler (invoking indirectly the ec processing)
Thread launcher = new Thread(createEventCycleRescheduler(cycle));
launcher.start();
List<Thread> producers = new LinkedList<Thread> ();
for (int i=0; i<50; i++) {
Thread producer = new Thread(addProducer(cycle, i));
producer.start();
producers.add(producer);
}
// now wait... :-)
Thread.sleep(120000L);
launcher.interrupt();
for (Thread producer : producers) {
producer.interrupt();
}
EasyMock.verify(manager);
EasyMock.verify(reportsGenerator);
EasyMock.verify(lr1);
}
private void loadTags() throws Exception {
TestAdaptor ta = new TestAdaptor();
ta.loadTags();
tagsAsArray = ta.getTags();
tagSize = tagsAsArray.length;
}
private Runnable addProducer(final EventCycle ec, final long delay) {
return new Runnable() {
@Override
public void run() {
try {
while (true) {
Thread.sleep(delay + 1);
Tag tag = randomTag();
ec.update(null, tag);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
private Tag randomTag() {
int pos = ((int) (Math.random() * tagSize * 1000))%tagSize;
return tagsAsArray[pos];
}
private Runnable createEventCycleRescheduler(final EventCycle ec) {
return new Runnable() {
@Override
public void run() {
try {
ec.launch();
while (true) {
Thread.sleep(307L);
if (((EventCycleImpl) ec).isRoundOver()) {
LOG.debug("reschedule EventCycle.");
ec.launch();
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
}