/*
* 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.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.easymock.EasyMock;
import org.fosstrak.ale.exception.DuplicateSubscriptionException;
import org.fosstrak.ale.exception.ECSpecValidationException;
import org.fosstrak.ale.exception.ImplementationException;
import org.fosstrak.ale.exception.InvalidURIException;
import org.fosstrak.ale.exception.NoSuchSubscriberException;
import org.fosstrak.ale.server.EventCycle;
import org.fosstrak.ale.server.ReportsGenerator;
import org.fosstrak.ale.server.ReportsGeneratorState;
import org.fosstrak.ale.server.impl.ReportsGeneratorImpl;
import org.fosstrak.ale.server.util.ECReportsHelper;
import org.fosstrak.ale.server.util.ECSpecValidator;
import org.fosstrak.ale.server.util.test.ECReportsHelperTest;
import org.fosstrak.ale.util.DeserializerUtil;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReport;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportGroup;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReportSpec;
import org.fosstrak.ale.xsd.ale.epcglobal.ECReports;
import org.fosstrak.ale.xsd.ale.epcglobal.ECSpec;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import util.ECElementsUtils;
import com.rits.cloning.Cloner;
/**
* test the reports generator.
*
* TODO: test the thread behavior of the generator and the reports notification...
*
* @author swieland
*
*/
@Ignore
public class ReportsGeneratorTest {
/** logger */
private static final Logger LOG = Logger.getLogger(ReportsGeneratorTest.class);
/**
* ec spec with report spec for group 'null' and requesting report if report does not contain tags.
*/
public final static String ECSPEC_CURRENT_REPORTSPECNULL_EMPTYREPORT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns2:ECSpec xmlns:ns2=\"urn:epcglobal:ale:xsd:1\"><logicalReaders><logicalReader>LogicalReader1</logicalReader></logicalReaders><boundarySpec><repeatPeriod unit=\"MS\">10000</repeatPeriod><duration unit=\"MS\">9500</duration><stableSetInterval unit=\"MS\">0</stableSetInterval></boundarySpec><reportSpecs><reportSpec reportIfEmpty=\"true\"><reportSet set=\"CURRENT\"/><output includeRawHex=\"true\" includeRawDecimal=\"true\" includeEPC=\"true\" includeTag=\"true\"/></reportSpec></reportSpecs></ns2:ECSpec>";
/**
* ec spec with report spec for group 'null' and request report only on change.
*/
public final static String ECSPEC_CURRENT_REPORTSPECNULL_ONLYONCHANGE = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns2:ECSpec xmlns:ns2=\"urn:epcglobal:ale:xsd:1\"><logicalReaders><logicalReader>LogicalReader1</logicalReader></logicalReaders><boundarySpec><repeatPeriod unit=\"MS\">10000</repeatPeriod><duration unit=\"MS\">9500</duration><stableSetInterval unit=\"MS\">0</stableSetInterval></boundarySpec><reportSpecs><reportSpec reportOnlyOnChange=\"true\"><reportSet set=\"CURRENT\"/><output includeRawHex=\"true\" includeRawDecimal=\"true\" includeEPC=\"true\" includeTag=\"true\"/></reportSpec></reportSpecs></ns2:ECSpec>";
/**
* ec spec with report spec for group 'null' and requesting no report if report does not contain tags.
*/
public static final String ECSPEC_CURRENT_REPORTSPECNULL_NOEMPTYREPORT = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns2:ECSpec xmlns:ns2=\"urn:epcglobal:ale:xsd:1\"><logicalReaders><logicalReader>LogicalReader1</logicalReader></logicalReaders><boundarySpec><repeatPeriod unit=\"MS\">10000</repeatPeriod><duration unit=\"MS\">9500</duration><stableSetInterval unit=\"MS\">0</stableSetInterval></boundarySpec><reportSpecs><reportSpec><reportSet set=\"CURRENT\"/><output includeRawHex=\"true\" includeRawDecimal=\"true\" includeEPC=\"true\" includeTag=\"true\"/></reportSpec></reportSpecs></ns2:ECSpec>";
/**
* obtain the EC Spec from the given input string.
* @param specString the specification.
* @return the ECSpec.
* @throws Exception error
*/
public static ECSpec getECSpec(String specString) throws Exception {
ByteArrayInputStream bis = new ByteArrayInputStream(specString.getBytes());
ECSpec ecReports = DeserializerUtil.deserializeECSpec(bis);
bis.close();
return ecReports;
}
/**
* test the correct behavior of the constructor in the spec validation case.
*/
@Test(expected = ECSpecValidationException.class)
public void testConstructorValidationException() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall().andThrow(new ECSpecValidationException("Mock exception"));
EasyMock.replay(validator);
new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
}
/**
* test the correct behavior of the constructor in the spec validation case.
*/
@Test(expected = ImplementationException.class)
public void testConstructorImplementationException() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall().andThrow(new ImplementationException("Mock exception"));
EasyMock.replay(validator);
new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
}
/**
* test getter.
* @throws Exception test failure.
*/
@Test
public void testGetSpecAndStateAndGetSubscribersAndGetName() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
Assert.assertEquals(spec, generator.getSpec());
Assert.assertEquals(ReportsGeneratorState.UNREQUESTED, ((ReportsGeneratorImpl) generator).getState());
Assert.assertNotNull(generator.getSubscribers());
Assert.assertEquals(0, generator.getSubscribers().size());
Assert.assertEquals("theName", generator.getName());
EasyMock.verify(validator);
}
/**
* test the correct behavior of the constructor in the spec validation case.
*/
@Test(expected = InvalidURIException.class)
public void testSubscribeInvalidURI() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
generator.subscribe(null);
}
/**
* test duplicate subscription not allowed.
*/
@Test(expected = DuplicateSubscriptionException.class)
public void testSubscribeDuplicateSubscriptionException() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new NonRunnableReportsGenerator("theName", spec, validator);
final String uri ="http://localhost:9999";
generator.subscribe(uri);
generator.subscribe(uri);
}
/**
* test the correct behavior of the constructor in the spec validation case.
*/
@Test(expected = NoSuchSubscriberException.class)
public void testUnsubscribeNoSuchSubscriber() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
generator.unsubscribe("http://localhost:9999");
}
/**
* test the correct behavior of the constructor in the spec validation case.
*/
@Test(expected = InvalidURIException.class)
public void testUnsubscribeInvalidURI() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new ReportsGeneratorImpl("theName", spec, validator, new ECReportsHelper());
generator.unsubscribe(null);
}
@Test
public void testSubscribeUnSubscribe() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
ReportsGenerator generator = new NonRunnableReportsGenerator("theName", spec, validator);
final String uri ="http://localhost:9999";
final String uri2 ="http://localhost:8888";
Assert.assertEquals(ReportsGeneratorState.UNREQUESTED, ((ReportsGeneratorImpl) generator).getState());
generator.subscribe(uri);
Assert.assertEquals(1, generator.getSubscribers().size());
Assert.assertEquals(ReportsGeneratorState.REQUESTED, ((ReportsGeneratorImpl) generator).getState());
generator.subscribe(uri2);
Assert.assertEquals(2, generator.getSubscribers().size());
List<String> subscribers = generator.getSubscribers();
for (String str : new String[] {uri, uri2 }) {
Assert.assertTrue(subscribers.contains(str));
}
generator.unsubscribe(uri);
Assert.assertEquals(1, generator.getSubscribers().size());
Assert.assertEquals(ReportsGeneratorState.REQUESTED, ((ReportsGeneratorImpl) generator).getState());
generator.unsubscribe(uri2);
Assert.assertEquals(0, generator.getSubscribers().size());
Assert.assertEquals(ReportsGeneratorState.UNREQUESTED, ((ReportsGeneratorImpl) generator).getState());
EasyMock.verify(validator);
}
/**
* test the notifications for poll and immediate - they should always receive all the reports (even empty).
* @throws Exception test failure.
*/
@Test
public void testNotifyPollers() throws Exception {
ECSpec spec = ECElementsUtils.createECSpec();
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
final String reportSpecName = "TestReport";
ECReportSpec reportSpec = EasyMock.createMock(ECReportSpec.class);
EasyMock.expect(reportSpec.isReportOnlyOnChange()).andReturn(false);
EasyMock.replay(reportSpec);
Map<String, ECReport> lastReports = new HashMap<String, ECReport> ();
EventCycle ec = EasyMock.createMock(EventCycle.class);
EasyMock.expect(ec.getReportSpecByName(reportSpecName)).andReturn(reportSpec).atLeastOnce();
EasyMock.expect(ec.getLastReports()).andReturn(lastReports).atLeastOnce();
EasyMock.replay(ec);
NonRunnablePollableReportsGenerator generator = new NonRunnablePollableReportsGenerator("theSpec", spec, validator);
ECReports reports = ECElementsUtils.createECReports();
generator.notifySubscribers(reports, ec);
ECReports result = generator.getPollReport();
Assert.assertEquals(reports.getALEID(), result.getALEID());
Assert.assertEquals(reports.getReports().getReport().get(0).getReportName(), result.getReports().getReport().get(0).getReportName());
EasyMock.verify(validator);
EasyMock.verify(ec);
EasyMock.verify(reportSpec);
}
@Test
public void testNotifyAllwaysButNotEmpty() throws Exception {
ECReports ecReportsNotEmpty = ECReportsHelperTest.getECReports(ECReportsHelperTest.ECREPORTS_NULLGROUP_TWOTAGS);
ECReports ecReportsEmpty = ECReportsHelperTest.getECReports(ECReportsHelperTest.ECREPORTS_NULLGROUP_NOTAGSINGROUP);
ECSpec spec = getECSpec(ECSPEC_CURRENT_REPORTSPECNULL_NOEMPTYREPORT);
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
Map<String, ECReport> lastReports = new HashMap<String, ECReport> ();
EventCycle ec = EasyMock.createMock(EventCycle.class);
EasyMock.expect(ec.getReportSpecByName(null)).andReturn(spec.getReportSpecs().getReportSpec().get(0)).atLeastOnce();
EasyMock.expect(ec.getLastReports()).andReturn(lastReports).atLeastOnce();
EasyMock.replay(ec);
NonRunnableNotifyableReportsGenerator generator = new NonRunnableNotifyableReportsGenerator("current", spec, validator);
// first run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
generator.setNotifiedReportsToNull();
// second run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
generator.setNotifiedReportsToNull();
// empty report (must not be delivered)
generator.notifySubscribers(new Cloner().deepClone(ecReportsEmpty), ec);
Assert.assertNull(generator.getNotifiedReports());
EasyMock.verify(validator);
EasyMock.verify(ec);
}
/**
* the report spec defines to return even empty reports.
* @throws Exception
*/
@Test
public void testNotifyReportIfEmpty() throws Exception {
ECReports ecReportsNotEmpty = ECReportsHelperTest.getECReports(ECReportsHelperTest.ECREPORTS_NULLGROUP_TWOTAGS);
ECReports ecReportsEmpty = ECReportsHelperTest.getECReports(ECReportsHelperTest.ECREPORTS_NULLGROUP_NOTAGSINGROUP);
ECSpec spec = getECSpec(ECSPEC_CURRENT_REPORTSPECNULL_EMPTYREPORT);
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
Map<String, ECReport> lastReports = new HashMap<String, ECReport> ();
EventCycle ec = EasyMock.createMock(EventCycle.class);
EasyMock.expect(ec.getReportSpecByName(null)).andReturn(spec.getReportSpecs().getReportSpec().get(0)).atLeastOnce();
EasyMock.expect(ec.getLastReports()).andReturn(lastReports).atLeastOnce();
EasyMock.replay(ec);
NonRunnableNotifyableReportsGenerator generator = new NonRunnableNotifyableReportsGenerator("current", spec, validator);
// first run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
generator.setNotifiedReportsToNull();
// second run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
generator.setNotifiedReportsToNull();
// empty report (must be delivered)
generator.notifySubscribers(new Cloner().deepClone(ecReportsEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), false);
EasyMock.verify(validator);
EasyMock.verify(ec);
}
/**
* the report spec defines to return even empty reports.
* @throws Exception test failure.
*/
@Test
public void testNotifyReportOnlyOnChange() throws Exception {
ECReports ecReportsNotEmpty = ECReportsHelperTest.getECReports(ECReportsHelperTest.ECREPORTS_NULLGROUP_TWOTAGS);
ECSpec spec = getECSpec(ECSPEC_CURRENT_REPORTSPECNULL_ONLYONCHANGE);
ECSpecValidator validator = EasyMock.createMock(ECSpecValidator.class);
validator.validateSpec(spec);
EasyMock.expectLastCall();
EasyMock.replay(validator);
Map<String, ECReport> lastReports = new HashMap<String, ECReport> ();
EventCycle ec = EasyMock.createMock(EventCycle.class);
EasyMock.expect(ec.getReportSpecByName(null)).andReturn(spec.getReportSpecs().getReportSpec().get(0)).atLeastOnce();
EasyMock.expect(ec.getLastReports()).andReturn(lastReports).atLeastOnce();
EasyMock.replay(ec);
NonRunnableNotifyableReportsGenerator generator = new NonRunnableNotifyableReportsGenerator("current", spec, validator);
// first run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
generator.setNotifiedReportsToNull();
// second run
generator.notifySubscribers(new Cloner().deepClone(ecReportsNotEmpty), ec);
Assert.assertNull(generator.getNotifiedReports());
generator.setNotifiedReportsToNull();
// remove one tag and thus the report must be delivered again.
ECReports r2 = new Cloner().deepClone(ecReportsNotEmpty);
r2.getReports().getReport().get(0).getGroup().get(0).getGroupList().getMember().remove(0);
generator.notifySubscribers(r2, ec);
Assert.assertNotNull(generator.getNotifiedReports());
assertTagsContained(generator.getNotifiedReports(), true);
EasyMock.verify(validator);
EasyMock.verify(ec);
}
/**
* verify that either tags are contained or not at all.
* @param notifiedReports the reports to verify.
* @param b if true, then tags must be contained, if false then tags shall not be contained.
*/
private void assertTagsContained(ECReports notifiedReports, boolean b) {
for (ECReport ecReport : notifiedReports.getReports().getReport()) {
for (ECReportGroup group : ecReport.getGroup()) {
if (b) {
// must contain tags
Assert.assertTrue(group.getGroupList().getMember().size() > 0);
} else {
// shall not contain tags
Assert.assertTrue(group.getGroupList().getMember().size() == 0);
}
}
}
}
/**
* little helper class overriding the thread parts of the reports generator -> allows the testing.
* @author swieland
*
*/
private class NonRunnableReportsGenerator extends ReportsGeneratorImpl {
public NonRunnableReportsGenerator(String name, ECSpec spec, ECSpecValidator validator) throws ECSpecValidationException, ImplementationException {
super(name, spec, validator, new ECReportsHelper());
}
@Override
public void start() {
LOG.debug("Mock start");
}
@Override
public void stop() {
LOG.debug("Mock stop");
}
}
/**
* helper class for tests
* @author swieland
*
*/
private class NonRunnableNotifyableReportsGenerator extends NonRunnableReportsGenerator {
private ECReports notifiedReports;
public NonRunnableNotifyableReportsGenerator(String name, ECSpec spec, ECSpecValidator validator) throws ECSpecValidationException, ImplementationException {
super(name, spec, validator);
}
@Override
protected void notifySubscribersWithFilteredReports(ECReports reports) {
notifiedReports = reports;
}
public ECReports getNotifiedReports() {
return notifiedReports;
}
public void setNotifiedReportsToNull() {
notifiedReports = null;
}
}
/**
* little helper class overriding the thread parts and polling of the reports generator -> allows the testing.
* @author swieland
*
*/
private class NonRunnablePollableReportsGenerator extends ReportsGeneratorImpl {
public NonRunnablePollableReportsGenerator(String name, ECSpec spec, ECSpecValidator validator) throws ECSpecValidationException, ImplementationException {
super(name, spec, validator, new ECReportsHelper());
}
@Override
public void start() {
LOG.debug("Mock start");
}
@Override
public void stop() {
LOG.debug("Mock stop");
}
@Override
public boolean isPolling() {
return true;
}
@Override
public ECReports getPollReport() {
return super.getPollReport();
}
}
}