package hu.sztaki.ilab.longneck.process.task; import hu.sztaki.ilab.longneck.Record; import hu.sztaki.ilab.longneck.TestCase; import hu.sztaki.ilab.longneck.bootstrap.CompactProcess; import hu.sztaki.ilab.longneck.bootstrap.DecimalKeyGenerator; import hu.sztaki.ilab.longneck.bootstrap.KeyGenerator; import hu.sztaki.ilab.longneck.process.FailException; import hu.sztaki.ilab.longneck.process.FilterException; import hu.sztaki.ilab.longneck.process.ImmutableErrorRecordImpl; import hu.sztaki.ilab.longneck.process.LongneckProcess; import hu.sztaki.ilab.longneck.process.constraint.CheckResult; import hu.sztaki.ilab.longneck.process.kernel.Kernel; import hu.sztaki.ilab.longneck.process.mapping.MappedRecord; import hu.sztaki.ilab.longneck.util.MaxMatching; import hu.sztaki.ilab.longneck.util.TestUtil; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; /** * * @author Geszler Döme <gdome@ilab.sztaki.hu> */ public class ProcessTester { private final static Logger LOG = Logger.getLogger(ProcessTester.class); private final Kernel kernel; private final LongneckProcess longneckProcess; private final List<Record> localCloneQueue = new ArrayList<Record>(); private final KeyGenerator nodeKeyGenerator = new DecimalKeyGenerator(); private final boolean verbose; public ProcessTester(CompactProcess process, boolean verbose) { longneckProcess = process.getProcess(); kernel = new Kernel(longneckProcess.getTopLevelBlocks(), process.getFrameAddressResolver(), localCloneQueue); this.verbose = verbose; } private boolean process(TestCase testCase) { if (verbose) { showAndLog("Testing " + testCase.getId() + " ..."); showAndLog("Source record for " + testCase.getId() + " :"); showAndLog(testCase.getSourceRecord().toString()); } List<Record> queue = new ArrayList<Record>(); queue.add(testCase.getSourceRecord()); long startTime = System.currentTimeMillis(); while (!queue.isEmpty()) { for (Record record : queue) { try { kernel.process(record); // Beacause the cloned records if(record instanceof MappedRecord) record = ((MappedRecord)record).getAncestor(); testCase.getObservedTargetRecords().add(record); } catch (FailException e) { // Beacause the cloned records if(record instanceof MappedRecord) record = ((MappedRecord)record).getAncestor(); // do nothing } catch (FilterException e) { // Beacause the cloned records if(record instanceof MappedRecord) record = ((MappedRecord)record).getAncestor(); // do nothing } finally { for (Record errorRecord : createErrorRecords(record)) { testCase.getObservedErrorRecords().add(errorRecord); } } } queue.clear(); for (Record clone : localCloneQueue) { queue.add(clone); } localCloneQueue.clear(); } long elapsedTime = System.currentTimeMillis() - startTime; if (verbose) { showAndLog("Target records for " + testCase.getId() + " :"); for (Record rec : testCase.getObservedTargetRecords()) showAndLog(rec.toString()); showAndLog("Error records for " + testCase.getId() + " :"); for (Record rec : testCase.getObservedErrorRecords()) showAndLog(rec.toString()); showAndLog("Testing " + testCase.getId() + " took " + elapsedTime + " ms."); } if (elapsedTime > testCase.getTimeout()) { LOG.error("Processing test " + testCase.getId() + " timed out."); return false; } else return true; } private List<Record> createErrorRecords(Record record) { List<Record> errorRecords = new ArrayList<Record>(); for (CheckResult c : record.getErrors()) { // Flatten tree to list and assign keys List<CheckTreeItem> results = CheckTreeItem.flatten(c, nodeKeyGenerator, -1); for (CheckTreeItem treeItem : results) { Record errorRecord = new ImmutableErrorRecordImpl(record, treeItem); errorRecords.add(errorRecord); } } return errorRecords; } private boolean check(TestCase testCase) { return checkErrorRecords(testCase) && checkTargetRecords(testCase); } private boolean checkErrorRecords(TestCase testCase) { for (Record expected : testCase.getExpectedErrorRecords()) { boolean fit = false; for (Record observed : testCase.getObservedErrorRecords()) { if (TestUtil.fit(expected, observed)) { fit = true; break; } } if (!fit) { LOG.error("Expected error record " + expected.toString() + " does not match any of the observed error recods of test " + testCase.getId() + "."); return false; } } return true; } private boolean checkTargetRecords(TestCase testCase) { List<Record> expectedRecords = testCase.getExpectedTargetRecords(); List<Record> observedRecords = testCase.getObservedTargetRecords(); if (observedRecords.size() != expectedRecords.size()) { LOG.error("Size of observed target records do not match size of expected ones in test " + testCase.getId() + "."); return false; } int size = expectedRecords.size(); boolean[][] graphOfRecords = new boolean[size][size]; for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { graphOfRecords[i][j] = TestUtil.fit(expectedRecords.get(i), observedRecords.get(j)); } } int maxMatching = MaxMatching.maxMatching(graphOfRecords); boolean check = (maxMatching == size); if (!check) LOG.error("Observed target records do not match expected ones in test " + testCase.getId() + "."); return check; } public boolean testAll() { for (TestCase testCase : longneckProcess.getTestCases()) { if (!process(testCase) || !check(testCase)) { LOG.error("Test " + testCase.getId() + " failed."); return false; } } return true; } public void showAndLog(String message) { LOG.debug(message); System.out.println(message); } }