@Override public FSMTransition choose(TestSuite suite, List<FSMTransition> choices) { int testIndex = suite.getAllTestCases().size(); List<String> path = suite.getCurrentTest().getAllStepNames(); log.d("path for the current (explored) test:" + path); log.i("Exploring step " + testIndex + "." + path.size()); TestCoverage suiteCoverage = suite.getCoverage(); // create trace if DOT graph is wanted TraceNode[] trace = initTrace(path, testIndex); ExplorationState state = new ExplorationState(config, suiteCoverage); String choice = null; if (choices.size() == 1) { // this handles the scenario startup, where there is always just one choice (and other similar // scenarios) choice = choices.get(0).getStringName(); path.add(choice); } else { // initiate exploration of the possible paths choice = exploreLocal(suite, state, path, trace[1]); } writeDot(path, trace[0]); // we have to find the transition here based on string matching because returning the actual // FSMTransition // object would give a reference to the wrong instance of the model object for (FSMTransition transition : choices) { if (transition.getStringName().equals(choice)) { return transition; } } throw new IllegalStateException( "Exploration choice (" + choice + ") not available. OSMO is bugging?"); }
private boolean checkProbability(long mySeed) { // need a separate randomizer, with predictable but changing seed to allow for parallel runs // using same endcondition Randomizer rand = new Randomizer(mySeed); // finally we go with random values to allow progress beyond end if so desired double v = rand.nextDouble(); log.d("randomizing..:" + v); return v < fallbackProbability; }
@Override public void createModelObjects(TestModels models) { for (Class aClass : classes) { try { models.add(aClass.newInstance()); } catch (Exception e) { log.e("Failed to create a model class instance. Exiting.", e); e.printStackTrace(); throw new RuntimeException(e); } } }
/** * Creates the representation of the generation/exploration trace for using with DOT trace * writing. * * @param script The script for the test case. * @return index[0] = root, index[1] = current step from which exploration continues. */ private TraceNode[] initTrace(Collection<String> script, int testIndex) { if (dot.getTestIndex() != testIndex) { log.d("New test started, creating new DOT tracer."); dot = new DOTWriter(testIndex); } TraceNode.reset(); TraceNode[] nodes = new TraceNode[2]; TraceNode root = new TraceNode("init", null, false); nodes[0] = root; TraceNode node = root; for (String step : script) { node = node.add(step, false); } nodes[1] = node; return nodes; }
/** * Calculate length of text to generate next. * * @return Length defined. */ private int length() { int length = -1; if (!invalid) { length = rand.nextInt(min, max); } else { if (zeroSize && !zeroDone) { log.d("Giving zero length"); zeroDone = true; previousLength = 0; return 0; } int offset = rand.nextInt(minOffset, maxOffset); if (previousLength < min) { length = max + offset; } else { length = min - offset; } if (length < 0) { length = 0; } } previousLength = length; return length; }
@Override public boolean endTest(TestSuite suite, FSM fsm) { if (scenarioEndCondition != null) { // if scenario is not yet done, we do not end no matter what if (!scenarioEndCondition.endTest(suite, fsm)) return false; } if (isTimedOut()) { log.d("Exploration timeout"); return true; } int max = config.getMaxTestLength(); int testSteps = suite.currentSteps(); if (max > 0) { if (testSteps >= max) { log.d("test over maximum length"); return true; } } // have we achieved defined minimum length yet? int min = config.getMinTestLength(); if (min > 0) { if (testSteps < min) { return false; } } long mySeed = seed + suite.totalSteps(); // plateau should take precedence over score limit otherwise it never happens. thus the ordering // with this here int plateauThreshold = config.getTestPlateauThreshold(); if (plateauThreshold > 0) { if (isTestPlateau(suite, config.getTestPlateauLength())) { log.d("test has plateaued"); return checkProbability(mySeed); } } // have we achieved minimum defined added test coverage yet? int minScore = config.getMinTestScore(); if (minScore > 0) { if (suiteCoverage == null) suiteCoverage = suite.getCoverage(); TestCase test = suite.getCurrentTest(); TestCaseStep step = test.getCurrentStep(); // this is the case when starting generation if (step == null) return false; int added = step.getAddedCoverage(); if (added < minScore) { return false; } } // exploration only works nice and shiny until the end condition hits, then we have to go with // the pössis // this is because if we evaluate paths for overall score and one of them is longer but only due // to having // a different random "v" (below) value generated, it "seems" better although in fact should not // (or should it ?:) // for example: ++-+-+++++++++ //<-evaluates one step later for the random "v" and gets a // different value // ++-+++++++ //<-evaluates one step before for the random "v" and gets a // different value if (exploring) return true; return checkProbability(mySeed); }