import org.argeo.slc.ant.structure.SAwareTask;\r
import org.argeo.slc.core.deploy.DeployedSystem;\r
import org.argeo.slc.core.structure.StructureAware;\r
+import org.argeo.slc.core.test.ExecutableTestRun;\r
import org.argeo.slc.core.test.TestData;\r
import org.argeo.slc.core.test.TestDefinition;\r
import org.argeo.slc.core.test.TestResult;\r
getPath());\r
}\r
\r
- testRun.execute();\r
+ ((ExecutableTestRun)testRun).execute();\r
}\r
\r
/**\r
--- /dev/null
+package org.argeo.slc.core;\r
+\r
+public class UnsupportedException extends SlcException {\r
+ static final long serialVersionUID = 1l;\r
+\r
+ public UnsupportedException(String message) {\r
+ super(message);\r
+ }\r
+\r
+ public UnsupportedException(String nature, Object obj) {\r
+ super("Unsupported " + nature + ": " + obj.getClass());\r
+ }\r
+\r
+ public UnsupportedException(String nature, String value) {\r
+ super("Unsupported " + nature + ": " + value);\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.core.test;\r
+\r
+/** A test run that can be executed*/\r
+public interface ExecutableTestRun extends TestRun{\r
+\r
+ /** Executes this test run. */\r
+ public void execute();\r
+\r
+}\r
* </p>\r
*/\r
public class SimpleResultPart implements TestResultPart {\r
-\r
- /** The flag for a passed test: 1 */\r
- public final static int PASSED = 1;\r
- /** The flag for a failed test: 2 */\r
- public final static int FAILED = 2;\r
- /** The flag for a test which could not properly run because of an error: 3 */\r
- public final static int ERROR = 3;\r
-\r
/** For ORM */\r
private Long tid;\r
\r
- private Integer status;\r
+ private TestStatus status;\r
private String message;\r
private Throwable exception;\r
\r
+ \r
+ /** Empty constructor for ORM */\r
+ public SimpleResultPart(){\r
+ \r
+ }\r
+ \r
+ public SimpleResultPart(TestStatus status, String message,\r
+ Throwable exception) {\r
+ super();\r
+ this.status = status;\r
+ this.message = message;\r
+ this.exception = exception;\r
+ }\r
+\r
public String getMessage() {\r
return message;\r
}\r
this.message = message;\r
}\r
\r
- public void setStatus(Integer status) {\r
+ public void setStatus(TestStatus status) {\r
this.status = status;\r
}\r
\r
- public Integer getStatus() {\r
+ public TestStatus getStatus() {\r
return status;\r
}\r
\r
@Override\r
public String toString() {\r
StringBuffer buf = new StringBuffer("");\r
- if (status == PASSED) {\r
- buf.append("PASSED ");\r
- } else if (status == FAILED) {\r
- buf.append("FAILED ");\r
- } else if (status == ERROR) {\r
- buf.append("ERROR ");\r
- }\r
+ buf.append(status).append(" ");\r
buf.append(message);\r
if (exception != null) {\r
buf.append("(").append(exception.getMessage()).append(")");\r
--- /dev/null
+package org.argeo.slc.core.test;\r
+\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+\r
+public class SimpleTestResult implements TestResult {\r
+ private static Log log = LogFactory.getLog(SimpleTestResult.class);\r
+\r
+ private TestResultId testResultId;\r
+ private List<TestResultPart> parts = new Vector<TestResultPart>();\r
+\r
+ public void addResultPart(TestResultPart part) {\r
+ parts.add(part);\r
+ if (log.isDebugEnabled())\r
+ log.debug(part);\r
+ }\r
+\r
+ public void close() {\r
+ parts.clear();\r
+ }\r
+\r
+ public TestResultId getTestResultId() {\r
+ return testResultId;\r
+ }\r
+\r
+ public void setTestResultId(TestResultId testResultId) {\r
+ this.testResultId = testResultId;\r
+ }\r
+\r
+ public List<TestResultPart> getParts() {\r
+ return parts;\r
+ }\r
+\r
+}\r
* A basic bean implementation of a <code>WritableTestRun</code>, holding\r
* references to the various parts of a test run.\r
*/\r
-public class SimpleTestRun implements WritableTestRun {\r
+public class SimpleTestRun implements WritableTestRun, ExecutableTestRun {\r
private DeployedSystem deployedSystem;\r
private TestData testData;\r
private TestDefinition testDefinition;\r
* @see TestResult\r
*/\r
public interface TestResultPart {\r
+ public TestStatus getStatus();\r
\r
+ public String getMessage();\r
}\r
\r
/** Gets the related result where to record results. */\r
public TestResult getTestResult();\r
-\r
- /** Executes this test run. */\r
- public void execute();\r
}\r
--- /dev/null
+package org.argeo.slc.core.test;\r
+\r
+/** Simple statuses. */\r
+public enum TestStatus {\r
+ /** Test passed */\r
+ PASSED,\r
+ /** Test failed: the behavior was not the expected one */\r
+ FAILED,\r
+ /**\r
+ * Test could not run properly because of an unexpected issue: their can be\r
+ * no feedback on the behavior of the tested component\r
+ */\r
+ ERROR\r
+}\r
import org.argeo.slc.core.structure.StructureRegistry;\r
import org.argeo.slc.core.structure.tree.TreeSPath;\r
import org.argeo.slc.core.test.SimpleResultPart;\r
+import org.argeo.slc.core.test.TestStatus;\r
import org.argeo.slc.core.test.TestReport;\r
import org.argeo.slc.core.test.TestResult;\r
import org.argeo.slc.core.test.TestResultPart;\r
for (TestResultPart part : subList.getParts()) {\r
SimpleResultPart sPart = (SimpleResultPart) part;\r
String color = "yellow";\r
- if (sPart.getStatus() == SimpleResultPart.PASSED) {\r
+ if (sPart.getStatus() == TestStatus.PASSED) {\r
color = "green";\r
} else {\r
color = "red";\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/**\r
+ * Converts data into a format better adapted for comparison. It is typically\r
+ * used to convert <code>String</code> into typed format such as\r
+ * <code>BigDecimal</code>\r
+ */\r
+public interface DataInterpreter {\r
+ /**\r
+ * Converts data\r
+ * \r
+ * @param key\r
+ * any object used to differentiate the type of data (e.g.\r
+ * column, path)\r
+ * @param value\r
+ * the data to convert\r
+ * @return the converted object\r
+ */\r
+ public Object convert(Object key, Object value);\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+import org.springframework.core.io.Resource;\r
+\r
+/** A comparator providing structured information about the differences found. */\r
+public interface Diff {\r
+ /** Performs the comparison. */\r
+ public DiffResult compare(Resource expected, Resource reached);\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/** The root class for issues which happened during a diff. */\r
+public abstract class DiffIssue implements Comparable<DiffIssue> {\r
+ protected final DiffPosition position;\r
+\r
+ public DiffIssue(DiffPosition position) {\r
+ super();\r
+ this.position = position;\r
+ }\r
+\r
+ public int compareTo(DiffIssue o) {\r
+ return position.compareTo(o.position);\r
+ }\r
+\r
+ /** The position of this issue within the test file */\r
+ public DiffPosition getPosition() {\r
+ return position;\r
+ }\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/**\r
+ * Object able to uniquely identify an atomic diff part. Used to identify\r
+ * missings and left-overs.\r
+ */\r
+public interface DiffKey {\r
+ public String toString();\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+\r
+/**\r
+ * A value missing in one of the file. If its position is related to expected,\r
+ * this means it is a left over in the reached, if its position is related to\r
+ * the reached it means that it is missing from the reached. If the value is\r
+ * null it means that the entire line is missing.\r
+ */\r
+public class DiffMissing extends DiffIssue {\r
+ private final DiffKey key;\r
+\r
+ public DiffMissing(DiffPosition position, DiffKey key) {\r
+ super(position);\r
+ this.key = key;\r
+ }\r
+\r
+ public Object getKey() {\r
+ return key;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ if (position.relatedFile == RelatedFile.EXPECTED) {\r
+ return position + ": left over " + key;\r
+ }\r
+ else if (position.relatedFile == RelatedFile.REACHED) {\r
+ return position + ": missing " + key;\r
+ }\r
+ return super.toString();\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/** Diff issue where reached and expected values are different. */\r
+public class DiffNotMatched extends DiffIssue {\r
+ private final Object expected;\r
+ private final Object reached;\r
+\r
+ public DiffNotMatched(DiffPosition position, Object expected, Object reached) {\r
+ super(position);\r
+ this.expected = expected;\r
+ this.reached = reached;\r
+ }\r
+\r
+ public Object getExpected() {\r
+ return expected;\r
+ }\r
+\r
+ public Object getReached() {\r
+ return reached;\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return position + ": not matched " + expected + " <> " + reached;\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/** The position of a diff issue within the test resource. */\r
+public abstract class DiffPosition implements Comparable<DiffPosition> {\r
+ protected RelatedFile relatedFile;\r
+\r
+ public DiffPosition(RelatedFile relatedFile) {\r
+ super();\r
+ this.relatedFile = relatedFile;\r
+ }\r
+\r
+ public RelatedFile getRelatedFile() {\r
+ return relatedFile;\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+import java.util.List;\r
+\r
+/**\r
+ * The result of a diff. Can be subclassed to provided more structured\r
+ * information.\r
+ */\r
+public interface DiffResult {\r
+ /** The list of issues, a zero size meaning that the diff succeeded. */\r
+ public List<DiffIssue> getIssues();\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/** Enumeration of the types of resource tested. */\r
+public enum RelatedFile {\r
+ /** The expected resource */\r
+ EXPECTED,\r
+ /** The reached resource */\r
+ REACHED\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+import java.util.List;\r
+import java.util.Vector;\r
+\r
+/** A basic implementation of <code>DiffResult</code>.*/\r
+public class SimpleDiffResult implements DiffResult {\r
+ private List<DiffIssue> issues = new Vector<DiffIssue>();\r
+\r
+ public List<DiffIssue> getIssues() {\r
+ return issues;\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+import org.argeo.slc.core.UnsupportedException;\r
+\r
+/**\r
+ * A diff position within a table structure such a CSV file or an SQL result\r
+ * set.\r
+ */\r
+public class TableDiffPosition extends DiffPosition {\r
+ private Integer line;\r
+ /** Can be null */\r
+ private Integer column;\r
+ /** Can be null */\r
+ private String columnName;\r
+\r
+ public TableDiffPosition(RelatedFile relatedFile, Integer line,\r
+ Integer column, String columnName) {\r
+ super(relatedFile);\r
+ this.line = line;\r
+ this.column = column;\r
+ this.columnName = columnName;\r
+ }\r
+\r
+ public Integer getLine() {\r
+ return line;\r
+ }\r
+\r
+ public Integer getColumn() {\r
+ return column;\r
+ }\r
+\r
+ public String getColumnName() {\r
+ return columnName;\r
+ }\r
+\r
+ public int compareTo(DiffPosition dp) {\r
+ if (!(dp instanceof TableDiffPosition))\r
+ throw new UnsupportedException("position", dp);\r
+\r
+ TableDiffPosition o = (TableDiffPosition) dp;\r
+ if (relatedFile.equals(o.relatedFile)) {\r
+ if (line == o.line) {\r
+ return column.compareTo(o.column);\r
+ } else {\r
+ return line.compareTo(o.line);\r
+ }\r
+ } else {\r
+ return relatedFile.compareTo(o.relatedFile);\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ StringBuffer buf = new StringBuffer("");\r
+ buf.append(relatedFile).append('[').append(line);\r
+ if (column != null) {\r
+ buf.append(',').append(column);\r
+ if (columnName != null) {\r
+ buf.append('-').append(columnName);\r
+ }\r
+ }\r
+ buf.append(']');\r
+ return buf.toString();\r
+ }\r
+\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+/** Compares objects, eventually using tolerance mechanisms. */\r
+public interface Tolerance {\r
+ /**\r
+ * Compares objects\r
+ * \r
+ * @param key\r
+ * any object used to differentiate the type of data (e.g.\r
+ * column, path)\r
+ * @param expected\r
+ * the expected value\r
+ * @param reached\r
+ * the reached value\r
+ * @return the converted object\r
+ */\r
+ public Boolean compare(Object key, Object expected, Object reached);\r
+}\r
--- /dev/null
+package org.argeo.slc.diff;\r
+\r
+import org.argeo.slc.core.UnsupportedException;\r
+\r
+/** A diff position within an Xml file. <b>NOT YET IMPLEMENTED</b>.*/\r
+public class XPathDiffPosition extends DiffPosition {\r
+\r
+ private String xPath;\r
+\r
+ public XPathDiffPosition(RelatedFile relatedFile, String path) {\r
+ super(relatedFile);\r
+ xPath = path;\r
+ }\r
+\r
+ public int compareTo(DiffPosition dp) {\r
+ if (!(dp instanceof XPathDiffPosition))\r
+ throw new UnsupportedException("position", dp);\r
+\r
+ XPathDiffPosition o = (XPathDiffPosition) dp;\r
+ if (relatedFile.equals(o.relatedFile)) {\r
+ return xPath.compareTo(o.xPath);\r
+ } else {\r
+ return relatedFile.compareTo(o.relatedFile);\r
+ }\r
+ }\r
+\r
+}\r
import org.argeo.slc.core.structure.StructureRegistry;\r
import org.argeo.slc.core.structure.tree.TreeSPath;\r
import org.argeo.slc.core.test.SimpleResultPart;\r
+import org.argeo.slc.core.test.TestStatus;\r
import org.argeo.slc.core.test.TestDefinition;\r
import org.argeo.slc.core.test.TestResult;\r
import org.argeo.slc.core.test.TestRun;\r
\r
public void execute(TestRun testRun) {\r
SimpleResultPart part = new SimpleResultPart();\r
- part.setStatus(SimpleResultPart.PASSED);\r
+ part.setStatus(TestStatus.PASSED);\r
part.setMessage("Sub task with path " + path + " executed");\r
\r
TestResult result = testRun.getTestResult();\r
import org.apache.commons.logging.LogFactory;\r
\r
import org.argeo.slc.core.test.SimpleResultPart;\r
+import org.argeo.slc.core.test.TestStatus;\r
import org.argeo.slc.core.test.TestDefinition;\r
import org.argeo.slc.core.test.TestResult;\r
import org.argeo.slc.core.test.TestResultPart;\r
// execute\r
appli.filter(args);\r
\r
- executePart.setStatus(SimpleResultPart.PASSED);\r
+ executePart.setStatus(TestStatus.PASSED);\r
} catch (Exception e) {\r
- executePart.setStatus(SimpleResultPart.ERROR);\r
+ executePart.setStatus(TestStatus.ERROR);\r
executePart.setException(e);\r
}\r
result.addResultPart(executePart);\r
- if (executePart.getStatus() == SimpleResultPart.ERROR) {\r
+ if (executePart.getStatus() == TestStatus.ERROR) {\r
return;\r
}\r
\r
try {\r
String expected = loadFile(data.getExpectedFile());\r
String reached = loadFile(data.getReachedFile());\r
- part.setStatus(expected.equals(reached) ? SimpleResultPart.PASSED\r
- : SimpleResultPart.FAILED);\r
+ part.setStatus(expected.equals(reached) ? TestStatus.PASSED\r
+ : TestStatus.FAILED);\r
} catch (Exception e) {\r
- part.setStatus(SimpleResultPart.ERROR);\r
+ part.setStatus(TestStatus.ERROR);\r
part.setException(e);\r
log.error("Error while asserting files", e);\r
}\r