Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/test-windows-webdriver.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,15 @@ jobs:
name: Java${{ matrix.java }}-runTestWebdriverSuspiciousTagStateModel-artifact
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_and_suspicious

- name: Run webdriver to detect a browser console error in parabank
run: ./gradlew runTestWebdriverParabankConsoleError
- name: Save runTestWebdriverParabankConsoleError HTML report artifact
- name: Run webdriver to detect a browser console error and accessibility warning in parabank
run: ./gradlew runTestWebdriverParabankConsoleErrorAndAccessibilityWarning
- name: Save runTestWebdriverParabankConsoleErrorAndAccessibilityWarning HTML report artifact
uses: actions/upload-artifact@v4
# Only upload GitHub Actions results if this task fails (Can be replaced with 'if: always()')
if: failure()
with:
name: Java${{ matrix.java }}-runTestWebdriverParabankConsoleError-artifact
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_console_error
name: Java${{ matrix.java }}-runTestWebdriverParabankConsoleErrorAndAccessibilityWarning-artifact
path: D:/a/TESTAR_dev/TESTAR_dev/testar/target/install/testar/bin/webdriver_console_error_and_accessibility_warning

- name: Run webdriver to login in parabank and detect a welcome suspicious tag
run: ./gradlew runTestWebdriverParabankLogin
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ Some of the most interesting parameters that can help to integrate TESTAR as an

ShowVisualSettingsDialogOnStartup -> To run TESTAR without the GUI

Mode -> TESTAR execution Mode (Spy, Generate, Record, Replay, View)
Mode -> TESTAR execution Mode (Spy, Generate, Replay, View)

SUTConnector & SUTConnectorValue -> The way to link with the desired application to be tested

Expand Down
8 changes: 5 additions & 3 deletions core/src/org/testar/ProtocolUtil.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/***************************************************************************************************
*
* Copyright (c) 2016 - 2025 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2019 - 2025 Open Universiteit - www.ou.nl
* Copyright (c) 2016 - 2026 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2019 - 2026 Open Universiteit - www.ou.nl
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand Down Expand Up @@ -49,6 +49,7 @@
import org.testar.monkey.alayer.Widget;

import java.awt.*;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -251,7 +252,8 @@ public static AWTCanvas getStateshotBinary(State state) {
}

//If the state Shape is not properly obtained, or the State has an error, use full monitor screen
if (viewPort == null || (state.get(Tags.OracleVerdict, Verdict.OK).severity() > Verdict.Severity.OK.getValue()))
List<Verdict> verdicts = state.get(Tags.OracleVerdicts, Collections.singletonList(Verdict.OK));
if (viewPort == null || !Verdict.helperAreAllVerdictsOK(verdicts))
viewPort = state.get(Tags.Shape, null); // get the SUT process canvas (usually, full monitor screen)

// Validate viewport dimensions before taking the screenshot
Expand Down
14 changes: 5 additions & 9 deletions core/src/org/testar/monkey/alayer/Tags.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/***************************************************************************************************
*
* Copyright (c) 2013 - 2025 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2018 - 2025 Open Universiteit - www.ou.nl
* Copyright (c) 2013 - 2026 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2018 - 2026 Open Universiteit - www.ou.nl
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand All @@ -28,10 +28,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************************************/

/**
* @author Sebastian Bauersfeld
*/

package org.testar.monkey.alayer;

import org.testar.CodingManager;
Expand Down Expand Up @@ -161,9 +157,9 @@ private Tags() {}
/** Usually attached to an object of {@link State}. The value is a screenshot of the state. */
public static final Tag<String> ScreenshotPath = from("ScreenshotPath", String.class);

/** Usually attached to a {@link State} object. The value is an outcome of a test oracle for that state. It is
* used to mark states as 'suspicious' or 'erroneous' */
public static final Tag<Verdict> OracleVerdict = from("OracleVerdict", Verdict.class);
/** Usually attached to a {@link State} object. The value is a list of outcomes of test oracles for that state. */
@SuppressWarnings("unchecked")
public static final Tag<List<Verdict>> OracleVerdicts = from("OracleVerdicts", (Class<List<Verdict>>)(Class<?>)List.class);

/** The standard mouse object. Usually attached to systems */
public static final Tag<Mouse> StandardMouse = from("StandardMouse", Mouse.class);
Expand Down
48 changes: 27 additions & 21 deletions core/src/org/testar/monkey/alayer/Verdict.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
package org.testar.monkey.alayer;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.testar.monkey.Assert;
import org.testar.monkey.Util;
Expand Down Expand Up @@ -93,12 +95,16 @@ public enum Severity {
// WARNING GROUP: ACCESSIBILITY
WARNING_ACCESSIBILITY_FAULT(0.4, "WARNING_ACCESSIBILITY_FAULT"),

/** FAIL (0.5 - 1.0) **/
/** FAIL (0.5 - 0.899) **/

UNREPLAYABLE(0.5, "UNREPLAYABLE"), // Sequence not replayable
SUSPICIOUS_TAG(0.8, "SUSPICIOUS_TAG"), // Suspicious tag
SUSPICIOUS_PROCESS(0.87, "SUSPICIOUS_PROCESS"), // Suspicious message in the process standard output/error
SUSPICIOUS_LOG(0.89, "SUSPICIOUS_LOG"), // Suspicious message in log file or command output (LogOracle)

/** CRITICAL (0.9 - 1.0) **/

CRITICAL(0.9, "CRITICAL"),
NOT_RESPONDING(0.99999990, "NOT_RESPONDING"), // Unresponsive
UNEXPECTEDCLOSE(0.99999999, "UNEXPECTEDCLOSE"), // Crash? Unexpected close?
FAIL(1.0, "FAIL");
Expand Down Expand Up @@ -193,29 +199,18 @@ public Visualizer visualizer() {
return visualizer;
}

@Override
public String toString() {
return "severity: " + severity + " info: " + info;
}

/**
* Retrieves the verdict result of joining two verdicts.
* @param verdict A verdict to join with current verdict.
*
* @return A new verdict that is the result of joining the current verdict with the provided verdict.
* Indicates if this verdict is critical (SUT froze or crashed).
*
* @return true if verdict is critical
*/
public Verdict join(Verdict verdict) {
Severity joinedSeverity = Arrays.stream(Severity.values())
.filter(s -> s.getValue() == Math.max(this.severity, verdict.severity()))
.findFirst()
.orElse(Severity.FAIL);

String joinedInfo = this.info.contains(verdict.info()) ? this.info
: (this.severity == Severity.OK.getValue() ? "" : this.info + "\n") + verdict.info();

Visualizer joinedVisualizer = Visualizer.join(this.visualizer(), verdict.visualizer());
public boolean isCritical() {
return this.severity() >= Severity.CRITICAL.getValue();
}

return new Verdict(joinedSeverity, joinedInfo, joinedVisualizer);
@Override
public String toString() {
return "severity: " + severity + " info: " + info;
}

/**
Expand All @@ -234,4 +229,15 @@ public boolean equals(Object o) {
&& this.visualizer.equals(other.visualizer);
}

public static boolean helperAreAllVerdictsOK(List<Verdict> verdicts) {
if(verdicts == null || verdicts.isEmpty()) return true;

for (Verdict verdict : verdicts) {
if (verdict.severity() > Severity.OK.getValue()) {
return false;
}
}
return true;
}

}
66 changes: 5 additions & 61 deletions core/test/org/testar/monkey/alayer/VerdictTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,16 @@
import java.util.Arrays;

import org.junit.Test;
import org.testar.monkey.alayer.visualizers.RegionsVisualizer;
import org.testar.monkey.alayer.visualizers.ShapeVisualizer;

public class VerdictTest {

private final double DELTA = 0;

private final Visualizer dummyVisualizer = new Visualizer(){
private static final long serialVersionUID = -7830649624698071090L;
public void run(State s, Canvas c, Pen pen) {}
};

private final Visualizer failVisualizer = new ShapeVisualizer(
Pen.PEN_RED,
Rect.from(0, 0, 10, 10),
"Fail Visualizer",
0.5, 0.5);

private final Visualizer issueVisualizer = new RegionsVisualizer(
Pen.PEN_RED,
Arrays.asList(Rect.from(0, 0, 10, 10)),
"Issue Visualizer",
0.5, 0.5);

@Test
public void testToString() {
Verdict v = new Verdict(Verdict.Severity.OK, "This is a test verdict");
Expand All @@ -67,54 +53,12 @@ public void testToString() {
}

@Test
public void testJoin() {
Verdict v1 = new Verdict(Verdict.Severity.OK, "Foo Bar");
Verdict v2 = new Verdict(Verdict.Severity.FAIL, "Bar", failVisualizer);
Verdict v3 = new Verdict(Verdict.Severity.OK, "Baz", dummyVisualizer);
Verdict v4 = new Verdict(Verdict.Severity.FAIL, "Exception", issueVisualizer);
Verdict emptyVisualizerVerdict = new Verdict(Verdict.Severity.FAIL, "Empty");

assertTrue("Joining two Verdicts shall create a new Verdict",
v1 != v1.join(v2));

assertEquals("Joining two Verdicts shall set the severity to the maximum of both",
Verdict.Severity.FAIL.getValue(), v3.join(v2).severity(), DELTA);

assertEquals("If a Verdict's info contains the info of the Verdict to be joined with, " +
"then only the containing info shall be used",
"Foo Bar", v1.join(v2).info());

assertEquals("If a Verdict is OK and its info does not contain the info of the Verdict to be joined with, " +
"then the containing info shall be discarded",
"Baz", v1.join(v3).info());

assertEquals("If a Verdict is not OK and its info does not contain the info of the Verdict to be joined with, " +
"then both infos shall be included separated by a line break",
"Bar\nBaz", v2.join(v3).info());

assertTrue("Joining an OK and Fail Verdicts shall use the Visualizer of the Verdict with high severity",
v2.join(v1).visualizer() == failVisualizer);

assertTrue("Joining an OK and Fail Verdicts shall use the Visualizer of the Verdict with high severity",
v1.join(v2).visualizer() == failVisualizer);

assertTrue("Joining Fail and Issue Verdicts must contain Fail Shapes",
v2.join(v4).visualizer().getShapes().containsAll(failVisualizer.getShapes()));

assertTrue("Joining Issue and Fail Verdicts must contain Fail Shapes",
v4.join(v2).visualizer().getShapes().containsAll(failVisualizer.getShapes()));

assertTrue("Joining Fail and Issue Verdicts must contain Issue Shapes",
v2.join(v4).visualizer().getShapes().containsAll(issueVisualizer.getShapes()));

assertTrue("Joining Issue and Fail Verdicts must contain Issue Shapes",
v4.join(v2).visualizer().getShapes().containsAll(issueVisualizer.getShapes()));

assertTrue("Joining Fail and emptyVisualizerVerdict Verdicts must equal Fail visualizer",
v2.join(emptyVisualizerVerdict).visualizer() == failVisualizer);
public void testVerdictHelperAreOK() {
Verdict ok = Verdict.OK;
Verdict warn = new Verdict(Verdict.Severity.SUSPICIOUS_TAG, "Issue", failVisualizer);

assertTrue("Joining emptyVisualizerVerdict and Fail Verdicts must equal Fail visualizer",
emptyVisualizerVerdict.join(v2).visualizer() == failVisualizer);
assertTrue(Verdict.helperAreAllVerdictsOK(Arrays.asList(ok)));
assertFalse(Verdict.helperAreAllVerdictsOK(Arrays.asList(warn)));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/***************************************************************************************************
*
* Copyright (c) 2018 - 2025 Open Universiteit - www.ou.nl
* Copyright (c) 2018 - 2025 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2018 - 2026 Open Universiteit - www.ou.nl
* Copyright (c) 2018 - 2026 Universitat Politecnica de Valencia - www.upv.es
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand Down Expand Up @@ -39,6 +39,10 @@
import org.testar.statemodel.persistence.orientdb.entity.TypeConvertor;
import org.testar.statemodel.persistence.orientdb.entity.VertexEntity;
import org.testar.statemodel.persistence.orientdb.util.Validation;

import java.util.Collections;
import java.util.List;

import org.testar.monkey.alayer.Tag;
import org.testar.monkey.alayer.TaggableBase;
import org.testar.monkey.alayer.Tags;
Expand Down Expand Up @@ -89,18 +93,13 @@ public void hydrate(VertexEntity target, Object source) throws HydrationExceptio
}

// get the oracle verdict and transform it into a custom code
Verdict verdict = attributes.get(Tags.OracleVerdict, null);
List<Verdict> verdicts = attributes.get(Tags.OracleVerdicts, Collections.singletonList(Verdict.OK));
int oracleVerdictCode = 4; // default value
if (verdict != null) {
if (verdict.severity() == Verdict.Severity.OK.getValue()) {
oracleVerdictCode = 1;
}
else if (verdict.severity() == Verdict.Severity.FAIL.getValue()) {
oracleVerdictCode = 2;
}
else if (verdict.severity() > Verdict.Severity.OK.getValue() && verdict.severity() < Verdict.Severity.FAIL.getValue()) {
oracleVerdictCode = 3;
}
if (Verdict.helperAreAllVerdictsOK(verdicts)) {
oracleVerdictCode = 1;
}
else {
oracleVerdictCode = 2;
}
target.addPropertyValue("oracleVerdictCode", new PropertyValue(OType.INTEGER, oracleVerdictCode));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/***************************************************************************************************
*
* Copyright (c) 2020 - 2023 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2020 - 2023 Open Universiteit - www.ou.nl
* Copyright (c) 2020 - 2026 Universitat Politecnica de Valencia - www.upv.es
* Copyright (c) 2020 - 2026 Open Universiteit - www.ou.nl
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
Expand Down Expand Up @@ -41,6 +41,7 @@
import org.testar.protocols.DesktopProtocol;
import org.testar.settings.Settings;

import java.util.List;
import java.util.Set;

/**
Expand Down Expand Up @@ -118,18 +119,18 @@ protected State getState(SUT system) throws StateBuildException{
* @return oracle verdict, which determines whether the state is erroneous and why.
*/
@Override
protected Verdict getVerdict(State state){
protected List<Verdict> getVerdicts(State state){
// The super methods implements the implicit online state oracles for:
// system crashes
// non-responsiveness
// suspicious tags
Verdict verdict = super.getVerdict(state);
List<Verdict> verdicts = super.getVerdicts(state);

//--------------------------------------------------------
// MORE SOPHISTICATED STATE ORACLES CAN BE PROGRAMMED HERE
//--------------------------------------------------------

return verdict;
return verdicts;
}

/**
Expand Down
Loading