From 82d09997ed678d2f43508798a53e55cb041e38b6 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:04:32 +0000 Subject: [PATCH 01/14] Add unit tests for NamedThreadFactory - Test thread naming with prefix and incrementing numbers - Test multiple threads creation - Test thread properties (non-daemon) - Test different prefixes and special characters - Test thread execution of runnables --- .../execution/NamedThreadFactoryTest.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java new file mode 100644 index 00000000..f0e35835 --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java @@ -0,0 +1,99 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +public class NamedThreadFactoryTest { + + @Test + public void testNewThreadWithPrefix() { + String prefix = "TestThread"; + NamedThreadFactory factory = new NamedThreadFactory(prefix); + + Runnable runnable = () -> {}; + Thread thread = factory.newThread(runnable); + + assertNotNull(thread); + assertEquals(prefix + "-1", thread.getName()); + } + + @Test + public void testMultipleThreadsWithIncrementingNumbers() { + String prefix = "Worker"; + NamedThreadFactory factory = new NamedThreadFactory(prefix); + + Thread thread1 = factory.newThread(() -> {}); + Thread thread2 = factory.newThread(() -> {}); + Thread thread3 = factory.newThread(() -> {}); + + assertEquals(prefix + "-1", thread1.getName()); + assertEquals(prefix + "-2", thread2.getName()); + assertEquals(prefix + "-3", thread3.getName()); + } + + @Test + public void testThreadsAreNotDaemon() { + NamedThreadFactory factory = new NamedThreadFactory("Test"); + Thread thread = factory.newThread(() -> {}); + + // Default thread factory creates non-daemon threads + assertTrue(!thread.isDaemon()); + } + + @Test + public void testThreadsWithDifferentPrefixes() { + NamedThreadFactory factory1 = new NamedThreadFactory("Factory1"); + NamedThreadFactory factory2 = new NamedThreadFactory("Factory2"); + + Thread thread1 = factory1.newThread(() -> {}); + Thread thread2 = factory2.newThread(() -> {}); + + assertEquals("Factory1-1", thread1.getName()); + assertEquals("Factory2-1", thread2.getName()); + } + + @Test + public void testThreadExecutesRunnable() throws InterruptedException { + NamedThreadFactory factory = new NamedThreadFactory("Executor"); + AtomicInteger counter = new AtomicInteger(0); + + Runnable runnable = () -> { + counter.incrementAndGet(); + }; + + Thread thread = factory.newThread(runnable); + thread.start(); + thread.join(); + + assertEquals(1, counter.get()); + } + + @Test + public void testEmptyPrefix() { + NamedThreadFactory factory = new NamedThreadFactory(""); + Thread thread = factory.newThread(() -> {}); + + assertEquals("-1", thread.getName()); + } + + @Test + public void testSpecialCharactersInPrefix() { + String prefix = "Test-Thread_123@#$"; + NamedThreadFactory factory = new NamedThreadFactory(prefix); + Thread thread = factory.newThread(() -> {}); + + assertEquals(prefix + "-1", thread.getName()); + } +} \ No newline at end of file From acbb15028ee58eea6929b4db430b9a95fc2bac47 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:05:25 +0000 Subject: [PATCH 02/14] Add unit tests for ScanJob - Test construction with empty and non-empty lists - Test that getter methods return copies (defensive copying) - Test immutability of internal lists - Test preservation of list order --- .../scanner/core/execution/ScanJobTest.java | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java new file mode 100644 index 00000000..45744af5 --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java @@ -0,0 +1,188 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.*; + +import de.rub.nds.scanner.core.afterprobe.AfterProbe; +import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.report.ScanReport; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class ScanJobTest { + + // Mock classes for testing + static class TestReport extends ScanReport { + @Override + public String getRemoteName() { + return "TestHost"; + } + } + + static class TestState {} + + static class TestProbe extends ScannerProbe { + private final String name; + + TestProbe(String name) { + this.name = name; + } + + @Override + public void executeTest(TestState state) {} + + @Override + public String getProbeName() { + return name; + } + + @Override + public ProbeType getType() { + return null; + } + + @Override + public boolean canBeExecuted(TestReport report) { + return true; + } + + @Override + public void adjustConfig(TestReport report) {} + + @Override + public TestProbe prepare(TestReport report) { + return this; + } + + @Override + public void merge(TestReport report) {} + } + + static class TestAfterProbe extends AfterProbe { + private final String name; + + TestAfterProbe(String name) { + this.name = name; + } + + @Override + public void analyze(TestReport report) {} + + public String getName() { + return name; + } + } + + interface ProbeType {} + + @Test + public void testConstructorWithEmptyLists() { + List probeList = new ArrayList<>(); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + assertNotNull(scanJob.getProbeList()); + assertNotNull(scanJob.getAfterList()); + assertTrue(scanJob.getProbeList().isEmpty()); + assertTrue(scanJob.getAfterList().isEmpty()); + } + + @Test + public void testConstructorWithNonEmptyLists() { + List probeList = new ArrayList<>(); + probeList.add(new TestProbe("probe1")); + probeList.add(new TestProbe("probe2")); + + List afterList = new ArrayList<>(); + afterList.add(new TestAfterProbe("after1")); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + assertEquals(2, scanJob.getProbeList().size()); + assertEquals(1, scanJob.getAfterList().size()); + } + + @Test + public void testGetProbeListReturnsCopy() { + List probeList = new ArrayList<>(); + TestProbe probe = new TestProbe("probe1"); + probeList.add(probe); + + ScanJob scanJob = + new ScanJob<>(probeList, new ArrayList<>()); + + List returnedList = scanJob.getProbeList(); + returnedList.add(new TestProbe("probe2")); + + // Original list should not be modified + assertEquals(1, scanJob.getProbeList().size()); + assertEquals(2, returnedList.size()); + } + + @Test + public void testGetAfterListReturnsCopy() { + List afterList = new ArrayList<>(); + TestAfterProbe afterProbe = new TestAfterProbe("after1"); + afterList.add(afterProbe); + + ScanJob scanJob = + new ScanJob<>(new ArrayList<>(), afterList); + + List returnedList = scanJob.getAfterList(); + returnedList.add(new TestAfterProbe("after2")); + + // Original list should not be modified + assertEquals(1, scanJob.getAfterList().size()); + assertEquals(2, returnedList.size()); + } + + @Test + public void testImmutabilityOfInternalLists() { + List probeList = new ArrayList<>(); + probeList.add(new TestProbe("probe1")); + + List afterList = new ArrayList<>(); + afterList.add(new TestAfterProbe("after1")); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + // Modify original lists + probeList.add(new TestProbe("probe2")); + afterList.add(new TestAfterProbe("after2")); + + // ScanJob should not be affected + assertEquals(1, scanJob.getProbeList().size()); + assertEquals(1, scanJob.getAfterList().size()); + } + + @Test + public void testPreservesListOrder() { + List probeList = new ArrayList<>(); + TestProbe probe1 = new TestProbe("probe1"); + TestProbe probe2 = new TestProbe("probe2"); + TestProbe probe3 = new TestProbe("probe3"); + probeList.add(probe1); + probeList.add(probe2); + probeList.add(probe3); + + ScanJob scanJob = + new ScanJob<>(probeList, new ArrayList<>()); + + List returnedList = scanJob.getProbeList(); + assertEquals("probe1", returnedList.get(0).getProbeName()); + assertEquals("probe2", returnedList.get(1).getProbeName()); + assertEquals("probe3", returnedList.get(2).getProbeName()); + } +} \ No newline at end of file From 325dc50b1e458f7fc64177321efb54fa6ad5e311 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:06:14 +0000 Subject: [PATCH 03/14] Add unit tests for ScanJobExecutor - Test abstract methods implementation - Test execute method behavior - Test shutdown method behavior - Test InterruptedException handling - Verify abstract class and method signatures --- .../core/execution/ScanJobExecutorTest.java | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java new file mode 100644 index 00000000..e6556a5e --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java @@ -0,0 +1,146 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.*; + +import de.rub.nds.scanner.core.report.ScanReport; +import org.junit.jupiter.api.Test; + +public class ScanJobExecutorTest { + + // Mock ScanReport for testing + static class TestReport extends ScanReport { + private boolean executed = false; + + @Override + public String getRemoteName() { + return "TestHost"; + } + + public boolean isExecuted() { + return executed; + } + + public void setExecuted(boolean executed) { + this.executed = executed; + } + } + + // Test implementation of ScanJobExecutor + static class TestScanJobExecutor extends ScanJobExecutor { + private boolean shutdownCalled = false; + private int executeCallCount = 0; + + @Override + public void execute(TestReport report) throws InterruptedException { + executeCallCount++; + report.setExecuted(true); + } + + @Override + public void shutdown() { + shutdownCalled = true; + } + + public boolean isShutdownCalled() { + return shutdownCalled; + } + + public int getExecuteCallCount() { + return executeCallCount; + } + } + + // Test implementation that throws InterruptedException + static class InterruptingExecutor extends ScanJobExecutor { + @Override + public void execute(TestReport report) throws InterruptedException { + throw new InterruptedException("Test interruption"); + } + + @Override + public void shutdown() { + } + } + + @Test + public void testExecuteMethod() throws InterruptedException { + TestScanJobExecutor executor = new TestScanJobExecutor(); + TestReport report = new TestReport(); + + assertFalse(report.isExecuted()); + executor.execute(report); + + assertTrue(report.isExecuted()); + assertEquals(1, executor.getExecuteCallCount()); + } + + @Test + public void testShutdownMethod() { + TestScanJobExecutor executor = new TestScanJobExecutor(); + + assertFalse(executor.isShutdownCalled()); + executor.shutdown(); + assertTrue(executor.isShutdownCalled()); + } + + @Test + public void testMultipleExecuteCalls() throws InterruptedException { + TestScanJobExecutor executor = new TestScanJobExecutor(); + TestReport report1 = new TestReport(); + TestReport report2 = new TestReport(); + TestReport report3 = new TestReport(); + + executor.execute(report1); + executor.execute(report2); + executor.execute(report3); + + assertEquals(3, executor.getExecuteCallCount()); + assertTrue(report1.isExecuted()); + assertTrue(report2.isExecuted()); + assertTrue(report3.isExecuted()); + } + + @Test + public void testExecuteThrowsInterruptedException() { + InterruptingExecutor executor = new InterruptingExecutor(); + TestReport report = new TestReport(); + + assertThrows(InterruptedException.class, () -> executor.execute(report)); + } + + @Test + public void testAbstractClass() { + // Verify that ScanJobExecutor is abstract and cannot be instantiated directly + assertTrue(java.lang.reflect.Modifier.isAbstract(ScanJobExecutor.class.getModifiers())); + } + + @Test + public void testExecuteMethodSignature() throws NoSuchMethodException { + // Verify the execute method signature + var method = ScanJobExecutor.class.getDeclaredMethod("execute", ScanReport.class); + assertTrue(java.lang.reflect.Modifier.isAbstract(method.getModifiers())); + assertEquals(void.class, method.getReturnType()); + + // Check that it declares InterruptedException + Class[] exceptionTypes = method.getExceptionTypes(); + assertEquals(1, exceptionTypes.length); + assertEquals(InterruptedException.class, exceptionTypes[0]); + } + + @Test + public void testShutdownMethodSignature() throws NoSuchMethodException { + // Verify the shutdown method signature + var method = ScanJobExecutor.class.getDeclaredMethod("shutdown"); + assertTrue(java.lang.reflect.Modifier.isAbstract(method.getModifiers())); + assertEquals(void.class, method.getReturnType()); + assertEquals(0, method.getExceptionTypes().length); + } +} \ No newline at end of file From 2c5d323acf7ec4bec880fe3321816b22c30dfd0b Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:07:40 +0000 Subject: [PATCH 04/14] Add unit tests for Scanner abstract class - Test both constructors (with and without probe lists) - Test scan flow with prerequisites check - Test probe registration methods - Test lifecycle methods (onScanStart, onScanEnd) - Test integration with SiteReportRater and Guidelines - Test file output functionality - Test timing measurements - Test AutoCloseable implementation --- .../scanner/core/execution/ScannerTest.java | 417 ++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java new file mode 100644 index 00000000..f0b0ae9e --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -0,0 +1,417 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.*; + +import de.rub.nds.scanner.core.afterprobe.AfterProbe; +import de.rub.nds.scanner.core.config.ExecutorConfig; +import de.rub.nds.scanner.core.guideline.Guideline; +import de.rub.nds.scanner.core.passive.ExtractedValueContainer; +import de.rub.nds.scanner.core.passive.StatsWriter; +import de.rub.nds.scanner.core.passive.TrackableValue; +import de.rub.nds.scanner.core.probe.ProbeType; +import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.report.ScanReport; +import de.rub.nds.scanner.core.report.rating.PropertyResultRatingInfluencer; +import de.rub.nds.scanner.core.report.rating.RatingInfluencer; +import de.rub.nds.scanner.core.report.rating.ScoreReport; +import de.rub.nds.scanner.core.report.rating.SiteReportRater; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +public class ScannerTest { + + @TempDir + private File tempDir; + + private ExecutorConfig executorConfig; + + // Test implementations + static class TestProbeType implements ProbeType { + private final String name; + + TestProbeType(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + } + + static class TestState {} + + static class TestReport extends ScanReport { + private String remoteName = "TestHost"; + private boolean prerequisitesFulfilled = true; + + @Override + public String getRemoteName() { + return remoteName; + } + + public void setPrerequisitesFulfilled(boolean fulfilled) { + this.prerequisitesFulfilled = fulfilled; + } + + public boolean arePrerequisitesFulfilled() { + return prerequisitesFulfilled; + } + } + + static class TestProbe extends ScannerProbe { + private final ProbeType type; + private boolean executed = false; + private boolean canExecute = true; + + TestProbe(ProbeType type) { + this.type = type; + } + + @Override + public void executeTest(TestState state) { + executed = true; + } + + @Override + public String getProbeName() { + return type.getName(); + } + + @Override + public ProbeType getType() { + return type; + } + + @Override + public boolean canBeExecuted(TestReport report) { + return canExecute; + } + + @Override + public void adjustConfig(TestReport report) {} + + @Override + public TestProbe prepare(TestReport report) { + return this; + } + + @Override + public void merge(TestReport report) {} + + public boolean isExecuted() { + return executed; + } + + public void setCanExecute(boolean canExecute) { + this.canExecute = canExecute; + } + } + + static class TestAfterProbe extends AfterProbe { + private boolean analyzed = false; + + @Override + public void analyze(TestReport report) { + analyzed = true; + } + + public boolean isAnalyzed() { + return analyzed; + } + } + + static class TestStatsWriter extends StatsWriter { + @Override + public void extract(TestState state) {} + } + + static class TestScanner extends Scanner { + private boolean fillProbesCalled = false; + private boolean onScanStartCalled = false; + private boolean onScanEndCalled = false; + private TestReport reportToReturn; + private boolean checkPrerequisites = true; + private SiteReportRater rater; + private List> guidelines = new ArrayList<>(); + + TestScanner(ExecutorConfig config) { + super(config); + } + + TestScanner(ExecutorConfig config, List probeList, List afterList) { + super(config, probeList, afterList); + } + + @Override + protected void fillProbeLists() { + fillProbesCalled = true; + } + + @Override + protected StatsWriter getDefaultProbeWriter() { + return new TestStatsWriter(); + } + + @Override + protected TestReport getEmptyReport() { + if (reportToReturn != null) { + return reportToReturn; + } + return new TestReport(); + } + + @Override + protected boolean checkScanPrerequisites(TestReport report) { + return checkPrerequisites && report.arePrerequisitesFulfilled(); + } + + @Override + protected void onScanStart() { + onScanStartCalled = true; + } + + @Override + protected void onScanEnd() { + onScanEndCalled = true; + } + + @Override + protected SiteReportRater getSiteReportRater() { + return rater; + } + + @Override + protected List> getGuidelines() { + return guidelines; + } + + public void setReportToReturn(TestReport report) { + this.reportToReturn = report; + } + + public void setCheckPrerequisites(boolean check) { + this.checkPrerequisites = check; + } + + public void setSiteReportRater(SiteReportRater rater) { + this.rater = rater; + } + + public void setGuidelines(List> guidelines) { + this.guidelines = guidelines; + } + + public boolean isFillProbesCalled() { + return fillProbesCalled; + } + + public boolean isOnScanStartCalled() { + return onScanStartCalled; + } + + public boolean isOnScanEndCalled() { + return onScanEndCalled; + } + } + + @BeforeEach + public void setUp() { + executorConfig = new ExecutorConfig(); + executorConfig.setParallelProbes(1); + executorConfig.setProbeTimeout(1000); + } + + @Test + public void testScanWithDefaultConstructor() { + TestScanner scanner = new TestScanner(executorConfig); + TestReport report = scanner.scan(); + + assertNotNull(report); + assertTrue(scanner.isFillProbesCalled()); + assertTrue(scanner.isOnScanStartCalled()); + assertTrue(scanner.isOnScanEndCalled()); + } + + @Test + public void testScanWithProbesConstructor() { + List probeList = new ArrayList<>(); + probeList.add(new TestProbe(new TestProbeType("probe1"))); + + List afterList = new ArrayList<>(); + afterList.add(new TestAfterProbe()); + + TestScanner scanner = new TestScanner(executorConfig, probeList, afterList); + TestReport report = scanner.scan(); + + assertNotNull(report); + assertFalse(scanner.isFillProbesCalled()); // Should not be called when probes are provided + } + + @Test + public void testScanPrerequisitesNotFulfilled() { + TestScanner scanner = new TestScanner(executorConfig); + TestReport report = new TestReport(); + report.setPrerequisitesFulfilled(false); + scanner.setReportToReturn(report); + + TestReport result = scanner.scan(); + + assertSame(report, result); + assertTrue(scanner.isOnScanStartCalled()); + assertFalse(scanner.isOnScanEndCalled()); // Should not reach end if prerequisites fail + } + + @Test + public void testRegisterProbeForExecution() { + TestScanner scanner = new TestScanner(executorConfig); + TestProbe probe = new TestProbe(new TestProbeType("test")); + + scanner.registerProbeForExecution(probe); + // Since this adds to internal probe list, we can't directly verify + // But the test ensures no exceptions are thrown + } + + @Test + public void testRegisterProbeWithExecuteByDefault() { + TestScanner scanner = new TestScanner(executorConfig); + TestProbe probe = new TestProbe(new TestProbeType("test")); + + scanner.registerProbeForExecution(probe, false); + // Test with executeByDefault = false + } + + @Test + public void testRegisterProbeWithSpecificProbesConfig() { + executorConfig.setProbes(List.of(new TestProbeType("allowed"))); + TestScanner scanner = new TestScanner(executorConfig); + + TestProbe allowedProbe = new TestProbe(new TestProbeType("allowed")); + TestProbe notAllowedProbe = new TestProbe(new TestProbeType("notallowed")); + + scanner.registerProbeForExecution(allowedProbe); + scanner.registerProbeForExecution(notAllowedProbe); + } + + @Test + public void testRegisterProbeWithExcludedProbes() { + executorConfig.setExcludedProbes(List.of(new TestProbeType("excluded"))); + TestScanner scanner = new TestScanner(executorConfig); + + TestProbe excludedProbe = new TestProbe(new TestProbeType("excluded")); + scanner.registerProbeForExecution(excludedProbe); + } + + @Test + public void testRegisterAfterProbe() { + TestScanner scanner = new TestScanner(executorConfig); + TestAfterProbe afterProbe = new TestAfterProbe(); + + scanner.registerProbeForExecution(afterProbe); + } + + @Test + public void testScanWithSiteReportRater() { + TestScanner scanner = new TestScanner(executorConfig); + SiteReportRater rater = new SiteReportRater(new ArrayList<>()); + scanner.setSiteReportRater(rater); + + TestReport report = scanner.scan(); + + assertNotNull(report.getScoreReport()); + } + + @Test + public void testScanWithGuidelines() { + TestScanner scanner = new TestScanner(executorConfig); + + Guideline guideline = new Guideline<>("TestGuideline", null) { + @Override + public String getRequirementLevel() { + return "MUST"; + } + }; + + scanner.setGuidelines(List.of(guideline)); + TestReport report = scanner.scan(); + + assertNotNull(report); + } + + @Test + public void testScanWithFileOutput() throws IOException { + File outputFile = new File(tempDir, "test-report.json"); + executorConfig.setWriteReportToFile(true); + executorConfig.setOutputFile(outputFile); + + TestScanner scanner = new TestScanner(executorConfig); + TestReport report = scanner.scan(); + + assertTrue(outputFile.exists()); + String content = Files.readString(outputFile.toPath()); + assertFalse(content.isEmpty()); + } + + @Test + public void testScanWithInvalidOutputFile() { + File invalidFile = new File("/invalid/path/that/does/not/exist/report.json"); + executorConfig.setWriteReportToFile(true); + executorConfig.setOutputFile(invalidFile); + + TestScanner scanner = new TestScanner(executorConfig); + + assertThrows(RuntimeException.class, scanner::scan); + } + + @Test + public void testAutoCloseable() throws Exception { + TestScanner scanner = new TestScanner(executorConfig); + + // Test that Scanner implements AutoCloseable + assertTrue(scanner instanceof AutoCloseable); + + // Test close method + scanner.close(); + } + + @Test + public void testScanTimingMeasurement() { + TestScanner scanner = new TestScanner(executorConfig); + TestReport report = scanner.scan(); + + assertTrue(report.getScanStartTime() > 0); + assertTrue(report.getScanEndTime() > 0); + assertTrue(report.getScanEndTime() >= report.getScanStartTime()); + } + + @Test + public void testInterruptedScan() throws InterruptedException { + TestScanner scanner = new TestScanner(executorConfig); + + Thread testThread = new Thread(() -> { + Thread.currentThread().interrupt(); + scanner.scan(); + }); + + testThread.start(); + testThread.join(); + + assertTrue(testThread.isInterrupted() || !testThread.isAlive()); + } +} \ No newline at end of file From 7e12ae8bc26d1071950b841c32e7717461642acf Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:08:46 +0000 Subject: [PATCH 05/14] Add unit tests for ScannerThreadPoolExecutor - Test basic construction and configuration - Test all submit methods (Runnable, Runnable with result, Callable) - Test semaphore release behavior on success and failure - Test task timeout functionality - Test multiple concurrent tasks - Test shutdown behavior and policies - Test edge cases like tasks completing before timeout --- .../ScannerThreadPoolExecutorTest.java | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java new file mode 100644 index 00000000..828a34dd --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java @@ -0,0 +1,242 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +public class ScannerThreadPoolExecutorTest { + + @Test + public void testBasicConstruction() { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 2, new NamedThreadFactory("Test"), semaphore, 5000); + + assertNotNull(executor); + assertEquals(2, executor.getCorePoolSize()); + assertFalse(executor.isShutdown()); + + executor.shutdown(); + } + + @Test + public void testSubmitRunnable() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + AtomicBoolean taskExecuted = new AtomicBoolean(false); + Future future = executor.submit(() -> taskExecuted.set(true)); + + // Wait for task completion + semaphore.acquire(); + + assertTrue(taskExecuted.get()); + assertTrue(future.isDone()); + + executor.shutdown(); + } + + @Test + public void testSubmitRunnableWithResult() throws InterruptedException, ExecutionException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + String result = "TestResult"; + AtomicBoolean taskExecuted = new AtomicBoolean(false); + Future future = executor.submit(() -> taskExecuted.set(true), result); + + // Wait for task completion + semaphore.acquire(); + + assertTrue(taskExecuted.get()); + assertEquals(result, future.get()); + + executor.shutdown(); + } + + @Test + public void testSubmitCallable() throws InterruptedException, ExecutionException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + Callable callable = () -> 42; + Future future = executor.submit(callable); + + // Wait for task completion + semaphore.acquire(); + + assertEquals(42, future.get()); + + executor.shutdown(); + } + + @Test + public void testSemaphoreReleasedAfterTaskCompletion() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + executor.submit(() -> { + // Simple task + }); + + // Should be able to acquire, proving semaphore was released + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); + + executor.shutdown(); + } + + @Test + public void testSemaphoreReleasedOnException() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + executor.submit(() -> { + throw new RuntimeException("Test exception"); + }); + + // Semaphore should still be released even when task throws exception + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); + + executor.shutdown(); + } + + @Test + public void testTaskTimeout() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + // Set very short timeout + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 100); + + CountDownLatch taskStarted = new CountDownLatch(1); + AtomicBoolean taskCompleted = new AtomicBoolean(false); + + Future future = executor.submit(() -> { + taskStarted.countDown(); + try { + Thread.sleep(500); // Sleep longer than timeout + taskCompleted.set(true); + } catch (InterruptedException e) { + // Expected when task is cancelled + } + }); + + // Wait for task to start + taskStarted.await(); + + // Wait for timeout to trigger + Thread.sleep(200); + + assertTrue(future.isCancelled()); + assertFalse(taskCompleted.get()); + + // Semaphore should be released after timeout + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); + + executor.shutdown(); + } + + @Test + public void testMultipleTasks() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 3, new NamedThreadFactory("Test"), semaphore, 5000); + + AtomicInteger counter = new AtomicInteger(0); + int taskCount = 10; + + for (int i = 0; i < taskCount; i++) { + executor.submit(counter::incrementAndGet); + } + + // Wait for all tasks + for (int i = 0; i < taskCount; i++) { + semaphore.acquire(); + } + + assertEquals(taskCount, counter.get()); + + executor.shutdown(); + } + + @Test + public void testShutdownBehavior() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + AtomicBoolean taskExecuted = new AtomicBoolean(false); + executor.submit(() -> taskExecuted.set(true)); + + semaphore.acquire(); + assertTrue(taskExecuted.get()); + + executor.shutdown(); + assertTrue(executor.isShutdown()); + + // Should not accept new tasks after shutdown + assertThrows(RejectedExecutionException.class, () -> { + executor.submit(() -> {}); + }); + } + + @Test + public void testContinueExistingPeriodicTasksPolicy() { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 5000); + + // These are set in constructor + assertFalse(executor.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + assertFalse(executor.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + + executor.shutdown(); + } + + @Test + public void testTaskAlreadyDoneBeforeTimeout() throws InterruptedException { + Semaphore semaphore = new Semaphore(0); + ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Test"), semaphore, 1000); + + CountDownLatch timeoutCheckLatch = new CountDownLatch(1); + + // Submit a quick task + Future future = executor.submit(() -> { + // Quick task that completes before timeout + }); + + // Wait for task completion + semaphore.acquire(); + assertTrue(future.isDone()); + + // Wait a bit to ensure timeout task runs + Thread.sleep(1100); + + // The timeout task should have run but found the future already done + // No exception should be thrown + + executor.shutdown(); + } +} \ No newline at end of file From fdd2965c947c5c5c54b758b7024655ac3a2acbc1 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:10:33 +0000 Subject: [PATCH 06/14] Add unit tests for ThreadedScanJobExecutor - Test basic execution flow with probes and after probes - Test handling of probes that cannot be executed - Test exception handling during probe execution - Test property change listener functionality - Test statistics collection and merging - Test shutdown and AutoCloseable interface - Test custom executor constructor - Test edge cases (empty probe list, invalid property changes) - Test merging of extracted value containers --- .../ThreadedScanJobExecutorTest.java | 482 ++++++++++++++++++ 1 file changed, 482 insertions(+) create mode 100644 src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java new file mode 100644 index 00000000..184fc895 --- /dev/null +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -0,0 +1,482 @@ +/* + * Scanner Core - A Modular Framework for Probe Definition, Execution, and Result Analysis. + * + * Copyright 2017-2023 Ruhr University Bochum, Paderborn University, Technology Innovation Institute, and Hackmanit GmbH + * + * Licensed under Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + */ +package de.rub.nds.scanner.core.execution; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import de.rub.nds.scanner.core.afterprobe.AfterProbe; +import de.rub.nds.scanner.core.config.ExecutorConfig; +import de.rub.nds.scanner.core.passive.ExtractedValueContainer; +import de.rub.nds.scanner.core.passive.StatsWriter; +import de.rub.nds.scanner.core.passive.TrackableValue; +import de.rub.nds.scanner.core.probe.ProbeType; +import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.probe.requirements.Requirement; +import de.rub.nds.scanner.core.report.ScanReport; +import java.beans.PropertyChangeEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +public class ThreadedScanJobExecutorTest { + + private ExecutorConfig executorConfig; + + // Test implementations + static class TestProbeType implements ProbeType { + private final String name; + + TestProbeType(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof TestProbeType) { + return name.equals(((TestProbeType) obj).name); + } + return false; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + } + + static class TestState {} + + static class TestReport extends ScanReport { + private final List executedProbes = new ArrayList<>(); + private final List unexecutedProbes = new ArrayList<>(); + + @Override + public String getRemoteName() { + return "TestHost"; + } + + @Override + public void markProbeAsExecuted(ScannerProbe probe) { + executedProbes.add(probe.getType()); + firePropertyChange("supportedProbe", null, probe.getType()); + } + + @Override + public void markProbeAsUnexecuted(ScannerProbe probe) { + unexecutedProbes.add(probe.getType()); + firePropertyChange("unsupportedProbe", null, probe.getType()); + } + + public List getExecutedProbes() { + return executedProbes; + } + + public List getUnexecutedProbes() { + return unexecutedProbes; + } + } + + static class TestProbe extends ScannerProbe { + private final ProbeType type; + private boolean canExecute = true; + private boolean wasExecuted = false; + private boolean shouldThrowException = false; + private final List> requirements = new ArrayList<>(); + + TestProbe(ProbeType type) { + this.type = type; + setWriter(new TestStatsWriter()); + } + + @Override + public TestProbe call() throws Exception { + if (shouldThrowException) { + throw new RuntimeException("Test exception"); + } + wasExecuted = true; + return this; + } + + @Override + public void executeTest(TestState state) { + wasExecuted = true; + } + + @Override + public String getProbeName() { + return type.getName(); + } + + @Override + public ProbeType getType() { + return type; + } + + @Override + public boolean canBeExecuted(TestReport report) { + return canExecute; + } + + @Override + public void adjustConfig(TestReport report) {} + + @Override + public TestProbe prepare(TestReport report) { + return this; + } + + @Override + public void merge(TestReport report) {} + + @Override + public List> getRequirements() { + return requirements; + } + + public void setCanExecute(boolean canExecute) { + this.canExecute = canExecute; + } + + public boolean wasExecuted() { + return wasExecuted; + } + + public void setShouldThrowException(boolean shouldThrow) { + this.shouldThrowException = shouldThrow; + } + + public void addRequirement(Requirement requirement) { + this.requirements.add(requirement); + } + } + + static class TestAfterProbe extends AfterProbe { + private boolean analyzed = false; + + @Override + public void analyze(TestReport report) { + analyzed = true; + } + + public boolean isAnalyzed() { + return analyzed; + } + } + + static class TestStatsWriter extends StatsWriter { + private int stateCount = 0; + + @Override + public void extract(TestState state) {} + + @Override + public int getStateCounter() { + return stateCount; + } + + public void setStateCount(int count) { + this.stateCount = count; + } + + @Override + public List> getCumulatedExtractedValues() { + List> containers = new ArrayList<>(); + containers.add(new TestExtractedValueContainer()); + return containers; + } + } + + static class TestExtractedValueContainer extends ExtractedValueContainer { + TestExtractedValueContainer() { + super(TestTrackableValue.TEST_VALUE); + put("test1"); + put("test2"); + } + } + + enum TestTrackableValue implements TrackableValue { + TEST_VALUE + } + + @BeforeEach + public void setUp() { + executorConfig = new ExecutorConfig(); + executorConfig.setParallelProbes(2); + executorConfig.setProbeTimeout(5000); + } + + @Test + public void testBasicExecution() throws InterruptedException { + List probeList = Arrays.asList( + new TestProbe(new TestProbeType("probe1")), + new TestProbe(new TestProbeType("probe2")) + ); + List afterList = Arrays.asList(new TestAfterProbe()); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { + + TestReport report = new TestReport(); + executor.execute(report); + + assertEquals(2, report.getExecutedProbes().size()); + assertTrue(probeList.get(0).wasExecuted()); + assertTrue(probeList.get(1).wasExecuted()); + assertTrue(afterList.get(0).isAnalyzed()); + } + } + + @Test + public void testProbesThatCannotBeExecuted() throws InterruptedException { + TestProbe executableProbe = new TestProbe(new TestProbeType("executable")); + TestProbe nonExecutableProbe = new TestProbe(new TestProbeType("nonExecutable")); + nonExecutableProbe.setCanExecute(false); + + List probeList = Arrays.asList(executableProbe, nonExecutableProbe); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { + + TestReport report = new TestReport(); + executor.execute(report); + + assertEquals(1, report.getExecutedProbes().size()); + assertEquals(1, report.getUnexecutedProbes().size()); + assertTrue(executableProbe.wasExecuted()); + assertFalse(nonExecutableProbe.wasExecuted()); + } + } + + @Test + public void testProbeExecutionException() throws InterruptedException { + TestProbe normalProbe = new TestProbe(new TestProbeType("normal")); + TestProbe failingProbe = new TestProbe(new TestProbeType("failing")); + failingProbe.setShouldThrowException(true); + + List probeList = Arrays.asList(normalProbe, failingProbe); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { + + TestReport report = new TestReport(); + + assertThrows(RuntimeException.class, () -> executor.execute(report)); + } + } + + @Test + public void testPropertyChangeListener() throws InterruptedException { + TestProbe probe1 = new TestProbe(new TestProbeType("probe1")); + TestProbe probe2 = new TestProbe(new TestProbeType("probe2")); + probe2.setCanExecute(false); // Initially cannot execute + + // Add requirement that probe1 must be executed first + probe2.addRequirement(report -> + report.getExecutedProbes().contains(new TestProbeType("probe1"))); + + List probeList = Arrays.asList(probe1, probe2); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { + + TestReport report = new TestReport(); + + // Simulate property change after probe1 executes + report.addPropertyChangeListener(evt -> { + if ("supportedProbe".equals(evt.getPropertyName()) && + evt.getNewValue().equals(new TestProbeType("probe1"))) { + probe2.setCanExecute(true); + } + }); + + executor.execute(report); + + assertEquals(2, report.getExecutedProbes().size()); + assertTrue(probe1.wasExecuted()); + assertTrue(probe2.wasExecuted()); + } + } + + @Test + public void testStatisticsCollection() throws InterruptedException { + TestProbe probe1 = new TestProbe(new TestProbeType("probe1")); + TestProbe probe2 = new TestProbe(new TestProbeType("probe2")); + + TestStatsWriter writer1 = (TestStatsWriter) probe1.getWriter(); + TestStatsWriter writer2 = (TestStatsWriter) probe2.getWriter(); + writer1.setStateCount(5); + writer2.setStateCount(3); + + List probeList = Arrays.asList(probe1, probe2); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { + + TestReport report = new TestReport(); + executor.execute(report); + + assertEquals(8, report.getPerformedConnections()); // 5 + 3 + assertFalse(report.getExtractedValueContainers().isEmpty()); + } + } + + @Test + public void testShutdown() throws InterruptedException { + List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); + + TestReport report = new TestReport(); + executor.execute(report); + + executor.shutdown(); + // Should not throw exception + } + + @Test + public void testAutoCloseable() throws Exception { + List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); + + TestReport report = new TestReport(); + executor.execute(report); + + executor.close(); // Test AutoCloseable + } + + @Test + public void testConstructorWithCustomExecutor() throws InterruptedException { + List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + ThreadPoolExecutor customExecutor = new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Custom"), new Semaphore(0), 5000); + + ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, customExecutor); + + TestReport report = new TestReport(); + executor.execute(report); + + assertEquals(1, report.getExecutedProbes().size()); + + executor.shutdown(); + customExecutor.shutdown(); + } + + @Test + public void testPropertyChangeWithInvalidSource() { + List probeList = new ArrayList<>(); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { + + // Test with non-ScanReport source + PropertyChangeEvent event = new PropertyChangeEvent( + new Object(), "supportedProbe", null, new TestProbeType("test")); + + executor.propertyChange(event); // Should log error but not throw + } + } + + @Test + public void testEmptyProbeList() throws InterruptedException { + List probeList = new ArrayList<>(); + List afterList = Arrays.asList(new TestAfterProbe()); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { + + TestReport report = new TestReport(); + executor.execute(report); + + assertTrue(report.getExecutedProbes().isEmpty()); + assertTrue(afterList.get(0).isAnalyzed()); // After probes should still run + } + } + + @Test + public void testMultipleExtractedValueContainersOfSameType() throws InterruptedException { + TestProbe probe1 = new TestProbe(new TestProbeType("probe1")); + TestProbe probe2 = new TestProbe(new TestProbeType("probe2")); + + List probeList = Arrays.asList(probe1, probe2); + List afterList = new ArrayList<>(); + + ScanJob scanJob = + new ScanJob<>(probeList, afterList); + + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { + + TestReport report = new TestReport(); + executor.execute(report); + + // Should merge containers of same type + assertEquals(1, report.getExtractedValueContainers().size()); + ExtractedValueContainer container = + report.getExtractedValueContainers().get(TestTrackableValue.TEST_VALUE); + assertNotNull(container); + // Each probe contributes 2 values, so we should have 4 total + assertEquals(4, container.getExtractedValueList().size()); + } + } +} \ No newline at end of file From e1c2be9dd32d0dff97f7911607c5c283d3c916f9 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:11:20 +0000 Subject: [PATCH 07/14] Remove unused Mockito imports from ThreadedScanJobExecutorTest --- .../nds/scanner/core/execution/ThreadedScanJobExecutorTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java index 184fc895..3af2518c 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -9,7 +9,6 @@ package de.rub.nds.scanner.core.execution; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.*; import de.rub.nds.scanner.core.afterprobe.AfterProbe; import de.rub.nds.scanner.core.config.ExecutorConfig; @@ -29,7 +28,6 @@ import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; public class ThreadedScanJobExecutorTest { From 8c17b8b560ce3bc7e0faa5d745c32af02e20017a Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:13:43 +0000 Subject: [PATCH 08/14] Fix compilation errors in test classes - Update test probe implementations to match ScannerProbe API - Add required method implementations (mergeData, getRequirements) - Fix constructor calls to use ProbeType parameter - Add missing imports and methods in TestReport --- .../execution/NamedThreadFactoryTest.java | 33 ++-- .../core/execution/ScanJobExecutorTest.java | 35 ++-- .../scanner/core/execution/ScanJobTest.java | 85 +++++---- .../scanner/core/execution/ScannerTest.java | 98 ++++------ .../ScannerThreadPoolExecutorTest.java | 146 ++++++++------- .../ThreadedScanJobExecutorTest.java | 172 +++++++++--------- 6 files changed, 274 insertions(+), 295 deletions(-) diff --git a/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java index f0e35835..c3871d70 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java @@ -21,10 +21,10 @@ public class NamedThreadFactoryTest { public void testNewThreadWithPrefix() { String prefix = "TestThread"; NamedThreadFactory factory = new NamedThreadFactory(prefix); - + Runnable runnable = () -> {}; Thread thread = factory.newThread(runnable); - + assertNotNull(thread); assertEquals(prefix + "-1", thread.getName()); } @@ -33,11 +33,11 @@ public void testNewThreadWithPrefix() { public void testMultipleThreadsWithIncrementingNumbers() { String prefix = "Worker"; NamedThreadFactory factory = new NamedThreadFactory(prefix); - + Thread thread1 = factory.newThread(() -> {}); Thread thread2 = factory.newThread(() -> {}); Thread thread3 = factory.newThread(() -> {}); - + assertEquals(prefix + "-1", thread1.getName()); assertEquals(prefix + "-2", thread2.getName()); assertEquals(prefix + "-3", thread3.getName()); @@ -47,7 +47,7 @@ public void testMultipleThreadsWithIncrementingNumbers() { public void testThreadsAreNotDaemon() { NamedThreadFactory factory = new NamedThreadFactory("Test"); Thread thread = factory.newThread(() -> {}); - + // Default thread factory creates non-daemon threads assertTrue(!thread.isDaemon()); } @@ -56,10 +56,10 @@ public void testThreadsAreNotDaemon() { public void testThreadsWithDifferentPrefixes() { NamedThreadFactory factory1 = new NamedThreadFactory("Factory1"); NamedThreadFactory factory2 = new NamedThreadFactory("Factory2"); - + Thread thread1 = factory1.newThread(() -> {}); Thread thread2 = factory2.newThread(() -> {}); - + assertEquals("Factory1-1", thread1.getName()); assertEquals("Factory2-1", thread2.getName()); } @@ -68,15 +68,16 @@ public void testThreadsWithDifferentPrefixes() { public void testThreadExecutesRunnable() throws InterruptedException { NamedThreadFactory factory = new NamedThreadFactory("Executor"); AtomicInteger counter = new AtomicInteger(0); - - Runnable runnable = () -> { - counter.incrementAndGet(); - }; - + + Runnable runnable = + () -> { + counter.incrementAndGet(); + }; + Thread thread = factory.newThread(runnable); thread.start(); thread.join(); - + assertEquals(1, counter.get()); } @@ -84,7 +85,7 @@ public void testThreadExecutesRunnable() throws InterruptedException { public void testEmptyPrefix() { NamedThreadFactory factory = new NamedThreadFactory(""); Thread thread = factory.newThread(() -> {}); - + assertEquals("-1", thread.getName()); } @@ -93,7 +94,7 @@ public void testSpecialCharactersInPrefix() { String prefix = "Test-Thread_123@#$"; NamedThreadFactory factory = new NamedThreadFactory(prefix); Thread thread = factory.newThread(() -> {}); - + assertEquals(prefix + "-1", thread.getName()); } -} \ No newline at end of file +} diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java index e6556a5e..2b42d428 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java @@ -18,16 +18,16 @@ public class ScanJobExecutorTest { // Mock ScanReport for testing static class TestReport extends ScanReport { private boolean executed = false; - + @Override public String getRemoteName() { return "TestHost"; } - + public boolean isExecuted() { return executed; } - + public void setExecuted(boolean executed) { this.executed = executed; } @@ -37,22 +37,22 @@ public void setExecuted(boolean executed) { static class TestScanJobExecutor extends ScanJobExecutor { private boolean shutdownCalled = false; private int executeCallCount = 0; - + @Override public void execute(TestReport report) throws InterruptedException { executeCallCount++; report.setExecuted(true); } - + @Override public void shutdown() { shutdownCalled = true; } - + public boolean isShutdownCalled() { return shutdownCalled; } - + public int getExecuteCallCount() { return executeCallCount; } @@ -64,20 +64,19 @@ static class InterruptingExecutor extends ScanJobExecutor { public void execute(TestReport report) throws InterruptedException { throw new InterruptedException("Test interruption"); } - + @Override - public void shutdown() { - } + public void shutdown() {} } @Test public void testExecuteMethod() throws InterruptedException { TestScanJobExecutor executor = new TestScanJobExecutor(); TestReport report = new TestReport(); - + assertFalse(report.isExecuted()); executor.execute(report); - + assertTrue(report.isExecuted()); assertEquals(1, executor.getExecuteCallCount()); } @@ -85,7 +84,7 @@ public void testExecuteMethod() throws InterruptedException { @Test public void testShutdownMethod() { TestScanJobExecutor executor = new TestScanJobExecutor(); - + assertFalse(executor.isShutdownCalled()); executor.shutdown(); assertTrue(executor.isShutdownCalled()); @@ -97,11 +96,11 @@ public void testMultipleExecuteCalls() throws InterruptedException { TestReport report1 = new TestReport(); TestReport report2 = new TestReport(); TestReport report3 = new TestReport(); - + executor.execute(report1); executor.execute(report2); executor.execute(report3); - + assertEquals(3, executor.getExecuteCallCount()); assertTrue(report1.isExecuted()); assertTrue(report2.isExecuted()); @@ -112,7 +111,7 @@ public void testMultipleExecuteCalls() throws InterruptedException { public void testExecuteThrowsInterruptedException() { InterruptingExecutor executor = new InterruptingExecutor(); TestReport report = new TestReport(); - + assertThrows(InterruptedException.class, () -> executor.execute(report)); } @@ -128,7 +127,7 @@ public void testExecuteMethodSignature() throws NoSuchMethodException { var method = ScanJobExecutor.class.getDeclaredMethod("execute", ScanReport.class); assertTrue(java.lang.reflect.Modifier.isAbstract(method.getModifiers())); assertEquals(void.class, method.getReturnType()); - + // Check that it declares InterruptedException Class[] exceptionTypes = method.getExceptionTypes(); assertEquals(1, exceptionTypes.length); @@ -143,4 +142,4 @@ public void testShutdownMethodSignature() throws NoSuchMethodException { assertEquals(void.class, method.getReturnType()); assertEquals(0, method.getExceptionTypes().length); } -} \ No newline at end of file +} diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java index 45744af5..00ac79d8 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java @@ -33,37 +33,23 @@ static class TestProbe extends ScannerProbe { private final String name; TestProbe(String name) { + super(new TestProbeType(name)); this.name = name; } @Override - public void executeTest(TestState state) {} + public void executeTest() {} @Override - public String getProbeName() { - return name; - } - - @Override - public ProbeType getType() { - return null; - } - - @Override - public boolean canBeExecuted(TestReport report) { - return true; + public de.rub.nds.scanner.core.probe.requirements.Requirement getRequirements() { + return report -> true; } @Override public void adjustConfig(TestReport report) {} @Override - public TestProbe prepare(TestReport report) { - return this; - } - - @Override - public void merge(TestReport report) {} + protected void mergeData(TestReport report) {} } static class TestAfterProbe extends AfterProbe { @@ -81,16 +67,27 @@ public String getName() { } } - interface ProbeType {} + static class TestProbeType implements de.rub.nds.scanner.core.probe.ProbeType { + private final String name; + + TestProbeType(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + } @Test public void testConstructorWithEmptyLists() { List probeList = new ArrayList<>(); List afterList = new ArrayList<>(); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(probeList, afterList); - + assertNotNull(scanJob.getProbeList()); assertNotNull(scanJob.getAfterList()); assertTrue(scanJob.getProbeList().isEmpty()); @@ -102,13 +99,13 @@ public void testConstructorWithNonEmptyLists() { List probeList = new ArrayList<>(); probeList.add(new TestProbe("probe1")); probeList.add(new TestProbe("probe2")); - + List afterList = new ArrayList<>(); afterList.add(new TestAfterProbe("after1")); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(probeList, afterList); - + assertEquals(2, scanJob.getProbeList().size()); assertEquals(1, scanJob.getAfterList().size()); } @@ -118,13 +115,13 @@ public void testGetProbeListReturnsCopy() { List probeList = new ArrayList<>(); TestProbe probe = new TestProbe("probe1"); probeList.add(probe); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(probeList, new ArrayList<>()); - + List returnedList = scanJob.getProbeList(); returnedList.add(new TestProbe("probe2")); - + // Original list should not be modified assertEquals(1, scanJob.getProbeList().size()); assertEquals(2, returnedList.size()); @@ -135,13 +132,13 @@ public void testGetAfterListReturnsCopy() { List afterList = new ArrayList<>(); TestAfterProbe afterProbe = new TestAfterProbe("after1"); afterList.add(afterProbe); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(new ArrayList<>(), afterList); - + List returnedList = scanJob.getAfterList(); returnedList.add(new TestAfterProbe("after2")); - + // Original list should not be modified assertEquals(1, scanJob.getAfterList().size()); assertEquals(2, returnedList.size()); @@ -151,17 +148,17 @@ public void testGetAfterListReturnsCopy() { public void testImmutabilityOfInternalLists() { List probeList = new ArrayList<>(); probeList.add(new TestProbe("probe1")); - + List afterList = new ArrayList<>(); afterList.add(new TestAfterProbe("after1")); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(probeList, afterList); - + // Modify original lists probeList.add(new TestProbe("probe2")); afterList.add(new TestAfterProbe("after2")); - + // ScanJob should not be affected assertEquals(1, scanJob.getProbeList().size()); assertEquals(1, scanJob.getAfterList().size()); @@ -176,13 +173,13 @@ public void testPreservesListOrder() { probeList.add(probe1); probeList.add(probe2); probeList.add(probe3); - - ScanJob scanJob = + + ScanJob scanJob = new ScanJob<>(probeList, new ArrayList<>()); - + List returnedList = scanJob.getProbeList(); assertEquals("probe1", returnedList.get(0).getProbeName()); assertEquals("probe2", returnedList.get(1).getProbeName()); assertEquals("probe3", returnedList.get(2).getProbeName()); } -} \ No newline at end of file +} diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index f0b0ae9e..73d5b4e6 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -13,31 +13,23 @@ import de.rub.nds.scanner.core.afterprobe.AfterProbe; import de.rub.nds.scanner.core.config.ExecutorConfig; import de.rub.nds.scanner.core.guideline.Guideline; -import de.rub.nds.scanner.core.passive.ExtractedValueContainer; import de.rub.nds.scanner.core.passive.StatsWriter; -import de.rub.nds.scanner.core.passive.TrackableValue; import de.rub.nds.scanner.core.probe.ProbeType; import de.rub.nds.scanner.core.probe.ScannerProbe; import de.rub.nds.scanner.core.report.ScanReport; -import de.rub.nds.scanner.core.report.rating.PropertyResultRatingInfluencer; -import de.rub.nds.scanner.core.report.rating.RatingInfluencer; -import de.rub.nds.scanner.core.report.rating.ScoreReport; import de.rub.nds.scanner.core.report.rating.SiteReportRater; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; public class ScannerTest { - @TempDir - private File tempDir; + @TempDir private File tempDir; private ExecutorConfig executorConfig; @@ -76,44 +68,28 @@ public boolean arePrerequisitesFulfilled() { } static class TestProbe extends ScannerProbe { - private final ProbeType type; private boolean executed = false; private boolean canExecute = true; TestProbe(ProbeType type) { - this.type = type; + super(type); } @Override - public void executeTest(TestState state) { + public void executeTest() { executed = true; } @Override - public String getProbeName() { - return type.getName(); - } - - @Override - public ProbeType getType() { - return type; - } - - @Override - public boolean canBeExecuted(TestReport report) { - return canExecute; + public de.rub.nds.scanner.core.probe.requirements.Requirement getRequirements() { + return report -> canExecute; } @Override public void adjustConfig(TestReport report) {} @Override - public TestProbe prepare(TestReport report) { - return this; - } - - @Override - public void merge(TestReport report) {} + protected void mergeData(TestReport report) {} public boolean isExecuted() { return executed; @@ -155,7 +131,8 @@ static class TestScanner extends Scanner probeList, List afterList) { + TestScanner( + ExecutorConfig config, List probeList, List afterList) { super(config, probeList, afterList); } @@ -253,7 +230,7 @@ public void testScanWithDefaultConstructor() { public void testScanWithProbesConstructor() { List probeList = new ArrayList<>(); probeList.add(new TestProbe(new TestProbeType("probe1"))); - + List afterList = new ArrayList<>(); afterList.add(new TestAfterProbe()); @@ -282,7 +259,7 @@ public void testScanPrerequisitesNotFulfilled() { public void testRegisterProbeForExecution() { TestScanner scanner = new TestScanner(executorConfig); TestProbe probe = new TestProbe(new TestProbeType("test")); - + scanner.registerProbeForExecution(probe); // Since this adds to internal probe list, we can't directly verify // But the test ensures no exceptions are thrown @@ -292,7 +269,7 @@ public void testRegisterProbeForExecution() { public void testRegisterProbeWithExecuteByDefault() { TestScanner scanner = new TestScanner(executorConfig); TestProbe probe = new TestProbe(new TestProbeType("test")); - + scanner.registerProbeForExecution(probe, false); // Test with executeByDefault = false } @@ -301,10 +278,10 @@ public void testRegisterProbeWithExecuteByDefault() { public void testRegisterProbeWithSpecificProbesConfig() { executorConfig.setProbes(List.of(new TestProbeType("allowed"))); TestScanner scanner = new TestScanner(executorConfig); - + TestProbe allowedProbe = new TestProbe(new TestProbeType("allowed")); TestProbe notAllowedProbe = new TestProbe(new TestProbeType("notallowed")); - + scanner.registerProbeForExecution(allowedProbe); scanner.registerProbeForExecution(notAllowedProbe); } @@ -313,7 +290,7 @@ public void testRegisterProbeWithSpecificProbesConfig() { public void testRegisterProbeWithExcludedProbes() { executorConfig.setExcludedProbes(List.of(new TestProbeType("excluded"))); TestScanner scanner = new TestScanner(executorConfig); - + TestProbe excludedProbe = new TestProbe(new TestProbeType("excluded")); scanner.registerProbeForExecution(excludedProbe); } @@ -322,7 +299,7 @@ public void testRegisterProbeWithExcludedProbes() { public void testRegisterAfterProbe() { TestScanner scanner = new TestScanner(executorConfig); TestAfterProbe afterProbe = new TestAfterProbe(); - + scanner.registerProbeForExecution(afterProbe); } @@ -333,24 +310,25 @@ public void testScanWithSiteReportRater() { scanner.setSiteReportRater(rater); TestReport report = scanner.scan(); - + assertNotNull(report.getScoreReport()); } @Test public void testScanWithGuidelines() { TestScanner scanner = new TestScanner(executorConfig); - - Guideline guideline = new Guideline<>("TestGuideline", null) { - @Override - public String getRequirementLevel() { - return "MUST"; - } - }; - + + Guideline guideline = + new Guideline<>("TestGuideline", null) { + @Override + public String getRequirementLevel() { + return "MUST"; + } + }; + scanner.setGuidelines(List.of(guideline)); TestReport report = scanner.scan(); - + assertNotNull(report); } @@ -375,17 +353,17 @@ public void testScanWithInvalidOutputFile() { executorConfig.setOutputFile(invalidFile); TestScanner scanner = new TestScanner(executorConfig); - + assertThrows(RuntimeException.class, scanner::scan); } @Test public void testAutoCloseable() throws Exception { TestScanner scanner = new TestScanner(executorConfig); - + // Test that Scanner implements AutoCloseable assertTrue(scanner instanceof AutoCloseable); - + // Test close method scanner.close(); } @@ -403,15 +381,17 @@ public void testScanTimingMeasurement() { @Test public void testInterruptedScan() throws InterruptedException { TestScanner scanner = new TestScanner(executorConfig); - - Thread testThread = new Thread(() -> { - Thread.currentThread().interrupt(); - scanner.scan(); - }); - + + Thread testThread = + new Thread( + () -> { + Thread.currentThread().interrupt(); + scanner.scan(); + }); + testThread.start(); testThread.join(); - + assertTrue(testThread.isInterrupted() || !testThread.isAlive()); } -} \ No newline at end of file +} diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java index 828a34dd..38599f2c 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java @@ -26,39 +26,39 @@ public class ScannerThreadPoolExecutorTest { @Test public void testBasicConstruction() { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 2, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(2, new NamedThreadFactory("Test"), semaphore, 5000); assertNotNull(executor); assertEquals(2, executor.getCorePoolSize()); assertFalse(executor.isShutdown()); - + executor.shutdown(); } @Test public void testSubmitRunnable() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); AtomicBoolean taskExecuted = new AtomicBoolean(false); Future future = executor.submit(() -> taskExecuted.set(true)); // Wait for task completion semaphore.acquire(); - + assertTrue(taskExecuted.get()); assertTrue(future.isDone()); - + executor.shutdown(); } @Test public void testSubmitRunnableWithResult() throws InterruptedException, ExecutionException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); String result = "TestResult"; AtomicBoolean taskExecuted = new AtomicBoolean(false); @@ -66,59 +66,61 @@ public void testSubmitRunnableWithResult() throws InterruptedException, Executio // Wait for task completion semaphore.acquire(); - + assertTrue(taskExecuted.get()); assertEquals(result, future.get()); - + executor.shutdown(); } @Test public void testSubmitCallable() throws InterruptedException, ExecutionException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); Callable callable = () -> 42; Future future = executor.submit(callable); // Wait for task completion semaphore.acquire(); - + assertEquals(42, future.get()); - + executor.shutdown(); } @Test public void testSemaphoreReleasedAfterTaskCompletion() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - executor.submit(() -> { - // Simple task - }); + executor.submit( + () -> { + // Simple task + }); // Should be able to acquire, proving semaphore was released assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - + executor.shutdown(); } @Test public void testSemaphoreReleasedOnException() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - executor.submit(() -> { - throw new RuntimeException("Test exception"); - }); + executor.submit( + () -> { + throw new RuntimeException("Test exception"); + }); // Semaphore should still be released even when task throws exception assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - + executor.shutdown(); } @@ -126,46 +128,48 @@ public void testSemaphoreReleasedOnException() throws InterruptedException { public void testTaskTimeout() throws InterruptedException { Semaphore semaphore = new Semaphore(0); // Set very short timeout - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 100); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 100); CountDownLatch taskStarted = new CountDownLatch(1); AtomicBoolean taskCompleted = new AtomicBoolean(false); - - Future future = executor.submit(() -> { - taskStarted.countDown(); - try { - Thread.sleep(500); // Sleep longer than timeout - taskCompleted.set(true); - } catch (InterruptedException e) { - // Expected when task is cancelled - } - }); + + Future future = + executor.submit( + () -> { + taskStarted.countDown(); + try { + Thread.sleep(500); // Sleep longer than timeout + taskCompleted.set(true); + } catch (InterruptedException e) { + // Expected when task is cancelled + } + }); // Wait for task to start taskStarted.await(); - + // Wait for timeout to trigger Thread.sleep(200); - + assertTrue(future.isCancelled()); assertFalse(taskCompleted.get()); - + // Semaphore should be released after timeout assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - + executor.shutdown(); } @Test public void testMultipleTasks() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 3, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(3, new NamedThreadFactory("Test"), semaphore, 5000); AtomicInteger counter = new AtomicInteger(0); int taskCount = 10; - + for (int i = 0; i < taskCount; i++) { executor.submit(counter::incrementAndGet); } @@ -174,69 +178,73 @@ public void testMultipleTasks() throws InterruptedException { for (int i = 0; i < taskCount; i++) { semaphore.acquire(); } - + assertEquals(taskCount, counter.get()); - + executor.shutdown(); } @Test public void testShutdownBehavior() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); AtomicBoolean taskExecuted = new AtomicBoolean(false); executor.submit(() -> taskExecuted.set(true)); - + semaphore.acquire(); assertTrue(taskExecuted.get()); - + executor.shutdown(); assertTrue(executor.isShutdown()); - + // Should not accept new tasks after shutdown - assertThrows(RejectedExecutionException.class, () -> { - executor.submit(() -> {}); - }); + assertThrows( + RejectedExecutionException.class, + () -> { + executor.submit(() -> {}); + }); } @Test public void testContinueExistingPeriodicTasksPolicy() { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 5000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); // These are set in constructor assertFalse(executor.getContinueExistingPeriodicTasksAfterShutdownPolicy()); assertFalse(executor.getExecuteExistingDelayedTasksAfterShutdownPolicy()); - + executor.shutdown(); } @Test public void testTaskAlreadyDoneBeforeTimeout() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Test"), semaphore, 1000); + ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 1000); CountDownLatch timeoutCheckLatch = new CountDownLatch(1); - + // Submit a quick task - Future future = executor.submit(() -> { - // Quick task that completes before timeout - }); + Future future = + executor.submit( + () -> { + // Quick task that completes before timeout + }); // Wait for task completion semaphore.acquire(); assertTrue(future.isDone()); - + // Wait a bit to ensure timeout task runs Thread.sleep(1100); - + // The timeout task should have run but found the future already done // No exception should be thrown - + executor.shutdown(); } -} \ No newline at end of file +} diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java index 3af2518c..0cb54623 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -22,17 +22,18 @@ import java.beans.PropertyChangeEvent; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; public class ThreadedScanJobExecutorTest { private ExecutorConfig executorConfig; - + // Test implementations static class TestProbeType implements ProbeType { private final String name; @@ -65,6 +66,7 @@ static class TestState {} static class TestReport extends ScanReport { private final List executedProbes = new ArrayList<>(); private final List unexecutedProbes = new ArrayList<>(); + private final Map> extractedContainers = new HashMap<>(); @Override public String getRemoteName() { @@ -90,64 +92,53 @@ public List getExecutedProbes() { public List getUnexecutedProbes() { return unexecutedProbes; } + + public Map> getExtractedValueContainers() { + return extractedContainers; + } + + @Override + public void putAllExtractedValueContainers(Map> containers) { + extractedContainers.putAll(containers); + } } static class TestProbe extends ScannerProbe { - private final ProbeType type; private boolean canExecute = true; private boolean wasExecuted = false; private boolean shouldThrowException = false; - private final List> requirements = new ArrayList<>(); + private Requirement requirement = report -> canExecute; TestProbe(ProbeType type) { - this.type = type; + super(type); setWriter(new TestStatsWriter()); } @Override - public TestProbe call() throws Exception { + public TestProbe call() { if (shouldThrowException) { throw new RuntimeException("Test exception"); } + super.call(); wasExecuted = true; return this; } @Override - public void executeTest(TestState state) { + public void executeTest() { wasExecuted = true; } @Override - public String getProbeName() { - return type.getName(); - } - - @Override - public ProbeType getType() { - return type; - } - - @Override - public boolean canBeExecuted(TestReport report) { - return canExecute; + public Requirement getRequirements() { + return requirement; } @Override public void adjustConfig(TestReport report) {} @Override - public TestProbe prepare(TestReport report) { - return this; - } - - @Override - public void merge(TestReport report) {} - - @Override - public List> getRequirements() { - return requirements; - } + protected void mergeData(TestReport report) {} public void setCanExecute(boolean canExecute) { this.canExecute = canExecute; @@ -162,7 +153,7 @@ public void setShouldThrowException(boolean shouldThrow) { } public void addRequirement(Requirement requirement) { - this.requirements.add(requirement); + this.requirement = requirement; } } @@ -181,7 +172,7 @@ public boolean isAnalyzed() { static class TestStatsWriter extends StatsWriter { private int stateCount = 0; - + @Override public void extract(TestState state) {} @@ -223,18 +214,18 @@ public void setUp() { @Test public void testBasicExecution() throws InterruptedException { - List probeList = Arrays.asList( - new TestProbe(new TestProbeType("probe1")), - new TestProbe(new TestProbeType("probe2")) - ); + List probeList = + Arrays.asList( + new TestProbe(new TestProbeType("probe1")), + new TestProbe(new TestProbeType("probe2"))); List afterList = Arrays.asList(new TestAfterProbe()); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { - + TestReport report = new TestReport(); executor.execute(report); @@ -254,12 +245,12 @@ public void testProbesThatCannotBeExecuted() throws InterruptedException { List probeList = Arrays.asList(executableProbe, nonExecutableProbe); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { - + TestReport report = new TestReport(); executor.execute(report); @@ -279,14 +270,14 @@ public void testProbeExecutionException() throws InterruptedException { List probeList = Arrays.asList(normalProbe, failingProbe); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { - + TestReport report = new TestReport(); - + assertThrows(RuntimeException.class, () -> executor.execute(report)); } } @@ -298,27 +289,28 @@ public void testPropertyChangeListener() throws InterruptedException { probe2.setCanExecute(false); // Initially cannot execute // Add requirement that probe1 must be executed first - probe2.addRequirement(report -> - report.getExecutedProbes().contains(new TestProbeType("probe1"))); + probe2.addRequirement( + report -> report.getExecutedProbes().contains(new TestProbeType("probe1"))); List probeList = Arrays.asList(probe1, probe2); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { - + TestReport report = new TestReport(); - + // Simulate property change after probe1 executes - report.addPropertyChangeListener(evt -> { - if ("supportedProbe".equals(evt.getPropertyName()) && - evt.getNewValue().equals(new TestProbeType("probe1"))) { - probe2.setCanExecute(true); - } - }); + report.addPropertyChangeListener( + evt -> { + if ("supportedProbe".equals(evt.getPropertyName()) + && evt.getNewValue().equals(new TestProbeType("probe1"))) { + probe2.setCanExecute(true); + } + }); executor.execute(report); @@ -332,7 +324,7 @@ public void testPropertyChangeListener() throws InterruptedException { public void testStatisticsCollection() throws InterruptedException { TestProbe probe1 = new TestProbe(new TestProbeType("probe1")); TestProbe probe2 = new TestProbe(new TestProbeType("probe2")); - + TestStatsWriter writer1 = (TestStatsWriter) probe1.getWriter(); TestStatsWriter writer2 = (TestStatsWriter) probe2.getWriter(); writer1.setStateCount(5); @@ -341,12 +333,12 @@ public void testStatisticsCollection() throws InterruptedException { List probeList = Arrays.asList(probe1, probe2); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { - + TestReport report = new TestReport(); executor.execute(report); @@ -360,11 +352,11 @@ public void testShutdown() throws InterruptedException { List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); ThreadedScanJobExecutor executor = - new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); TestReport report = new TestReport(); executor.execute(report); @@ -378,11 +370,11 @@ public void testAutoCloseable() throws Exception { List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); ThreadedScanJobExecutor executor = - new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); TestReport report = new TestReport(); executor.execute(report); @@ -395,20 +387,21 @@ public void testConstructorWithCustomExecutor() throws InterruptedException { List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); - ThreadPoolExecutor customExecutor = new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Custom"), new Semaphore(0), 5000); + ThreadPoolExecutor customExecutor = + new ScannerThreadPoolExecutor( + 1, new NamedThreadFactory("Custom"), new Semaphore(0), 5000); ThreadedScanJobExecutor executor = - new ThreadedScanJobExecutor<>(executorConfig, scanJob, customExecutor); + new ThreadedScanJobExecutor<>(executorConfig, scanJob, customExecutor); TestReport report = new TestReport(); executor.execute(report); assertEquals(1, report.getExecutedProbes().size()); - + executor.shutdown(); customExecutor.shutdown(); } @@ -418,16 +411,17 @@ public void testPropertyChangeWithInvalidSource() { List probeList = new ArrayList<>(); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { - + // Test with non-ScanReport source - PropertyChangeEvent event = new PropertyChangeEvent( - new Object(), "supportedProbe", null, new TestProbeType("test")); - + PropertyChangeEvent event = + new PropertyChangeEvent( + new Object(), "supportedProbe", null, new TestProbeType("test")); + executor.propertyChange(event); // Should log error but not throw } } @@ -437,12 +431,12 @@ public void testEmptyProbeList() throws InterruptedException { List probeList = new ArrayList<>(); List afterList = Arrays.asList(new TestAfterProbe()); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { - + TestReport report = new TestReport(); executor.execute(report); @@ -459,22 +453,22 @@ public void testMultipleExtractedValueContainersOfSameType() throws InterruptedE List probeList = Arrays.asList(probe1, probe2); List afterList = new ArrayList<>(); - ScanJob scanJob = - new ScanJob<>(probeList, afterList); + ScanJob scanJob = + new ScanJob<>(probeList, afterList); try (ThreadedScanJobExecutor executor = new ThreadedScanJobExecutor<>(executorConfig, scanJob, 2, "Test")) { - + TestReport report = new TestReport(); executor.execute(report); // Should merge containers of same type assertEquals(1, report.getExtractedValueContainers().size()); - ExtractedValueContainer container = - report.getExtractedValueContainers().get(TestTrackableValue.TEST_VALUE); + ExtractedValueContainer container = + report.getExtractedValueContainers().get(TestTrackableValue.TEST_VALUE); assertNotNull(container); // Each probe contributes 2 values, so we should have 4 total assertEquals(4, container.getExtractedValueList().size()); } } -} \ No newline at end of file +} From cc5d89451df0b13eb06bff586f5474cf14fd3d35 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:19:39 +0000 Subject: [PATCH 09/14] Fix remaining compilation errors in test classes - Add serializeToJson implementation to all TestReport classes - Replace lambda requirements with concrete Requirement implementations - Fix TestScanner to implement close() method - Update SiteReportRater constructor call with proper parameters - Fix ExecutorConfig method calls (use setOutputFile with String) - Update all references from getExecutedProbes() to getExecutedProbeTypes() --- .../core/execution/ScanJobExecutorTest.java | 5 ++ .../scanner/core/execution/ScanJobTest.java | 10 +++- .../scanner/core/execution/ScannerTest.java | 43 +++++++++----- .../ThreadedScanJobExecutorTest.java | 57 ++++++++++++------- 4 files changed, 80 insertions(+), 35 deletions(-) diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java index 2b42d428..4978147a 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java @@ -24,6 +24,11 @@ public String getRemoteName() { return "TestHost"; } + @Override + public void serializeToJson(java.io.OutputStream outputStream) { + // Simple implementation for testing + } + public boolean isExecuted() { return executed; } diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java index 00ac79d8..323b7f20 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java @@ -25,6 +25,11 @@ static class TestReport extends ScanReport { public String getRemoteName() { return "TestHost"; } + + @Override + public void serializeToJson(java.io.OutputStream outputStream) { + // Simple implementation for testing + } } static class TestState {} @@ -41,8 +46,9 @@ static class TestProbe extends ScannerProbe { public void executeTest() {} @Override - public de.rub.nds.scanner.core.probe.requirements.Requirement getRequirements() { - return report -> true; + public de.rub.nds.scanner.core.probe.requirements.Requirement + getRequirements() { + return new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); } @Override diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index 73d5b4e6..de327c21 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -58,6 +58,16 @@ public String getRemoteName() { return remoteName; } + @Override + public void serializeToJson(java.io.OutputStream outputStream) { + // Simple implementation for testing + try { + outputStream.write("{\"remoteName\":\"TestHost\"}".getBytes()); + } catch (java.io.IOException e) { + // Ignore for testing + } + } + public void setPrerequisitesFulfilled(boolean fulfilled) { this.prerequisitesFulfilled = fulfilled; } @@ -81,8 +91,13 @@ public void executeTest() { } @Override - public de.rub.nds.scanner.core.probe.requirements.Requirement getRequirements() { - return report -> canExecute; + public de.rub.nds.scanner.core.probe.requirements.Requirement + getRequirements() { + if (canExecute) { + return new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + } else { + return new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); + } } @Override @@ -136,6 +151,11 @@ static class TestScanner extends Scanner()); + de.rub.nds.scanner.core.report.rating.RatingInfluencers influencers = + new de.rub.nds.scanner.core.report.rating.RatingInfluencers(new java.util.LinkedList<>()); + de.rub.nds.scanner.core.report.rating.Recommendations recommendations = + new de.rub.nds.scanner.core.report.rating.Recommendations(new java.util.LinkedList<>()); + SiteReportRater rater = new SiteReportRater(influencers, recommendations); scanner.setSiteReportRater(rater); TestReport report = scanner.scan(); @@ -319,12 +343,7 @@ public void testScanWithGuidelines() { TestScanner scanner = new TestScanner(executorConfig); Guideline guideline = - new Guideline<>("TestGuideline", null) { - @Override - public String getRequirementLevel() { - return "MUST"; - } - }; + new Guideline("TestGuideline", null); scanner.setGuidelines(List.of(guideline)); TestReport report = scanner.scan(); @@ -335,8 +354,7 @@ public String getRequirementLevel() { @Test public void testScanWithFileOutput() throws IOException { File outputFile = new File(tempDir, "test-report.json"); - executorConfig.setWriteReportToFile(true); - executorConfig.setOutputFile(outputFile); + executorConfig.setOutputFile(outputFile.getAbsolutePath()); TestScanner scanner = new TestScanner(executorConfig); TestReport report = scanner.scan(); @@ -349,8 +367,7 @@ public void testScanWithFileOutput() throws IOException { @Test public void testScanWithInvalidOutputFile() { File invalidFile = new File("/invalid/path/that/does/not/exist/report.json"); - executorConfig.setWriteReportToFile(true); - executorConfig.setOutputFile(invalidFile); + executorConfig.setOutputFile(invalidFile.getAbsolutePath()); TestScanner scanner = new TestScanner(executorConfig); diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java index 0cb54623..aaca5f7e 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -64,33 +64,39 @@ public int hashCode() { static class TestState {} static class TestReport extends ScanReport { - private final List executedProbes = new ArrayList<>(); - private final List unexecutedProbes = new ArrayList<>(); - private final Map> extractedContainers = new HashMap<>(); + private final List executedProbeTypes = new ArrayList<>(); + private final List unexecutedProbeTypes = new ArrayList<>(); + private final Map> extractedContainers = + new HashMap<>(); @Override public String getRemoteName() { return "TestHost"; } + @Override + public void serializeToJson(java.io.OutputStream outputStream) { + // Simple implementation for testing + } + @Override public void markProbeAsExecuted(ScannerProbe probe) { - executedProbes.add(probe.getType()); - firePropertyChange("supportedProbe", null, probe.getType()); + executedProbeTypes.add(probe.getType()); + super.markProbeAsExecuted(probe); } @Override public void markProbeAsUnexecuted(ScannerProbe probe) { - unexecutedProbes.add(probe.getType()); - firePropertyChange("unsupportedProbe", null, probe.getType()); + unexecutedProbeTypes.add(probe.getType()); + super.markProbeAsUnexecuted(probe); } - public List getExecutedProbes() { - return executedProbes; + public List getExecutedProbeTypes() { + return executedProbeTypes; } - public List getUnexecutedProbes() { - return unexecutedProbes; + public List getUnexecutedProbeTypes() { + return unexecutedProbeTypes; } public Map> getExtractedValueContainers() { @@ -98,7 +104,8 @@ public Map> getExtractedValueContaine } @Override - public void putAllExtractedValueContainers(Map> containers) { + public void putAllExtractedValueContainers( + Map> containers) { extractedContainers.putAll(containers); } } @@ -107,7 +114,7 @@ static class TestProbe extends ScannerProbe { private boolean canExecute = true; private boolean wasExecuted = false; private boolean shouldThrowException = false; - private Requirement requirement = report -> canExecute; + private Requirement requirement = new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); TestProbe(ProbeType type) { super(type); @@ -142,6 +149,11 @@ protected void mergeData(TestReport report) {} public void setCanExecute(boolean canExecute) { this.canExecute = canExecute; + if (canExecute) { + this.requirement = new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + } else { + this.requirement = new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); + } } public boolean wasExecuted() { @@ -229,7 +241,7 @@ public void testBasicExecution() throws InterruptedException { TestReport report = new TestReport(); executor.execute(report); - assertEquals(2, report.getExecutedProbes().size()); + assertEquals(2, report.getExecutedProbeTypes().size()); assertTrue(probeList.get(0).wasExecuted()); assertTrue(probeList.get(1).wasExecuted()); assertTrue(afterList.get(0).isAnalyzed()); @@ -254,8 +266,8 @@ public void testProbesThatCannotBeExecuted() throws InterruptedException { TestReport report = new TestReport(); executor.execute(report); - assertEquals(1, report.getExecutedProbes().size()); - assertEquals(1, report.getUnexecutedProbes().size()); + assertEquals(1, report.getExecutedProbeTypes().size()); + assertEquals(1, report.getUnexecutedProbeTypes().size()); assertTrue(executableProbe.wasExecuted()); assertFalse(nonExecutableProbe.wasExecuted()); } @@ -290,7 +302,12 @@ public void testPropertyChangeListener() throws InterruptedException { // Add requirement that probe1 must be executed first probe2.addRequirement( - report -> report.getExecutedProbes().contains(new TestProbeType("probe1"))); + new de.rub.nds.scanner.core.probe.requirements.Requirement() { + @Override + public boolean evaluate(TestReport report) { + return report.getExecutedProbeTypes().contains(new TestProbeType("probe1")); + } + }); List probeList = Arrays.asList(probe1, probe2); List afterList = new ArrayList<>(); @@ -314,7 +331,7 @@ public void testPropertyChangeListener() throws InterruptedException { executor.execute(report); - assertEquals(2, report.getExecutedProbes().size()); + assertEquals(2, report.getExecutedProbeTypes().size()); assertTrue(probe1.wasExecuted()); assertTrue(probe2.wasExecuted()); } @@ -400,7 +417,7 @@ public void testConstructorWithCustomExecutor() throws InterruptedException { TestReport report = new TestReport(); executor.execute(report); - assertEquals(1, report.getExecutedProbes().size()); + assertEquals(1, report.getExecutedProbeTypes().size()); executor.shutdown(); customExecutor.shutdown(); @@ -440,7 +457,7 @@ public void testEmptyProbeList() throws InterruptedException { TestReport report = new TestReport(); executor.execute(report); - assertTrue(report.getExecutedProbes().isEmpty()); + assertTrue(report.getExecutedProbeTypes().isEmpty()); assertTrue(afterList.get(0).isAnalyzed()); // After probes should still run } } From bc8cd7a6c6c7eaacc3f95c72ee64ee802cb33feb Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Wed, 18 Jun 2025 21:21:04 +0000 Subject: [PATCH 10/14] Fix final compilation errors - Fix Guideline constructor to use 3 parameters - Change List to Set for probe type collections in TestReport - Add missing imports (HashSet, Set) --- .../scanner/core/execution/ScannerTest.java | 13 +++++++------ .../ThreadedScanJobExecutorTest.java | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index de327c21..15899176 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -326,10 +326,12 @@ public void testRegisterAfterProbe() { @Test public void testScanWithSiteReportRater() { TestScanner scanner = new TestScanner(executorConfig); - de.rub.nds.scanner.core.report.rating.RatingInfluencers influencers = - new de.rub.nds.scanner.core.report.rating.RatingInfluencers(new java.util.LinkedList<>()); - de.rub.nds.scanner.core.report.rating.Recommendations recommendations = - new de.rub.nds.scanner.core.report.rating.Recommendations(new java.util.LinkedList<>()); + de.rub.nds.scanner.core.report.rating.RatingInfluencers influencers = + new de.rub.nds.scanner.core.report.rating.RatingInfluencers( + new java.util.LinkedList<>()); + de.rub.nds.scanner.core.report.rating.Recommendations recommendations = + new de.rub.nds.scanner.core.report.rating.Recommendations( + new java.util.LinkedList<>()); SiteReportRater rater = new SiteReportRater(influencers, recommendations); scanner.setSiteReportRater(rater); @@ -342,8 +344,7 @@ public void testScanWithSiteReportRater() { public void testScanWithGuidelines() { TestScanner scanner = new TestScanner(executorConfig); - Guideline guideline = - new Guideline("TestGuideline", null); + Guideline guideline = new Guideline("TestGuideline", "http://example.com", new ArrayList<>()); scanner.setGuidelines(List.of(guideline)); TestReport report = scanner.scan(); diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java index aaca5f7e..39bec010 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -23,8 +23,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; import org.junit.jupiter.api.BeforeEach; @@ -64,8 +66,8 @@ public int hashCode() { static class TestState {} static class TestReport extends ScanReport { - private final List executedProbeTypes = new ArrayList<>(); - private final List unexecutedProbeTypes = new ArrayList<>(); + private final Set executedProbeTypes = new HashSet<>(); + private final Set unexecutedProbeTypes = new HashSet<>(); private final Map> extractedContainers = new HashMap<>(); @@ -91,11 +93,11 @@ public void markProbeAsUnexecuted(ScannerProbe probe) { super.markProbeAsUnexecuted(probe); } - public List getExecutedProbeTypes() { + public Set getExecutedProbeTypes() { return executedProbeTypes; } - public List getUnexecutedProbeTypes() { + public Set getUnexecutedProbeTypes() { return unexecutedProbeTypes; } @@ -114,7 +116,8 @@ static class TestProbe extends ScannerProbe { private boolean canExecute = true; private boolean wasExecuted = false; private boolean shouldThrowException = false; - private Requirement requirement = new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + private Requirement requirement = + new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); TestProbe(ProbeType type) { super(type); @@ -150,9 +153,11 @@ protected void mergeData(TestReport report) {} public void setCanExecute(boolean canExecute) { this.canExecute = canExecute; if (canExecute) { - this.requirement = new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + this.requirement = + new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); } else { - this.requirement = new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); + this.requirement = + new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); } } From 1accb7f0c6ebcf55dfe2fd84d95e1448d0b4e226 Mon Sep 17 00:00:00 2001 From: Robert Merget Date: Thu, 19 Jun 2025 07:49:27 +0400 Subject: [PATCH 11/14] formatted --- .../java/de/rub/nds/scanner/core/execution/ScannerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index 15899176..82ddc54b 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -344,7 +344,8 @@ public void testScanWithSiteReportRater() { public void testScanWithGuidelines() { TestScanner scanner = new TestScanner(executorConfig); - Guideline guideline = new Guideline("TestGuideline", "http://example.com", new ArrayList<>()); + Guideline guideline = + new Guideline("TestGuideline", "http://example.com", new ArrayList<>()); scanner.setGuidelines(List.of(guideline)); TestReport report = scanner.scan(); From 7575f110b18ae5a9880ddb383426de725fa9422c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=A4umer?= Date: Wed, 2 Jul 2025 14:45:57 +0200 Subject: [PATCH 12/14] fix: Use separate timer to cancel tasks to avoid deadlock --- .../execution/ScannerThreadPoolExecutor.java | 54 ++++++++++++++----- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutor.java b/src/main/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutor.java index 4e7c4086..f662ccff 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutor.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutor.java @@ -8,6 +8,9 @@ */ package de.rub.nds.scanner.core.execution; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionHandler; @@ -15,14 +18,13 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; /** * Extends {@link ThreadPoolExecutor} with its own afterExecute function. A * ScannerThreadPoolExecutor hold a semaphore which is released each time a Thread finished - * executing. + * executing or is aborted on timeout. */ public class ScannerThreadPoolExecutor extends ScheduledThreadPoolExecutor { @@ -35,6 +37,8 @@ public class ScannerThreadPoolExecutor extends ScheduledThreadPoolExecutor { /** The time after which tasks are automatically cancelled */ private final long timeout; + private final Timer timer; + /** * Call super and assign the semaphore * @@ -50,6 +54,7 @@ public ScannerThreadPoolExecutor( this.timeout = timeout; this.setContinueExistingPeriodicTasksAfterShutdownPolicy(false); this.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + this.timer = new Timer(); } /** @@ -84,6 +89,7 @@ public Future submit(Runnable task) { * @param result the result to return when the task completes * @return a Future representing pending completion of the task */ + @Override public Future submit(Runnable task, T result) { Future future = super.submit(task, result); cancelFuture(future); @@ -98,28 +104,48 @@ public Future submit(Runnable task, T result) { * @param task the task to submit * @return a Future representing pending completion of the task */ + @Override public Future submit(Callable task) { Future future = super.submit(task); cancelFuture(future); return future; } + @Override + public void shutdown() { + super.shutdown(); + timer.cancel(); + } + + @Override + public List shutdownNow() { + timer.cancel(); + return super.shutdownNow(); + } + + @Override + public void close() { + super.close(); + timer.cancel(); + } + private void cancelFuture(Future future) { - this.schedule( - () -> { - if (!future.isDone()) { - future.cancel(true); - if (future.isCancelled()) { - LOGGER.error("Killed task {}", future); + timer.schedule( + new TimerTask() { + @Override + public void run() { + if (!future.isDone()) { + future.cancel(true); + if (future.isCancelled()) { + LOGGER.error("Killed task {}", future); + } else { + LOGGER.error("Could not kill task {}", future); + } } else { - LOGGER.error("Could not kill task {}", future); + LOGGER.debug("Future already done! {}", future); } - } else { - LOGGER.debug("Future already done! {}", future); } - semaphore.release(); }, - timeout, - TimeUnit.MILLISECONDS); + timeout); } } From a8a995d8ad6e6a353e5617bfde46d2a747e2c9a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=A4umer?= Date: Wed, 2 Jul 2025 14:47:50 +0200 Subject: [PATCH 13/14] fix: Make sure the scan job executor and thread pool use the same semaphore instance --- .../core/execution/ThreadedScanJobExecutor.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java index 09410277..4a8ce77e 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java @@ -20,10 +20,8 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.Semaphore; -import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.*; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -57,7 +55,7 @@ public class ThreadedScanJobExecutor< private final ThreadPoolExecutor executor; // Used for waiting for Threads in the ThreadPoolExecutor - private final Semaphore semaphore = new Semaphore(0); + private final Semaphore semaphore; private int probeCount; private int finishedProbes = 0; @@ -76,7 +74,8 @@ public ThreadedScanJobExecutor( int threadCount, String prefix) { long probeTimeout = config.getProbeTimeout(); - executor = + this.semaphore = new Semaphore(0); + this.executor = new ScannerThreadPoolExecutor( threadCount, new NamedThreadFactory(prefix), semaphore, probeTimeout); this.config = config; @@ -90,11 +89,14 @@ public ThreadedScanJobExecutor( * @param config the executor configuration * @param scanJob the scan job containing probes to execute * @param executor the thread pool executor to use + * @param semaphore the semaphore released by the executor when a probe finishes */ public ThreadedScanJobExecutor( ExecutorConfig config, ScanJob scanJob, - ThreadPoolExecutor executor) { + ThreadPoolExecutor executor, + Semaphore semaphore) { + this.semaphore = semaphore; this.executor = executor; this.config = config; this.scanJob = scanJob; From f0f299bfdcd48637ff7c1b6a41e34ef8632c92f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20B=C3=A4umer?= Date: Wed, 2 Jul 2025 14:49:44 +0200 Subject: [PATCH 14/14] test: Minor improvements to readability and style --- .../execution/ThreadedScanJobExecutor.java | 1 - .../execution/NamedThreadFactoryTest.java | 11 +- .../core/execution/ScanJobExecutorTest.java | 13 +- .../scanner/core/execution/ScanJobTest.java | 15 +- .../scanner/core/execution/ScannerTest.java | 168 ++++++----- .../ScannerThreadPoolExecutorTest.java | 272 +++++++++--------- .../ThreadedScanJobExecutorTest.java | 52 ++-- 7 files changed, 271 insertions(+), 261 deletions(-) diff --git a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java index 4a8ce77e..c254a1d7 100644 --- a/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java +++ b/src/main/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutor.java @@ -21,7 +21,6 @@ import java.util.LinkedList; import java.util.List; import java.util.concurrent.*; - import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java index c3871d70..bd2b5a93 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/NamedThreadFactoryTest.java @@ -8,9 +8,7 @@ */ package de.rub.nds.scanner.core.execution; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; @@ -49,7 +47,7 @@ public void testThreadsAreNotDaemon() { Thread thread = factory.newThread(() -> {}); // Default thread factory creates non-daemon threads - assertTrue(!thread.isDaemon()); + assertFalse(thread.isDaemon()); } @Test @@ -69,10 +67,7 @@ public void testThreadExecutesRunnable() throws InterruptedException { NamedThreadFactory factory = new NamedThreadFactory("Executor"); AtomicInteger counter = new AtomicInteger(0); - Runnable runnable = - () -> { - counter.incrementAndGet(); - }; + Runnable runnable = counter::incrementAndGet; Thread thread = factory.newThread(runnable); thread.start(); diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java index 4978147a..04c57e5a 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobExecutorTest.java @@ -11,6 +11,7 @@ import static org.junit.jupiter.api.Assertions.*; import de.rub.nds.scanner.core.report.ScanReport; +import java.lang.reflect.Modifier; import org.junit.jupiter.api.Test; public class ScanJobExecutorTest { @@ -44,7 +45,7 @@ static class TestScanJobExecutor extends ScanJobExecutor { private int executeCallCount = 0; @Override - public void execute(TestReport report) throws InterruptedException { + public void execute(TestReport report) { executeCallCount++; report.setExecuted(true); } @@ -75,7 +76,7 @@ public void shutdown() {} } @Test - public void testExecuteMethod() throws InterruptedException { + public void testExecuteMethod() { TestScanJobExecutor executor = new TestScanJobExecutor(); TestReport report = new TestReport(); @@ -96,7 +97,7 @@ public void testShutdownMethod() { } @Test - public void testMultipleExecuteCalls() throws InterruptedException { + public void testMultipleExecuteCalls() { TestScanJobExecutor executor = new TestScanJobExecutor(); TestReport report1 = new TestReport(); TestReport report2 = new TestReport(); @@ -123,14 +124,14 @@ public void testExecuteThrowsInterruptedException() { @Test public void testAbstractClass() { // Verify that ScanJobExecutor is abstract and cannot be instantiated directly - assertTrue(java.lang.reflect.Modifier.isAbstract(ScanJobExecutor.class.getModifiers())); + assertTrue(Modifier.isAbstract(ScanJobExecutor.class.getModifiers())); } @Test public void testExecuteMethodSignature() throws NoSuchMethodException { // Verify the execute method signature var method = ScanJobExecutor.class.getDeclaredMethod("execute", ScanReport.class); - assertTrue(java.lang.reflect.Modifier.isAbstract(method.getModifiers())); + assertTrue(Modifier.isAbstract(method.getModifiers())); assertEquals(void.class, method.getReturnType()); // Check that it declares InterruptedException @@ -143,7 +144,7 @@ public void testExecuteMethodSignature() throws NoSuchMethodException { public void testShutdownMethodSignature() throws NoSuchMethodException { // Verify the shutdown method signature var method = ScanJobExecutor.class.getDeclaredMethod("shutdown"); - assertTrue(java.lang.reflect.Modifier.isAbstract(method.getModifiers())); + assertTrue(Modifier.isAbstract(method.getModifiers())); assertEquals(void.class, method.getReturnType()); assertEquals(0, method.getExceptionTypes().length); } diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java index 323b7f20..821e962e 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScanJobTest.java @@ -11,8 +11,12 @@ import static org.junit.jupiter.api.Assertions.*; import de.rub.nds.scanner.core.afterprobe.AfterProbe; +import de.rub.nds.scanner.core.probe.ProbeType; import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement; +import de.rub.nds.scanner.core.probe.requirements.Requirement; import de.rub.nds.scanner.core.report.ScanReport; +import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.Test; @@ -27,7 +31,7 @@ public String getRemoteName() { } @Override - public void serializeToJson(java.io.OutputStream outputStream) { + public void serializeToJson(OutputStream outputStream) { // Simple implementation for testing } } @@ -35,20 +39,17 @@ public void serializeToJson(java.io.OutputStream outputStream) { static class TestState {} static class TestProbe extends ScannerProbe { - private final String name; TestProbe(String name) { super(new TestProbeType(name)); - this.name = name; } @Override public void executeTest() {} @Override - public de.rub.nds.scanner.core.probe.requirements.Requirement - getRequirements() { - return new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + public Requirement getRequirements() { + return new FulfilledRequirement<>(); } @Override @@ -73,7 +74,7 @@ public String getName() { } } - static class TestProbeType implements de.rub.nds.scanner.core.probe.ProbeType { + static class TestProbeType implements ProbeType { private final String name; TestProbeType(String name) { diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java index 82ddc54b..aa6983dc 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerTest.java @@ -16,12 +16,19 @@ import de.rub.nds.scanner.core.passive.StatsWriter; import de.rub.nds.scanner.core.probe.ProbeType; import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement; +import de.rub.nds.scanner.core.probe.requirements.Requirement; +import de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement; import de.rub.nds.scanner.core.report.ScanReport; +import de.rub.nds.scanner.core.report.rating.RatingInfluencers; +import de.rub.nds.scanner.core.report.rating.Recommendations; import de.rub.nds.scanner.core.report.rating.SiteReportRater; import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.nio.file.Files; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -50,20 +57,19 @@ public String getName() { static class TestState {} static class TestReport extends ScanReport { - private String remoteName = "TestHost"; private boolean prerequisitesFulfilled = true; @Override public String getRemoteName() { - return remoteName; + return "TestHost"; } @Override - public void serializeToJson(java.io.OutputStream outputStream) { + public void serializeToJson(OutputStream outputStream) { // Simple implementation for testing try { outputStream.write("{\"remoteName\":\"TestHost\"}".getBytes()); - } catch (java.io.IOException e) { + } catch (IOException e) { // Ignore for testing } } @@ -91,12 +97,11 @@ public void executeTest() { } @Override - public de.rub.nds.scanner.core.probe.requirements.Requirement - getRequirements() { + public Requirement getRequirements() { if (canExecute) { - return new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + return new FulfilledRequirement<>(); } else { - return new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); + return new UnfulfillableRequirement<>(); } } @@ -237,13 +242,14 @@ public void setUp() { @Test public void testScanWithDefaultConstructor() { - TestScanner scanner = new TestScanner(executorConfig); - TestReport report = scanner.scan(); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestReport report = scanner.scan(); - assertNotNull(report); - assertTrue(scanner.isFillProbesCalled()); - assertTrue(scanner.isOnScanStartCalled()); - assertTrue(scanner.isOnScanEndCalled()); + assertNotNull(report); + assertTrue(scanner.isFillProbesCalled()); + assertTrue(scanner.isOnScanStartCalled()); + assertTrue(scanner.isOnScanEndCalled()); + } } @Test @@ -254,101 +260,109 @@ public void testScanWithProbesConstructor() { List afterList = new ArrayList<>(); afterList.add(new TestAfterProbe()); - TestScanner scanner = new TestScanner(executorConfig, probeList, afterList); - TestReport report = scanner.scan(); + try (TestScanner scanner = new TestScanner(executorConfig, probeList, afterList)) { + TestReport report = scanner.scan(); - assertNotNull(report); - assertFalse(scanner.isFillProbesCalled()); // Should not be called when probes are provided + assertNotNull(report); + assertFalse( + scanner.isFillProbesCalled()); // Should not be called when probes are provided + } } @Test public void testScanPrerequisitesNotFulfilled() { - TestScanner scanner = new TestScanner(executorConfig); - TestReport report = new TestReport(); - report.setPrerequisitesFulfilled(false); - scanner.setReportToReturn(report); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestReport report = new TestReport(); + report.setPrerequisitesFulfilled(false); + scanner.setReportToReturn(report); - TestReport result = scanner.scan(); + TestReport result = scanner.scan(); - assertSame(report, result); - assertTrue(scanner.isOnScanStartCalled()); - assertFalse(scanner.isOnScanEndCalled()); // Should not reach end if prerequisites fail + assertSame(report, result); + assertTrue(scanner.isOnScanStartCalled()); + assertFalse(scanner.isOnScanEndCalled()); // Should not reach end if prerequisites fail + } } @Test public void testRegisterProbeForExecution() { - TestScanner scanner = new TestScanner(executorConfig); - TestProbe probe = new TestProbe(new TestProbeType("test")); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestProbe probe = new TestProbe(new TestProbeType("test")); - scanner.registerProbeForExecution(probe); + scanner.registerProbeForExecution(probe); + } // Since this adds to internal probe list, we can't directly verify // But the test ensures no exceptions are thrown } @Test public void testRegisterProbeWithExecuteByDefault() { - TestScanner scanner = new TestScanner(executorConfig); - TestProbe probe = new TestProbe(new TestProbeType("test")); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestProbe probe = new TestProbe(new TestProbeType("test")); - scanner.registerProbeForExecution(probe, false); + scanner.registerProbeForExecution(probe, false); + } // Test with executeByDefault = false } @Test public void testRegisterProbeWithSpecificProbesConfig() { executorConfig.setProbes(List.of(new TestProbeType("allowed"))); - TestScanner scanner = new TestScanner(executorConfig); + try (TestScanner scanner = new TestScanner(executorConfig)) { - TestProbe allowedProbe = new TestProbe(new TestProbeType("allowed")); - TestProbe notAllowedProbe = new TestProbe(new TestProbeType("notallowed")); + TestProbe allowedProbe = new TestProbe(new TestProbeType("allowed")); + TestProbe notAllowedProbe = new TestProbe(new TestProbeType("notallowed")); - scanner.registerProbeForExecution(allowedProbe); - scanner.registerProbeForExecution(notAllowedProbe); + scanner.registerProbeForExecution(allowedProbe); + scanner.registerProbeForExecution(notAllowedProbe); + } } @Test public void testRegisterProbeWithExcludedProbes() { executorConfig.setExcludedProbes(List.of(new TestProbeType("excluded"))); - TestScanner scanner = new TestScanner(executorConfig); + try (TestScanner scanner = new TestScanner(executorConfig)) { - TestProbe excludedProbe = new TestProbe(new TestProbeType("excluded")); - scanner.registerProbeForExecution(excludedProbe); + TestProbe excludedProbe = new TestProbe(new TestProbeType("excluded")); + scanner.registerProbeForExecution(excludedProbe); + } } @Test public void testRegisterAfterProbe() { - TestScanner scanner = new TestScanner(executorConfig); - TestAfterProbe afterProbe = new TestAfterProbe(); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestAfterProbe afterProbe = new TestAfterProbe(); - scanner.registerProbeForExecution(afterProbe); + scanner.registerProbeForExecution(afterProbe); + } } @Test public void testScanWithSiteReportRater() { - TestScanner scanner = new TestScanner(executorConfig); - de.rub.nds.scanner.core.report.rating.RatingInfluencers influencers = - new de.rub.nds.scanner.core.report.rating.RatingInfluencers( - new java.util.LinkedList<>()); - de.rub.nds.scanner.core.report.rating.Recommendations recommendations = - new de.rub.nds.scanner.core.report.rating.Recommendations( - new java.util.LinkedList<>()); - SiteReportRater rater = new SiteReportRater(influencers, recommendations); - scanner.setSiteReportRater(rater); - - TestReport report = scanner.scan(); + TestReport report; + try (TestScanner scanner = new TestScanner(executorConfig)) { + RatingInfluencers influencers = new RatingInfluencers(new LinkedList<>()); + Recommendations recommendations = new Recommendations(new LinkedList<>()); + SiteReportRater rater = new SiteReportRater(influencers, recommendations); + scanner.setSiteReportRater(rater); + + report = scanner.scan(); + } assertNotNull(report.getScoreReport()); } @Test public void testScanWithGuidelines() { - TestScanner scanner = new TestScanner(executorConfig); + TestReport report; + try (TestScanner scanner = new TestScanner(executorConfig)) { - Guideline guideline = - new Guideline("TestGuideline", "http://example.com", new ArrayList<>()); + Guideline guideline = + new Guideline<>("TestGuideline", "http://example.com", new ArrayList<>()); - scanner.setGuidelines(List.of(guideline)); - TestReport report = scanner.scan(); + scanner.setGuidelines(List.of(guideline)); + report = scanner.scan(); + } assertNotNull(report); } @@ -358,8 +372,9 @@ public void testScanWithFileOutput() throws IOException { File outputFile = new File(tempDir, "test-report.json"); executorConfig.setOutputFile(outputFile.getAbsolutePath()); - TestScanner scanner = new TestScanner(executorConfig); - TestReport report = scanner.scan(); + try (TestScanner scanner = new TestScanner(executorConfig)) { + TestReport report = scanner.scan(); + } assertTrue(outputFile.exists()); String content = Files.readString(outputFile.toPath()); @@ -371,9 +386,9 @@ public void testScanWithInvalidOutputFile() { File invalidFile = new File("/invalid/path/that/does/not/exist/report.json"); executorConfig.setOutputFile(invalidFile.getAbsolutePath()); - TestScanner scanner = new TestScanner(executorConfig); - - assertThrows(RuntimeException.class, scanner::scan); + try (TestScanner scanner = new TestScanner(executorConfig)) { + assertThrows(RuntimeException.class, scanner::scan); + } } @Test @@ -381,7 +396,7 @@ public void testAutoCloseable() throws Exception { TestScanner scanner = new TestScanner(executorConfig); // Test that Scanner implements AutoCloseable - assertTrue(scanner instanceof AutoCloseable); + assertInstanceOf(AutoCloseable.class, scanner); // Test close method scanner.close(); @@ -389,8 +404,10 @@ public void testAutoCloseable() throws Exception { @Test public void testScanTimingMeasurement() { - TestScanner scanner = new TestScanner(executorConfig); - TestReport report = scanner.scan(); + TestReport report; + try (TestScanner scanner = new TestScanner(executorConfig)) { + report = scanner.scan(); + } assertTrue(report.getScanStartTime() > 0); assertTrue(report.getScanEndTime() > 0); @@ -399,14 +416,15 @@ public void testScanTimingMeasurement() { @Test public void testInterruptedScan() throws InterruptedException { - TestScanner scanner = new TestScanner(executorConfig); - - Thread testThread = - new Thread( - () -> { - Thread.currentThread().interrupt(); - scanner.scan(); - }); + Thread testThread; + try (TestScanner scanner = new TestScanner(executorConfig)) { + testThread = + new Thread( + () -> { + Thread.currentThread().interrupt(); + scanner.scan(); + }); + } testThread.start(); testThread.join(); diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java index 38599f2c..95050b0b 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ScannerThreadPoolExecutorTest.java @@ -39,212 +39,210 @@ public void testBasicConstruction() { @Test public void testSubmitRunnable() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - - AtomicBoolean taskExecuted = new AtomicBoolean(false); - Future future = executor.submit(() -> taskExecuted.set(true)); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + AtomicBoolean taskExecuted = new AtomicBoolean(false); + Future future = executor.submit(() -> taskExecuted.set(true)); - // Wait for task completion - semaphore.acquire(); + // Wait for task completion + semaphore.acquire(); - assertTrue(taskExecuted.get()); - assertTrue(future.isDone()); + assertTrue(taskExecuted.get()); + assertTrue(future.isDone()); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testSubmitRunnableWithResult() throws InterruptedException, ExecutionException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - - String result = "TestResult"; - AtomicBoolean taskExecuted = new AtomicBoolean(false); - Future future = executor.submit(() -> taskExecuted.set(true), result); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + String result = "TestResult"; + AtomicBoolean taskExecuted = new AtomicBoolean(false); + Future future = executor.submit(() -> taskExecuted.set(true), result); - // Wait for task completion - semaphore.acquire(); + // Wait for task completion + semaphore.acquire(); - assertTrue(taskExecuted.get()); - assertEquals(result, future.get()); + assertTrue(taskExecuted.get()); + assertEquals(result, future.get()); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testSubmitCallable() throws InterruptedException, ExecutionException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + Callable callable = () -> 42; + Future future = executor.submit(callable); - Callable callable = () -> 42; - Future future = executor.submit(callable); - - // Wait for task completion - semaphore.acquire(); + // Wait for task completion + semaphore.acquire(); - assertEquals(42, future.get()); + assertEquals(42, future.get()); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testSemaphoreReleasedAfterTaskCompletion() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + executor.submit( + () -> { + // Simple task + }); - executor.submit( - () -> { - // Simple task - }); + // Should be able to acquire, proving semaphore was released + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - // Should be able to acquire, proving semaphore was released - assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - - executor.shutdown(); + executor.shutdown(); + } } @Test public void testSemaphoreReleasedOnException() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - - executor.submit( - () -> { - throw new RuntimeException("Test exception"); - }); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + executor.submit( + () -> { + throw new RuntimeException("Test exception"); + }); - // Semaphore should still be released even when task throws exception - assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); + // Semaphore should still be released even when task throws exception + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testTaskTimeout() throws InterruptedException { Semaphore semaphore = new Semaphore(0); // Set very short timeout - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 100); - - CountDownLatch taskStarted = new CountDownLatch(1); - AtomicBoolean taskCompleted = new AtomicBoolean(false); - - Future future = - executor.submit( - () -> { - taskStarted.countDown(); - try { - Thread.sleep(500); // Sleep longer than timeout - taskCompleted.set(true); - } catch (InterruptedException e) { - // Expected when task is cancelled - } - }); - - // Wait for task to start - taskStarted.await(); - - // Wait for timeout to trigger - Thread.sleep(200); - - assertTrue(future.isCancelled()); - assertFalse(taskCompleted.get()); - - // Semaphore should be released after timeout - assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); - - executor.shutdown(); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 100)) { + CountDownLatch taskStarted = new CountDownLatch(1); + AtomicBoolean taskCompleted = new AtomicBoolean(false); + + Future future = + executor.submit( + () -> { + taskStarted.countDown(); + try { + Thread.sleep(500); // Sleep longer than timeout + taskCompleted.set(true); + } catch (InterruptedException e) { + // Expected when task is cancelled + } + }); + + // Wait for task to start + taskStarted.await(); + + // Wait for timeout to trigger + Thread.sleep(200); + + assertTrue(future.isCancelled()); + assertFalse(taskCompleted.get()); + + // Semaphore should be released after timeout + assertTrue(semaphore.tryAcquire(1, TimeUnit.SECONDS)); + + executor.shutdown(); + } } @Test public void testMultipleTasks() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(3, new NamedThreadFactory("Test"), semaphore, 5000); - - AtomicInteger counter = new AtomicInteger(0); - int taskCount = 10; + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(3, new NamedThreadFactory("Test"), semaphore, 5000)) { + AtomicInteger counter = new AtomicInteger(0); + int taskCount = 10; - for (int i = 0; i < taskCount; i++) { - executor.submit(counter::incrementAndGet); - } + for (int i = 0; i < taskCount; i++) { + executor.submit(counter::incrementAndGet); + } - // Wait for all tasks - for (int i = 0; i < taskCount; i++) { - semaphore.acquire(); - } + // Wait for all tasks + for (int i = 0; i < taskCount; i++) { + semaphore.acquire(); + } - assertEquals(taskCount, counter.get()); + assertEquals(taskCount, counter.get()); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testShutdownBehavior() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + AtomicBoolean taskExecuted = new AtomicBoolean(false); + executor.submit(() -> taskExecuted.set(true)); - AtomicBoolean taskExecuted = new AtomicBoolean(false); - executor.submit(() -> taskExecuted.set(true)); + semaphore.acquire(); + assertTrue(taskExecuted.get()); - semaphore.acquire(); - assertTrue(taskExecuted.get()); + executor.shutdown(); + assertTrue(executor.isShutdown()); - executor.shutdown(); - assertTrue(executor.isShutdown()); - - // Should not accept new tasks after shutdown - assertThrows( - RejectedExecutionException.class, - () -> { - executor.submit(() -> {}); - }); + // Should not accept new tasks after shutdown + assertThrows( + RejectedExecutionException.class, + () -> { + executor.submit(() -> {}); + }); + } } @Test public void testContinueExistingPeriodicTasksPolicy() { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000); - - // These are set in constructor - assertFalse(executor.getContinueExistingPeriodicTasksAfterShutdownPolicy()); - assertFalse(executor.getExecuteExistingDelayedTasksAfterShutdownPolicy()); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 5000)) { + // These are set in constructor + assertFalse(executor.getContinueExistingPeriodicTasksAfterShutdownPolicy()); + assertFalse(executor.getExecuteExistingDelayedTasksAfterShutdownPolicy()); - executor.shutdown(); + executor.shutdown(); + } } @Test public void testTaskAlreadyDoneBeforeTimeout() throws InterruptedException { Semaphore semaphore = new Semaphore(0); - ScannerThreadPoolExecutor executor = - new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 1000); - - CountDownLatch timeoutCheckLatch = new CountDownLatch(1); - - // Submit a quick task - Future future = - executor.submit( - () -> { - // Quick task that completes before timeout - }); - - // Wait for task completion - semaphore.acquire(); - assertTrue(future.isDone()); + try (ScannerThreadPoolExecutor executor = + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Test"), semaphore, 1000)) { + // Submit a quick task + Future future = + executor.submit( + () -> { + // Quick task that completes before timeout + }); + + // Wait for task completion + semaphore.acquire(); + assertTrue(future.isDone()); - // Wait a bit to ensure timeout task runs - Thread.sleep(1100); + // Wait a bit to ensure timeout task runs + Thread.sleep(1100); - // The timeout task should have run but found the future already done - // No exception should be thrown + // The timeout task should have run but found the future already done + // No exception should be thrown - executor.shutdown(); + executor.shutdown(); + } } } diff --git a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java index 39bec010..59d5a056 100644 --- a/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java +++ b/src/test/java/de/rub/nds/scanner/core/execution/ThreadedScanJobExecutorTest.java @@ -17,9 +17,12 @@ import de.rub.nds.scanner.core.passive.TrackableValue; import de.rub.nds.scanner.core.probe.ProbeType; import de.rub.nds.scanner.core.probe.ScannerProbe; +import de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement; import de.rub.nds.scanner.core.probe.requirements.Requirement; +import de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement; import de.rub.nds.scanner.core.report.ScanReport; import java.beans.PropertyChangeEvent; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -77,7 +80,7 @@ public String getRemoteName() { } @Override - public void serializeToJson(java.io.OutputStream outputStream) { + public void serializeToJson(OutputStream outputStream) { // Simple implementation for testing } @@ -113,11 +116,9 @@ public void putAllExtractedValueContainers( } static class TestProbe extends ScannerProbe { - private boolean canExecute = true; private boolean wasExecuted = false; private boolean shouldThrowException = false; - private Requirement requirement = - new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + private Requirement requirement = new FulfilledRequirement<>(); TestProbe(ProbeType type) { super(type); @@ -151,13 +152,10 @@ public void adjustConfig(TestReport report) {} protected void mergeData(TestReport report) {} public void setCanExecute(boolean canExecute) { - this.canExecute = canExecute; if (canExecute) { - this.requirement = - new de.rub.nds.scanner.core.probe.requirements.FulfilledRequirement<>(); + this.requirement = new FulfilledRequirement<>(); } else { - this.requirement = - new de.rub.nds.scanner.core.probe.requirements.UnfulfillableRequirement<>(); + this.requirement = new UnfulfillableRequirement<>(); } } @@ -235,7 +233,7 @@ public void testBasicExecution() throws InterruptedException { Arrays.asList( new TestProbe(new TestProbeType("probe1")), new TestProbe(new TestProbeType("probe2"))); - List afterList = Arrays.asList(new TestAfterProbe()); + List afterList = List.of(new TestAfterProbe()); ScanJob scanJob = new ScanJob<>(probeList, afterList); @@ -247,9 +245,9 @@ public void testBasicExecution() throws InterruptedException { executor.execute(report); assertEquals(2, report.getExecutedProbeTypes().size()); - assertTrue(probeList.get(0).wasExecuted()); + assertTrue(probeList.getFirst().wasExecuted()); assertTrue(probeList.get(1).wasExecuted()); - assertTrue(afterList.get(0).isAnalyzed()); + assertTrue(afterList.getFirst().isAnalyzed()); } } @@ -279,7 +277,7 @@ public void testProbesThatCannotBeExecuted() throws InterruptedException { } @Test - public void testProbeExecutionException() throws InterruptedException { + public void testProbeExecutionException() { TestProbe normalProbe = new TestProbe(new TestProbeType("normal")); TestProbe failingProbe = new TestProbe(new TestProbeType("failing")); failingProbe.setShouldThrowException(true); @@ -307,7 +305,7 @@ public void testPropertyChangeListener() throws InterruptedException { // Add requirement that probe1 must be executed first probe2.addRequirement( - new de.rub.nds.scanner.core.probe.requirements.Requirement() { + new Requirement<>() { @Override public boolean evaluate(TestReport report) { return report.getExecutedProbeTypes().contains(new TestProbeType("probe1")); @@ -371,25 +369,25 @@ public void testStatisticsCollection() throws InterruptedException { @Test public void testShutdown() throws InterruptedException { - List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List probeList = List.of(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); ScanJob scanJob = new ScanJob<>(probeList, afterList); - ThreadedScanJobExecutor executor = - new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test"); - - TestReport report = new TestReport(); - executor.execute(report); + try (ThreadedScanJobExecutor executor = + new ThreadedScanJobExecutor<>(executorConfig, scanJob, 1, "Test")) { + TestReport report = new TestReport(); + executor.execute(report); - executor.shutdown(); + executor.shutdown(); + } // Should not throw exception } @Test public void testAutoCloseable() throws Exception { - List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List probeList = List.of(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); ScanJob scanJob = @@ -406,18 +404,18 @@ public void testAutoCloseable() throws Exception { @Test public void testConstructorWithCustomExecutor() throws InterruptedException { - List probeList = Arrays.asList(new TestProbe(new TestProbeType("probe1"))); + List probeList = List.of(new TestProbe(new TestProbeType("probe1"))); List afterList = new ArrayList<>(); ScanJob scanJob = new ScanJob<>(probeList, afterList); + Semaphore semaphore = new Semaphore(0); ThreadPoolExecutor customExecutor = - new ScannerThreadPoolExecutor( - 1, new NamedThreadFactory("Custom"), new Semaphore(0), 5000); + new ScannerThreadPoolExecutor(1, new NamedThreadFactory("Custom"), semaphore, 5000); ThreadedScanJobExecutor executor = - new ThreadedScanJobExecutor<>(executorConfig, scanJob, customExecutor); + new ThreadedScanJobExecutor<>(executorConfig, scanJob, customExecutor, semaphore); TestReport report = new TestReport(); executor.execute(report); @@ -451,7 +449,7 @@ public void testPropertyChangeWithInvalidSource() { @Test public void testEmptyProbeList() throws InterruptedException { List probeList = new ArrayList<>(); - List afterList = Arrays.asList(new TestAfterProbe()); + List afterList = List.of(new TestAfterProbe()); ScanJob scanJob = new ScanJob<>(probeList, afterList);