Repository: calcite Updated Branches: refs/heads/master 59b76701d -> 32630d1a2
Display random failure of Rex fuzzer in build logs to inspire further fixes fixes #844 Project: http://git-wip-us.apache.org/repos/asf/calcite/repo Commit: http://git-wip-us.apache.org/repos/asf/calcite/commit/32630d1a Tree: http://git-wip-us.apache.org/repos/asf/calcite/tree/32630d1a Diff: http://git-wip-us.apache.org/repos/asf/calcite/diff/32630d1a Branch: refs/heads/master Commit: 32630d1a2cc4f231968bec458cee5380abbbeb51 Parents: 59b7670 Author: Vladimir Sitnikov <[email protected]> Authored: Wed Sep 19 22:57:01 2018 +0300 Committer: Vladimir Sitnikov <[email protected]> Committed: Thu Sep 20 12:07:33 2018 +0300 ---------------------------------------------------------------------- .../org/apache/calcite/rex/RexInterpreter.java | 5 ++ .../test/fuzzer/RexProgramFuzzyTest.java | 57 +++++++++++++++----- 2 files changed, 49 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/calcite/blob/32630d1a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java index 0d4f0b2..67c53c9 100644 --- a/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java +++ b/core/src/main/java/org/apache/calcite/rex/RexInterpreter.java @@ -173,6 +173,11 @@ public class RexInterpreter implements RexVisitor<Comparable> { return values.get(0).equals(false); case IS_NOT_FALSE: return !values.get(0).equals(false); + case PLUS_PREFIX: + return values.get(0); + case MINUS_PREFIX: + return containsNull(values) ? N + : number(values.get(0)).negate(); case PLUS: return containsNull(values) ? N : number(values.get(0)).add(number(values.get(1))); http://git-wip-us.apache.org/repos/asf/calcite/blob/32630d1a/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java b/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java index 006cb9b..d29a6bd 100644 --- a/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java +++ b/core/src/test/java/org/apache/calcite/test/fuzzer/RexProgramFuzzyTest.java @@ -33,6 +33,8 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -42,7 +44,6 @@ import java.util.List; import java.util.PriorityQueue; import java.util.Random; import java.util.Set; -import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -60,8 +61,9 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { protected static final Logger LOGGER = LoggerFactory.getLogger(RexProgramFuzzyTest.class); - private static final int TEST_DURATION = Integer.getInteger("rex.fuzzing.duration", 5); - private static final long TEST_ITERATIONS = Long.getLong("rex.fuzzing.iterations", 5); + private static final Duration TEST_DURATION = + Duration.of(Integer.getInteger("rex.fuzzing.duration", 5), ChronoUnit.SECONDS); + private static final long TEST_ITERATIONS = Long.getLong("rex.fuzzing.iterations", 20); // Stop fuzzing after detecting MAX_FAILURES errors private static final int MAX_FAILURES = Integer.getInteger("rex.fuzzing.max.failures", 1); @@ -259,26 +261,51 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { + node.accept(new RexToTestCodeShuttle()); } + private static void trimStackTrace(Throwable t, int maxStackLines) { + StackTraceElement[] stackTrace = t.getStackTrace(); + if (stackTrace == null || stackTrace.length <= maxStackLines) { + return; + } + stackTrace = Arrays.copyOf(stackTrace, maxStackLines); + t.setStackTrace(stackTrace); + } + + @Test public void defaultFuzzTest() { + try { + runRexFuzzer(0, Duration.of(5, ChronoUnit.SECONDS), 1, 0, 0); + } catch (Throwable e) { + for (Throwable t = e; t != null; t = t.getCause()) { + trimStackTrace(t, 4); + } + LOGGER.info("Randomized test identified a potential defect. Feel free to fix that issue", e); + } + } + @Test public void testFuzzy() { - if (TEST_DURATION == 0) { + runRexFuzzer(SEED, TEST_DURATION, MAX_FAILURES, TEST_ITERATIONS, TOPN_SLOWEST); + } + + private void runRexFuzzer(long startSeed, Duration testDuration, int maxFailures, + long testIterations, int topnSlowest) { + if (testDuration.toMillis() == 0) { return; } slowestTasks = new TopN<>(TOPN_SLOWEST); Random r = new Random(); - if (SEED != 0) { - LOGGER.info("Using seed {} for rex fuzzing", SEED); - r.setSeed(SEED); + if (startSeed != 0) { + LOGGER.info("Using seed {} for rex fuzzing", startSeed); + r.setSeed(startSeed); } long start = System.currentTimeMillis(); - long deadline = start + TimeUnit.SECONDS.toMillis(TEST_DURATION); + long deadline = start + testDuration.toMillis(); List<Throwable> exceptions = new ArrayList<>(); Set<String> duplicates = new HashSet<>(); long total = 0; int dup = 0; int fail = 0; RexFuzzer fuzzer = new RexFuzzer(rexBuilder, typeFactory); - while (System.currentTimeMillis() < deadline && exceptions.size() < MAX_FAILURES - && (TEST_ITERATIONS == 0 || total < TEST_ITERATIONS)) { + while (System.currentTimeMillis() < deadline && exceptions.size() < maxFailures + && (testIterations == 0 || total < testIterations)) { long seed = r.nextLong(); this.currentSeed = seed; r.setSeed(seed); @@ -312,7 +339,7 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { "Rex fuzzing results: number of cases tested={}, failed cases={}, duplicate failures={}, fuzz rate={} per second", total, fail, dup, rate); - if (TOPN_SLOWEST > 0) { + if (topnSlowest > 0) { LOGGER.info("The 5 slowest to simplify nodes were"); SimplifyTask task; RexToTestCodeShuttle v = new RexToTestCodeShuttle(); @@ -334,7 +361,8 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { <Throwable>comparingInt(t -> t.getMessage() == null ? -1 : t.getMessage().length()) .thenComparing(Throwable::getMessage)); - for (int i = 0; i < exceptions.size() && i < 100; i++) { + // The first exception will be thrown, so the others go to printStackTrace + for (int i = 1; i < exceptions.size() && i < 100; i++) { Throwable exception = exceptions.get(i); exception.printStackTrace(); } @@ -343,7 +371,10 @@ public class RexProgramFuzzyTest extends RexProgramBuilderBase { if (ex instanceof Error) { throw (Error) ex; } - throw new RuntimeException("Exception in testFuzzy", ex); + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new RuntimeException("Exception in runRexFuzzer", ex); } private void generateRexAndCheckTrueFalse(RexFuzzer fuzzer, Random r) {
