Skip to content
Merged
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
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
#TESTAR v2.7.21 (24-Feb-2026)
- Bump org.seleniumhq.selenium:selenium-java from 4.40.0 to 4.41.0
- Update devtools dependencies to v145
- Ignore dynamic numbers when deduplicating AndroidLogcatOracle messages


#TESTAR v2.7.21 (17-Feb-2026)
- Add logic to detect Android logcat suspicious messages
- Refactor the GenerateMode logic to report initialState issues
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.21
2.7.22
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ subprojects {
implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.15.0'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.15.0'
// https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java
implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.40.0'
implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '4.41.0'
// https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager
implementation group: 'io.github.bonigarcia', name: 'webdrivermanager', version: '6.3.3'
// https://mvnrepository.com/artifact/io.appium/java-client
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
import org.openqa.selenium.WebElement;
import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.HasDevTools;
import org.openqa.selenium.devtools.v144.network.Network;
import org.openqa.selenium.devtools.v145.network.Network;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testar.SutVisualization;
Expand Down
2 changes: 1 addition & 1 deletion testar/src/org/testar/monkey/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

public class Main {

public static final String TESTAR_VERSION = "v2.7.21 (17-Feb-2026)";
public static final String TESTAR_VERSION = "v2.7.22 (24-Feb-2026)";

//public static final String TESTAR_DIR_PROPERTY = "DIRNAME"; //Use the OS environment to obtain TESTAR directory
public static final String SETTINGS_FILE = "test.settings";
Expand Down
38 changes: 34 additions & 4 deletions testar/src/org/testar/oracles/log/AndroidLogcatOracle.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,22 +185,52 @@ private List<String> detectRegexMatches(List<String> lines, String regex) {

// logcat threadtime format:
// 02-09 08:59:33.844 17550 17575 E Accessibility exception content...
private static final Pattern THREADTIME_PATTERN = Pattern.compile(
private final Pattern THREADTIME_PATTERN = Pattern.compile(
"^\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\s+\\d+\\s+\\d+\\s+([VDIWEAF])\\s+([^:]+):\\s*(.*)$"
);

private static String normalizeThreadtimeLine(String line) {
private String normalizeThreadtimeLine(String line) {
if (line == null) return "";
line = line.trim();
Matcher m = THREADTIME_PATTERN.matcher(line);
if (!m.matches()) {
return line.replaceAll("\\s+", " ");
return normalizeNumbers(line.replaceAll("\\s+", " "));
}

String tag = m.group(2).trim();
String msg = m.group(3).trim().replaceAll("\\s+", " ");
String msg = normalizeNumbers(m.group(3).trim().replaceAll("\\s+", " "));

return tag + ": " + msg;
}

private String normalizeNumbers(String text) {
if (text == null || text.isEmpty()) {
return "";
}
Matcher matcher = Pattern.compile("\\d+").matcher(text);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String num = matcher.group();
if (isHttpFailureStatus(num)) {
matcher.appendReplacement(sb, num);
} else {
matcher.appendReplacement(sb, "<num>");
}
}
matcher.appendTail(sb);
return sb.toString();
}

private boolean isHttpFailureStatus(String num) {
if (num.length() != 3) {
return false;
}
try {
int value = Integer.parseInt(num);
return value >= 300 && value <= 599;
} catch (NumberFormatException e) {
return false;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
package org.testar.securityanalysis.oracles;

import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v144.network.Network;
import org.openqa.selenium.devtools.v144.network.model.Headers;
import org.openqa.selenium.devtools.v145.network.Network;
import org.openqa.selenium.devtools.v145.network.model.Headers;
import org.testar.monkey.alayer.Verdict;
import org.testar.monkey.alayer.webdriver.WdDriver;
import org.testar.securityanalysis.NetworkCollector;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
package org.testar.securityanalysis.oracles;

import org.openqa.selenium.devtools.DevTools;
import org.openqa.selenium.devtools.v144.network.Network;
import org.openqa.selenium.devtools.v145.network.Network;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testar.monkey.alayer.*;
import org.testar.monkey.alayer.actions.WdSecurityInjectionAction;
Expand Down
57 changes: 57 additions & 0 deletions testar/test/org/testar/oracles/log/TestAndroidLogcatOracle.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,63 @@ public void generateModeVerdict_DeduplicatesAndOrdersMatches() {
}
}

@Test
public void generateModeVerdict_DeduplicatesNumbersInMatches() {
OutputStructure.logsOutputDir = Path.of("target").toString();
OutputStructure.startInnerLoopDateString = "YYYY-MM-DD_hh-mm-ss";
OutputStructure.executedSUTname = "test-sut";

Settings settings = buildSettings(RuntimeControlsProtocol.Modes.Generate, "(?i)(.*Exception.*)");
AndroidLogcatOracle androidLogcatOracle = new AndroidLogcatOracle(settings);
State state = Mockito.mock(State.class);

String line1 = "02-09 08:59:33.844 17550 17575 E ViewRootImpl: Exception @1:207875, unable to find 3421 viewState";
String line2 = "02-09 08:59:33.845 17550 17575 E ViewRootImpl: Exception @1:204868, unable to find 9008 viewState";

try (MockedStatic<AndroidAppiumFramework> mocked = Mockito.mockStatic(AndroidAppiumFramework.class)) {
mocked.when(AndroidAppiumFramework::getAppPackageFromCapabilitiesOrCurrent).thenReturn("org.testar.app");
mocked.when(() -> AndroidAppiumFramework.dumpLogcatThreadtimeForPackage("org.testar.app"))
.thenReturn(line1 + "\n" + line2);

androidLogcatOracle.initialize();
Verdict verdict = androidLogcatOracle.getVerdict(state);

Assert.assertEquals(Verdict.Severity.SUSPICIOUS_LOG.getValue(), verdict.severity(), 0.0);
String expected = "Suspicious Android logcat line(s) detected "
+ "ViewRootImpl: Exception @<num>:<num>, unable to find <num> viewState";
Assert.assertEquals(expected, verdict.info());
}
}

@Test
public void generateModeVerdict_KeepsHttpStatusCodes() {
OutputStructure.logsOutputDir = Path.of("target").toString();
OutputStructure.startInnerLoopDateString = "YYYY-MM-DD_hh-mm-ss";
OutputStructure.executedSUTname = "test-sut";

Settings settings = buildSettings(RuntimeControlsProtocol.Modes.Generate, "(?i)(.*Exception.*)");
AndroidLogcatOracle androidLogcatOracle = new AndroidLogcatOracle(settings);
State state = Mockito.mock(State.class);

String line1 = "02-09 08:59:33.844 17550 17575 E ViewRootImpl: Exception, http status 404";
String line2 = "02-09 08:59:33.845 17550 17575 E ViewRootImpl: Exception, http status 503";

try (MockedStatic<AndroidAppiumFramework> mocked = Mockito.mockStatic(AndroidAppiumFramework.class)) {
mocked.when(AndroidAppiumFramework::getAppPackageFromCapabilitiesOrCurrent).thenReturn("org.testar.app");
mocked.when(() -> AndroidAppiumFramework.dumpLogcatThreadtimeForPackage("org.testar.app"))
.thenReturn(line1 + "\n" + line2);

androidLogcatOracle.initialize();
Verdict verdict = androidLogcatOracle.getVerdict(state);

Assert.assertEquals(Verdict.Severity.SUSPICIOUS_LOG.getValue(), verdict.severity(), 0.0);
String expected = "Suspicious Android logcat line(s) detected "
+ "ViewRootImpl: Exception, http status 404"
+ " | ViewRootImpl: Exception, http status 503";
Assert.assertEquals(expected, verdict.info());
}
}

private Settings buildSettings(RuntimeControlsProtocol.Modes mode, String regex) {
List<Pair<?, ?>> tags = new ArrayList<>();
tags.add(Pair.from(ConfigTags.Mode, mode));
Expand Down