From 967445e29e9fb80b1dee87c2bd2b69f55219af66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Sun, 25 May 2025 16:52:40 +0200 Subject: [PATCH 01/14] DataWordSULWrapper, copied from StateFuzzerComposerRA NOTE: We might want to use this class in StateFuzzerComposerRA now that it exists as a standalone component --- .../core/sulwrappers/DataWordSULWrapper.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java new file mode 100644 index 00000000..072d0dbe --- /dev/null +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java @@ -0,0 +1,39 @@ +package com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers; + +import de.learnlib.ralib.sul.DataWordSUL; +import de.learnlib.sul.SUL; +import de.learnlib.ralib.words.PSymbolInstance; + +/** + * A wrapper that can be used as an {@code SUL} + * to DataWordSUL converter. Copied from StateFuzzerComposerRA. + */ +public class DataWordSULWrapper extends DataWordSUL { + + /** Stores the wrapped sul */ + protected SUL sul; + + /** + * Constructs a new instance from the given parameters. + * + * @param sul the wrapped sul + */ + public DataWordSULWrapper(SUL sul) { + this.sul = sul; + } + + @Override + public void pre() { + sul.pre(); + } + + @Override + public void post() { + sul.post(); + } + + @Override + public PSymbolInstance step(PSymbolInstance in) { + return sul.step(in); + } +} From b5646c09164c420386a9b0692d6c93fbec746541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Sun, 25 May 2025 16:55:18 +0200 Subject: [PATCH 02/14] Create MembershipOracleWrapper, wraps a RALib SULOracle to make it behave like a MembershipOracle required by TestRunner --- .../oracles/MembershipOracleWrapper.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java new file mode 100644 index 00000000..0ff9c17d --- /dev/null +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java @@ -0,0 +1,27 @@ +package com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles; + +import java.util.Collection; + +import de.learnlib.oracle.MembershipOracle; +import de.learnlib.query.Query; +import de.learnlib.ralib.sul.SULOracle; +import de.learnlib.ralib.words.PSymbolInstance; +import net.automatalib.word.Word; + +public class MembershipOracleWrapper implements MembershipOracle> { + + private SULOracle wrappedOracle; + + public MembershipOracleWrapper(SULOracle wrappedOracle) { + this.wrappedOracle = wrappedOracle; + } + + @Override + public void processQueries(Collection>> queries) { + for (Query> query : queries) { + query.answer( + wrappedOracle.trace(query.getInput()) + ); + } + } +} From 83b56218d6a9cddbcb77112d553df23304dc0f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Sun, 25 May 2025 16:57:15 +0200 Subject: [PATCH 03/14] Initial draft of RA testrunner, cut down version of TestRunnerStandard --- .../testrunner/core/TestRunnerRA.java | 263 ++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java new file mode 100644 index 00000000..e454f6b5 --- /dev/null +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -0,0 +1,263 @@ +package com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.testrunner.core; + +import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilder; +import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilderTransformer; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.AbstractSul; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulBuilder; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulWrapper; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.config.SulConfig; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.mapper.Mapper; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.mapper.abstractsymbols.MapperOutput; +import com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.testrunner.core.config.TestRunnerEnabler; +import com.github.protocolfuzzing.protocolstatefuzzer.utils.CleanupTasks; +import com.github.protocolfuzzing.protocolstatefuzzer.utils.MealyIOProcessor; +import com.github.protocolfuzzing.protocolstatefuzzer.utils.ModelFactory; +import de.learnlib.oracle.MembershipOracle.MealyMembershipOracle; +import de.learnlib.ralib.automata.RegisterAutomaton; +import de.learnlib.ralib.sul.SULOracle; +import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.ralib.words.ParameterizedSymbol; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import net.automatalib.alphabet.Alphabet; +import net.automatalib.automaton.transducer.MealyMachine; +import net.automatalib.exception.FormatException; +import net.automatalib.word.Word; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import de.learnlib.sul.SUL; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; +import de.learnlib.ralib.words.OutputSymbol; +import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles.MembershipOracleWrapper; +import net.automatalib.word.WordBuilder; +import java.util.stream.Stream; +/** + * The standard implementation of the TestRunner Interface. + * + * @param

the type of protocol messages + * @param the type of execution context + */ +public class TestRunnerRA implements TestRunner { + + private static final Logger LOGGER = LogManager.getLogger(); + + /** Stores the constructor parameter. */ + protected TestRunnerEnabler testRunnerEnabler; + + /** The built alphabet using the AlphabetBuilder constructor parameter. */ + protected Alphabet alphabet; + + + /** Transformer to convert mealy input symbols into Ralib input symbols */ + protected AlphabetBuilderTransformer inputTransformer; + + /** The Mapper provided from the built {@link #sulOracle}. */ + protected Mapper mapper; + + /** The Oracle that contains the sul built via SulBuilder and wrapped via SulWrapper constructor parameters. */ + protected SULOracle sulOracle; + + /** Stores the Mealy Machine specification built if provided in the TestRunnerConfig. */ + protected RegisterAutomaton testSpec; + + /** Stores the cleanup tasks of the TestRunner. */ + protected CleanupTasks cleanupTasks; + + /** + * Constructs a new instance from the given parameters. + *

+ * The {@link #sulOracle} contains the wrapped (and built) sul. + * Invoke {@link #initialize()} afterwards. + * + * @param testRunnerEnabler the configuration that enables the testing + * @param alphabetBuilder the builder of the alphabet + * @param sulBuilder the builder of the sul + * @param sulWrapper the wrapper of the sul + */ + public TestRunnerRA( + TestRunnerEnabler testRunnerEnabler, + AlphabetBuilder alphabetBuilder, + AlphabetBuilderTransformer alphabetBuilderTransformer, + SulBuilder sulBuilder, + SulWrapper sulWrapper + ) { + this.testRunnerEnabler = testRunnerEnabler; + this.alphabet = alphabetBuilder.build( + testRunnerEnabler.getLearnerConfig() + ); + this.cleanupTasks = new CleanupTasks(); + + AbstractSul abstractSul = + sulBuilder.build(testRunnerEnabler.getSulConfig(), cleanupTasks); + this.mapper = abstractSul.getMapper(); + SUL sul = sulWrapper.wrap(abstractSul).getWrappedSul(); + + this.sulOracle = new SULOracle( + new DataWordSULWrapper(sul), new OutputSymbol("_io_err") + ); + + this.testSpec = null; + } + + /** + * Initializes the instance; to be run after the constructor. + *

+ * It checks if the TestRunnerConfig from the TestRunnerEnabler contains + * any test specification that needs to be built and used. + * + * @return the same instance + */ + public TestRunnerRA initialize() { + if ( + this.testSpec == null && + this.testRunnerEnabler.getTestRunnerConfig() + .getTestSpecification() != + null + ) { + throw new UnsupportedOperationException("Running with test spec is not implemented for RA learning."); + } + return this; + } + + /** + * Returns the alphabet to be used during testing. + * + * @return the alphabet to be used during testing + */ + public Alphabet getAlphabet() { + return alphabet; + } + + /** + * Returns the SulConfig of the {@link #testRunnerEnabler}. + * + * @return the SulConfig of the {@link #testRunnerEnabler} + */ + public SulConfig getSulConfig() { + return testRunnerEnabler.getSulConfig(); + } + + /** + * Runs the tests using {@link #runTests()} and cleans up using {@link #terminate()}. + */ + @Override + public void run() { + try { + List< + TestRunnerResult, Word> + > results = runTests(); + + for (TestRunnerResult< + Word, + Word + > result : results) { + LOGGER.info(result.toString()); + if ( + testRunnerEnabler + .getTestRunnerConfig() + .isShowTransitionSequence() + ) { + LOGGER.info( + "Displaying Transition Sequence\n{}", result + ); + } + } + } catch (IOException | FormatException e) { + LOGGER.error(e.getMessage()); + e.printStackTrace(); + } finally { + terminate(); + } + } + + /** + * Executes the {@link #cleanupTasks}; should be called only after all the + * desired tests have been executed. + */ + public void terminate() { + cleanupTasks.execute(); + } + + /** + * Reads the tests provided in the TestRunnerConfig of {@link #testRunnerEnabler}, + * executes each one of them using {@link #runTest(Word)} and collects the results. + * + * @return a list with the test results + * + * @throws IOException if an error during reading occurs + * @throws FormatException if an invalid format was encountered + */ + protected List, Word>> runTests() + throws IOException, FormatException { + TestParser testParser = new TestParser<>(); + List> tests; + String testFileOrTestString = testRunnerEnabler + .getTestRunnerConfig() + .getTest(); + + if (new File(testFileOrTestString).exists()) { + tests = testParser.readTests(alphabet, testFileOrTestString); + } else { + LOGGER.info( + "File {} does not exist, interpreting argument as test", + testFileOrTestString + ); + String[] testStrings = testFileOrTestString.split("\\s+"); + tests = List.of( + testParser.readTest(alphabet, Arrays.asList(testStrings)) + ); + } + + // net.automatalib.word.WordCollector exists but is not explicitly marked pulic. + // This is most likely unintended since it is a wrapper around WordBuilder which is public. + // Using that would allow us to skip using WordBuilder directly. + // TODO: Open an issue or otherwise notify about this. + WordBuilder wordBuilder = new WordBuilder<>(); + List> convertedTests = new ArrayList<>(tests.size()); + for (Word test : tests) { + List wordList = test.stream() + .map(inputTransformer::toTransformedInput) + .map(p -> new PSymbolInstance(p)) + .toList(); + Word pWord = wordBuilder.append(wordList).toWord(); + convertedTests.add(pWord); + wordBuilder.clear(); + + } + + + List< + TestRunnerResult, Word> + > results = new ArrayList<>(); + for (Word test : convertedTests) { + results.add(runTest(test)); + } + return results; + } + + /** + * Runs a single test and collects the result. + *

+ * If a {@link #testSpec} is present then its output to the provided test + * is computed and stored also in the TestRunnerResult as the expected output. + * + * @param test the test to be run against the stored {@link #sulOracle} + * @return the result of the test + */ + protected TestRunnerResult< + Word, + Word + > runTest(Word test) { + TestRunnerResult, Word> result = + TestRunner.runTest( + test, + testRunnerEnabler.getTestRunnerConfig().getTimes(), + new MembershipOracleWrapper(sulOracle) + ); + return result; + } +} From 68078547de90b82c9f883817e322620bee7fa7eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 26 May 2025 16:29:56 +0200 Subject: [PATCH 04/14] Add javadoc parameter alphabetBuilderTransformer --- .../statefuzzer/testrunner/core/TestRunnerRA.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index e454f6b5..ae3d9062 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -73,10 +73,11 @@ public class TestRunnerRA implements TestRunner { * The {@link #sulOracle} contains the wrapped (and built) sul. * Invoke {@link #initialize()} afterwards. * - * @param testRunnerEnabler the configuration that enables the testing - * @param alphabetBuilder the builder of the alphabet - * @param sulBuilder the builder of the sul - * @param sulWrapper the wrapper of the sul + * @param testRunnerEnabler the configuration that enables the testing + * @param alphabetBuilder the builder of the alphabet + * @param alphabetBuilderTransformer the transformer used to translate inputs + * @param sulBuilder the builder of the sul + * @param sulWrapper the wrapper of the sul */ public TestRunnerRA( TestRunnerEnabler testRunnerEnabler, From b975d4fab4eb0638b81b3cb4e864fbd54fb218f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 26 May 2025 16:41:38 +0200 Subject: [PATCH 05/14] Javadoc comments for MembershipOracleWrapper --- .../learner/oracles/MembershipOracleWrapper.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java index 0ff9c17d..c6f131da 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java @@ -8,10 +8,21 @@ import de.learnlib.ralib.words.PSymbolInstance; import net.automatalib.word.Word; + +/** + * A wrapper that allows the RALib SULOracle to be used where + * a MembershipOracle is required, since SULOracle does not + * implement this interface. + */ public class MembershipOracleWrapper implements MembershipOracle> { + /** The wrapped oracle */ private SULOracle wrappedOracle; + /** + * Constructs a wrapper around the provided instance + * @param wrappedOracle The SULOracle to wrap + */ public MembershipOracleWrapper(SULOracle wrappedOracle) { this.wrappedOracle = wrappedOracle; } From 5ef7ad26dbbf8c918257f4c8144a3a2f5f6d1ca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 26 May 2025 16:43:20 +0200 Subject: [PATCH 06/14] mvn spotless:apply --- .../oracles/MembershipOracleWrapper.java | 19 +++++++------- .../core/sulwrappers/DataWordSULWrapper.java | 2 +- .../testrunner/core/TestRunnerRA.java | 26 +++++++------------ 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java index c6f131da..6dd71e52 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java @@ -1,13 +1,12 @@ package com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles; -import java.util.Collection; - import de.learnlib.oracle.MembershipOracle; import de.learnlib.query.Query; import de.learnlib.ralib.sul.SULOracle; import de.learnlib.ralib.words.PSymbolInstance; import net.automatalib.word.Word; +import java.util.Collection; /** * A wrapper that allows the RALib SULOracle to be used where @@ -27,12 +26,12 @@ public MembershipOracleWrapper(SULOracle wrappedOracle) { this.wrappedOracle = wrappedOracle; } - @Override - public void processQueries(Collection>> queries) { - for (Query> query : queries) { - query.answer( - wrappedOracle.trace(query.getInput()) - ); - } - } + @Override + public void processQueries(Collection>> queries) { + for (Query> query : queries) { + query.answer( + wrappedOracle.trace(query.getInput()) + ); + } + } } diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java index 072d0dbe..e041c489 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/sul/core/sulwrappers/DataWordSULWrapper.java @@ -1,8 +1,8 @@ package com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers; import de.learnlib.ralib.sul.DataWordSUL; -import de.learnlib.sul.SUL; import de.learnlib.ralib.words.PSymbolInstance; +import de.learnlib.sul.SUL; /** * A wrapper that can be used as an {@code SUL} diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index ae3d9062..ea828f6d 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -2,39 +2,33 @@ import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilder; import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilderTransformer; +import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles.MembershipOracleWrapper; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.AbstractSul; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulBuilder; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulWrapper; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.config.SulConfig; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.mapper.Mapper; -import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.mapper.abstractsymbols.MapperOutput; import com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.testrunner.core.config.TestRunnerEnabler; import com.github.protocolfuzzing.protocolstatefuzzer.utils.CleanupTasks; -import com.github.protocolfuzzing.protocolstatefuzzer.utils.MealyIOProcessor; -import com.github.protocolfuzzing.protocolstatefuzzer.utils.ModelFactory; -import de.learnlib.oracle.MembershipOracle.MealyMembershipOracle; import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.sul.SULOracle; +import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import de.learnlib.sul.SUL; import net.automatalib.alphabet.Alphabet; -import net.automatalib.automaton.transducer.MealyMachine; import net.automatalib.exception.FormatException; import net.automatalib.word.Word; +import net.automatalib.word.WordBuilder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import de.learnlib.sul.SUL; -import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; -import de.learnlib.ralib.words.OutputSymbol; -import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles.MembershipOracleWrapper; -import net.automatalib.word.WordBuilder; -import java.util.stream.Stream; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * The standard implementation of the TestRunner Interface. * From bb4e5c0f24e744682c952004ad156a25cd8b5283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 26 May 2025 16:44:10 +0200 Subject: [PATCH 07/14] Use imported class DataWordSulWrapper and remove the static nested one --- .../core/StateFuzzerComposerRA.java | 36 +------------------ 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/core/StateFuzzerComposerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/core/StateFuzzerComposerRA.java index cd06b9ba..61e391cd 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/core/StateFuzzerComposerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/core/StateFuzzerComposerRA.java @@ -9,6 +9,7 @@ import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.AbstractSul; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulBuilder; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulWrapper; +import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; import com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.core.config.StateFuzzerEnabler; import com.github.protocolfuzzing.protocolstatefuzzer.utils.CleanupTasks; import de.learnlib.query.DefaultQuery; @@ -18,7 +19,6 @@ import de.learnlib.ralib.learning.RaLearningAlgorithm; import de.learnlib.ralib.solver.ConstraintSolver; import de.learnlib.ralib.solver.simple.SimpleConstraintSolver; -import de.learnlib.ralib.sul.DataWordSUL; import de.learnlib.ralib.sul.SULOracle; import de.learnlib.ralib.theory.Theory; import de.learnlib.ralib.words.OutputSymbol; @@ -247,38 +247,4 @@ protected void composeEquivalenceOracle() { this.equivalenceOracle = LearningSetupFactory.createEquivalenceOracle(this.learnerConfig, this.sulOracle.getDataWordSUL(), this.alphabet, this.teachers, this.consts); } - - /** - * A wrapper that can be used as an {@code SUL} - * to DataWordSUL converter. - */ - protected static class DataWordSULWrapper extends DataWordSUL { - - /** Stores the wrapped sul */ - protected SUL sul; - - /** - * Constructs a new instance from the given parameters. - * - * @param sul the wrapped sul - */ - public DataWordSULWrapper(SUL sul) { - this.sul = sul; - } - - @Override - public void pre() { - sul.pre(); - } - - @Override - public void post() { - sul.post(); - } - - @Override - public PSymbolInstance step(PSymbolInstance in) { - return sul.step(in); - } - } } From 1d1e8697c41ccaaa4d9aad52f14f75d280f8bb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 26 May 2025 17:00:49 +0200 Subject: [PATCH 08/14] Remove testSpec and Mapper since they are unused, set inputTransformer class variable in constructor --- .../testrunner/core/TestRunnerRA.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index ea828f6d..652c9825 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -8,10 +8,8 @@ import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulWrapper; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.config.SulConfig; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.sulwrappers.DataWordSULWrapper; -import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.mapper.Mapper; import com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.testrunner.core.config.TestRunnerEnabler; import com.github.protocolfuzzing.protocolstatefuzzer.utils.CleanupTasks; -import de.learnlib.ralib.automata.RegisterAutomaton; import de.learnlib.ralib.sul.SULOracle; import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; @@ -49,15 +47,9 @@ public class TestRunnerRA implements TestRunner { /** Transformer to convert mealy input symbols into Ralib input symbols */ protected AlphabetBuilderTransformer inputTransformer; - /** The Mapper provided from the built {@link #sulOracle}. */ - protected Mapper mapper; - /** The Oracle that contains the sul built via SulBuilder and wrapped via SulWrapper constructor parameters. */ protected SULOracle sulOracle; - /** Stores the Mealy Machine specification built if provided in the TestRunnerConfig. */ - protected RegisterAutomaton testSpec; - /** Stores the cleanup tasks of the TestRunner. */ protected CleanupTasks cleanupTasks; @@ -84,18 +76,16 @@ public TestRunnerRA( this.alphabet = alphabetBuilder.build( testRunnerEnabler.getLearnerConfig() ); + this.inputTransformer = alphabetBuilderTransformer; this.cleanupTasks = new CleanupTasks(); AbstractSul abstractSul = sulBuilder.build(testRunnerEnabler.getSulConfig(), cleanupTasks); - this.mapper = abstractSul.getMapper(); SUL sul = sulWrapper.wrap(abstractSul).getWrappedSul(); this.sulOracle = new SULOracle( new DataWordSULWrapper(sul), new OutputSymbol("_io_err") ); - - this.testSpec = null; } /** @@ -108,7 +98,6 @@ public TestRunnerRA( */ public TestRunnerRA initialize() { if ( - this.testSpec == null && this.testRunnerEnabler.getTestRunnerConfig() .getTestSpecification() != null @@ -236,9 +225,6 @@ protected List, Word>> r /** * Runs a single test and collects the result. - *

- * If a {@link #testSpec} is present then its output to the provided test - * is computed and stored also in the TestRunnerResult as the expected output. * * @param test the test to be run against the stored {@link #sulOracle} * @return the result of the test From 58b426674897a0f69364980c4b8f258ef67a02d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Wed, 28 May 2025 17:09:42 +0200 Subject: [PATCH 09/14] Override answerQuery instead of processQueries, since trace takes an input word. --- .../components/learner/oracles/MembershipOracleWrapper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java index 6dd71e52..852a4496 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java @@ -26,6 +26,11 @@ public MembershipOracleWrapper(SULOracle wrappedOracle) { this.wrappedOracle = wrappedOracle; } + @Override + public Word answerQuery(Word inputWord) { + return wrappedOracle.trace(inputWord); + } + @Override public void processQueries(Collection>> queries) { for (Query> query : queries) { From 2f332fb1a6c3d0dc801230691dad51208f7bcdbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Wed, 28 May 2025 17:10:08 +0200 Subject: [PATCH 10/14] Interlace dummy output symbols in the input sequence so trace does not skip inputs --- .../statefuzzer/testrunner/core/TestRunnerRA.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index 652c9825..ebfdbedc 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -26,7 +26,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import java.util.List; +import java.util.stream.Stream; /** * The standard implementation of the TestRunner Interface. * @@ -200,18 +202,22 @@ protected List, Word>> r // This is most likely unintended since it is a wrapper around WordBuilder which is public. // Using that would allow us to skip using WordBuilder directly. // TODO: Open an issue or otherwise notify about this. + LOGGER.debug("Read mealy tests: {}", tests); WordBuilder wordBuilder = new WordBuilder<>(); List> convertedTests = new ArrayList<>(tests.size()); + PSymbolInstance placeholderElement = new PSymbolInstance(new OutputSymbol("PLACEHOLDER ELEMENT")); + Iterator placeholders = Stream.iterate(placeholderElement, i -> placeholderElement).iterator(); for (Word test : tests) { List wordList = test.stream() .map(inputTransformer::toTransformedInput) .map(p -> new PSymbolInstance(p)) + .flatMap(x -> Stream.of(x, placeholders.next())) .toList(); Word pWord = wordBuilder.append(wordList).toWord(); convertedTests.add(pWord); wordBuilder.clear(); - } + LOGGER.debug("Converted tests: {}", convertedTests); List< From 4c6c33029b8a90711deb417d815e0d667850d8bd Mon Sep 17 00:00:00 2001 From: pfg666 Date: Tue, 24 Jun 2025 13:44:06 +0200 Subject: [PATCH 11/14] Fix test parser bug when parsing test files meants for the RA test runner --- .../statefuzzer/testrunner/core/TestRunnerRA.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index ebfdbedc..eed9ab48 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -11,11 +11,13 @@ import com.github.protocolfuzzing.protocolstatefuzzer.statefuzzer.testrunner.core.config.TestRunnerEnabler; import com.github.protocolfuzzing.protocolstatefuzzer.utils.CleanupTasks; import de.learnlib.ralib.sul.SULOracle; +import de.learnlib.ralib.words.InputSymbol; import de.learnlib.ralib.words.OutputSymbol; import de.learnlib.ralib.words.PSymbolInstance; import de.learnlib.ralib.words.ParameterizedSymbol; import de.learnlib.sul.SUL; import net.automatalib.alphabet.Alphabet; +import net.automatalib.alphabet.impl.ListAlphabet; import net.automatalib.exception.FormatException; import net.automatalib.word.Word; import net.automatalib.word.WordBuilder; @@ -185,8 +187,11 @@ protected List, Word>> r .getTestRunnerConfig() .getTest(); + ListAlphabet inputAlphabet = new ListAlphabet<> (alphabet.stream() + .filter(i -> inputTransformer.toTransformedInput(i) instanceof InputSymbol).toList()); + if (new File(testFileOrTestString).exists()) { - tests = testParser.readTests(alphabet, testFileOrTestString); + tests = testParser.readTests(inputAlphabet, testFileOrTestString); } else { LOGGER.info( "File {} does not exist, interpreting argument as test", @@ -194,7 +199,7 @@ protected List, Word>> r ); String[] testStrings = testFileOrTestString.split("\\s+"); tests = List.of( - testParser.readTest(alphabet, Arrays.asList(testStrings)) + testParser.readTest(inputAlphabet, Arrays.asList(testStrings)) ); } From 71a8f853d556341638a8551b646f81bbeb666003 Mon Sep 17 00:00:00 2001 From: pfg666 Date: Tue, 24 Jun 2025 19:04:18 +0200 Subject: [PATCH 12/14] Simplfy TestRunnerRA, change name to MembershipOracleWrapperRA, move into this class some functionality (add output placeholder) from TestRunnerRA --- .../oracles/MembershipOracleWrapper.java | 42 -------------- .../oracles/MembershipOracleWrapperRA.java | 57 +++++++++++++++++++ .../testrunner/core/TestRunnerRA.java | 32 +++-------- 3 files changed, 66 insertions(+), 65 deletions(-) delete mode 100644 src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java create mode 100644 src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapperRA.java diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java deleted file mode 100644 index 852a4496..00000000 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapper.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles; - -import de.learnlib.oracle.MembershipOracle; -import de.learnlib.query.Query; -import de.learnlib.ralib.sul.SULOracle; -import de.learnlib.ralib.words.PSymbolInstance; -import net.automatalib.word.Word; - -import java.util.Collection; - -/** - * A wrapper that allows the RALib SULOracle to be used where - * a MembershipOracle is required, since SULOracle does not - * implement this interface. - */ -public class MembershipOracleWrapper implements MembershipOracle> { - - /** The wrapped oracle */ - private SULOracle wrappedOracle; - - /** - * Constructs a wrapper around the provided instance - * @param wrappedOracle The SULOracle to wrap - */ - public MembershipOracleWrapper(SULOracle wrappedOracle) { - this.wrappedOracle = wrappedOracle; - } - - @Override - public Word answerQuery(Word inputWord) { - return wrappedOracle.trace(inputWord); - } - - @Override - public void processQueries(Collection>> queries) { - for (Query> query : queries) { - query.answer( - wrappedOracle.trace(query.getInput()) - ); - } - } -} diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapperRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapperRA.java new file mode 100644 index 00000000..a160c728 --- /dev/null +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/components/learner/oracles/MembershipOracleWrapperRA.java @@ -0,0 +1,57 @@ +package com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles; + +import de.learnlib.oracle.MembershipOracle; +import de.learnlib.query.Query; +import de.learnlib.ralib.sul.SULOracle; +import de.learnlib.ralib.words.OutputSymbol; +import de.learnlib.ralib.words.PSymbolInstance; +import net.automatalib.word.Word; +import net.automatalib.word.WordBuilder; + +import java.util.Collection; + +/** + * A wrapper that allows the RALib SULOracle to be used where + * a MembershipOracle is required, since SULOracle does not + * implement this interface. + */ +public class MembershipOracleWrapperRA implements MembershipOracle> { + + /** The wrapped oracle */ + private SULOracle wrappedOracle; + + /** + * Constructs a wrapper around the provided instance + * @param wrappedOracle The SULOracle to wrap + */ + public MembershipOracleWrapperRA(SULOracle wrappedOracle) { + this.wrappedOracle = wrappedOracle; + } + + @Override + public Word answerQuery(Word inputWord) { + PSymbolInstance placeholderElement = new PSymbolInstance(new OutputSymbol("PLACEHOLDER ELEMENT")); + WordBuilder ioTraceBuilder = new WordBuilder(); + for (PSymbolInstance i: inputWord) { + ioTraceBuilder.add(i); + ioTraceBuilder.add(placeholderElement); + } + + Word ioTrace = wrappedOracle.trace(ioTraceBuilder.toWord()); + WordBuilder outputBuilder = new WordBuilder(); + for (PSymbolInstance symInstance : ioTrace) { + if (symInstance.getBaseSymbol() instanceof OutputSymbol) { + outputBuilder.add(symInstance); + } + } + + return outputBuilder.toWord(); + } + + @Override + public void processQueries(Collection>> queries) { + for (Query> query : queries) { + query.answer(answerQuery(query.getInput())); + } + } +} diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index eed9ab48..4577d46d 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -2,7 +2,7 @@ import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilder; import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.alphabet.AlphabetBuilderTransformer; -import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles.MembershipOracleWrapper; +import com.github.protocolfuzzing.protocolstatefuzzer.components.learner.oracles.MembershipOracleWrapperRA; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.AbstractSul; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulBuilder; import com.github.protocolfuzzing.protocolstatefuzzer.components.sul.core.SulWrapper; @@ -28,9 +28,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; import java.util.List; -import java.util.stream.Stream; /** * The standard implementation of the TestRunner Interface. * @@ -203,31 +201,19 @@ protected List, Word>> r ); } - // net.automatalib.word.WordCollector exists but is not explicitly marked pulic. + // net.automatalib.word.WordCollector exists but is not explicitly marked public. // This is most likely unintended since it is a wrapper around WordBuilder which is public. // Using that would allow us to skip using WordBuilder directly. // TODO: Open an issue or otherwise notify about this. - LOGGER.debug("Read mealy tests: {}", tests); - WordBuilder wordBuilder = new WordBuilder<>(); List> convertedTests = new ArrayList<>(tests.size()); - PSymbolInstance placeholderElement = new PSymbolInstance(new OutputSymbol("PLACEHOLDER ELEMENT")); - Iterator placeholders = Stream.iterate(placeholderElement, i -> placeholderElement).iterator(); for (Word test : tests) { - List wordList = test.stream() - .map(inputTransformer::toTransformedInput) - .map(p -> new PSymbolInstance(p)) - .flatMap(x -> Stream.of(x, placeholders.next())) - .toList(); - Word pWord = wordBuilder.append(wordList).toWord(); - convertedTests.add(pWord); - wordBuilder.clear(); + WordBuilder wordBuilder = new WordBuilder<>(); + for (I input : test) { + wordBuilder.append(new PSymbolInstance(inputTransformer.toTransformedInput(input))); + } + convertedTests.add(wordBuilder.toWord()); } - LOGGER.debug("Converted tests: {}", convertedTests); - - - List< - TestRunnerResult, Word> - > results = new ArrayList<>(); + List, Word>> results = new ArrayList<>(); for (Word test : convertedTests) { results.add(runTest(test)); } @@ -248,7 +234,7 @@ > runTest(Word test) { TestRunner.runTest( test, testRunnerEnabler.getTestRunnerConfig().getTimes(), - new MembershipOracleWrapper(sulOracle) + new MembershipOracleWrapperRA(sulOracle) ); return result; } From 7de5186e6e4e7fcb550faacbf369b60075f6aed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Mon, 27 Oct 2025 14:41:15 +0100 Subject: [PATCH 13/14] update name of sulBuilder.build() to sulBuilder.buildSul() --- .../statefuzzer/testrunner/core/TestRunnerRA.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index 4577d46d..19ef87a2 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -82,7 +82,7 @@ public TestRunnerRA( this.cleanupTasks = new CleanupTasks(); AbstractSul abstractSul = - sulBuilder.build(testRunnerEnabler.getSulConfig(), cleanupTasks); + sulBuilder.buildSul(testRunnerEnabler.getSulConfig(), cleanupTasks); SUL sul = sulWrapper.wrap(abstractSul).getWrappedSul(); this.sulOracle = new SULOracle( From 1266aa5b9e24cacfe20a7a3727b5e81bb8cbb556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Pettersson=20L=C3=B6fstedt?= <00oskpet@gmail.com> Date: Tue, 28 Oct 2025 13:17:40 +0100 Subject: [PATCH 14/14] Make TestRunnerRA build the sulWrapper using the sulBuilder --- .../statefuzzer/testrunner/core/TestRunnerRA.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java index 19ef87a2..f2430f4f 100644 --- a/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java +++ b/src/main/java/com/github/protocolfuzzing/protocolstatefuzzer/statefuzzer/testrunner/core/TestRunnerRA.java @@ -65,14 +65,12 @@ public class TestRunnerRA implements TestRunner { * @param alphabetBuilder the builder of the alphabet * @param alphabetBuilderTransformer the transformer used to translate inputs * @param sulBuilder the builder of the sul - * @param sulWrapper the wrapper of the sul */ public TestRunnerRA( TestRunnerEnabler testRunnerEnabler, AlphabetBuilder alphabetBuilder, AlphabetBuilderTransformer alphabetBuilderTransformer, - SulBuilder sulBuilder, - SulWrapper sulWrapper + SulBuilder sulBuilder ) { this.testRunnerEnabler = testRunnerEnabler; this.alphabet = alphabetBuilder.build( @@ -83,6 +81,7 @@ public TestRunnerRA( AbstractSul abstractSul = sulBuilder.buildSul(testRunnerEnabler.getSulConfig(), cleanupTasks); + SulWrapper sulWrapper = sulBuilder.buildWrapper(); SUL sul = sulWrapper.wrap(abstractSul).getWrappedSul(); this.sulOracle = new SULOracle(