private TestCaseResult executeInserts( Data data, TestCaseResult normalTestResult, Map<Integer, TestCaseResult> failedMutants, TestCase testCase) { for (Table table : schema.getTablesInOrder()) { if (data.getTables().contains(table)) { List<Integer> applicableMutants = changedTableMap.get(table.getIdentifier().get()); applicableMutants = applicableMutants == null ? new ArrayList<Integer>() : applicableMutants; for (Row row : data.getRows(table)) { String insert = sqlWriter.writeInsertStatement(row); // Only insert if we haven't failed yet if (normalTestResult == null) { Integer normalResult = databaseInteractor.executeUpdate(insert); if (normalResult != 1) { normalTestResult = new TestCaseResult( new InsertStatementException("Failed, result was: " + normalResult, insert)); } } // Setup for parallel execution executor = Executors.newFixedThreadPool(4); for (Integer mutantId : applicableMutants) { // Only insert if we haven't failed yet if (!failedMutants.containsKey(mutantId)) { MutantInsertsTask task = new MutantInsertsTask(insert, mutantId, failedMutants, testCase); executor.submit(task); } } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException ex) { throw new RuntimeException(ex); } // If a mutant isn't applicable, then it should 'inherit' the normal result for (int i = 0; i < mutants.size(); i++) { if (!applicableMutants.contains(i) && normalTestResult != null) { resultMap.get(i).add(testCase, normalTestResult); failedMutants.put(i, normalTestResult); } } } } } return normalTestResult; }
@Override public AnalysisResult analyse(TestSuiteResult originalResults) { // Get normal results AnalysisResult result = new AnalysisResult(); // Build map of changed tables this.changedTableMap = new HashMap<>(); executor = Executors.newFixedThreadPool(4); for (int id = 0; id < mutants.size(); id++) { Mutant<Schema> mutant = mutants.get(id); executor.submit(new ChangedTableTask(changedTableMap, id, mutant)); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.DAYS); } catch (InterruptedException ex) { throw new RuntimeException(ex); } // Build the meta-mutant schema and SQL statements Schema metamutant = MutationAnalysisUtils.mergeMutantsParallel(schema, mutants); createStmts = sqlWriter.writeCreateTableStatements(metamutant); dropStmts = sqlWriter.writeDropTableStatements(metamutant, true); deleteStmts = sqlWriter.writeDeleteFromTableStatements(metamutant); // Build map of results this.resultMap = new HashMap<>(); for (int i = 0; i < mutants.size(); i++) { resultMap.put(i, new TestSuiteResult()); } // Execute test suite executeDropStmts(databaseInteractor); executeCreateStmts(databaseInteractor); for (TestCase testCase : testSuite.getTestCases()) { executeDeleteStmts(databaseInteractor); TestCaseResult normalTestResult = null; Map<Integer, TestCaseResult> failedMutants = new HashMap<>(); Data data = testCase.getState(); normalTestResult = executeInserts(data, normalTestResult, failedMutants, testCase); data = testCase.getData(); normalTestResult = executeInserts(data, normalTestResult, failedMutants, testCase); if (normalTestResult == null) { for (int i = 0; i < mutants.size(); i++) { if (!failedMutants.containsKey(i)) { resultMap.get(i).add(testCase, TestCaseResult.SuccessfulTestCaseResult); } } } } // Build the TestSuiteResult objects for (int i = 0; i < mutants.size(); i++) { TestSuiteResult mutantResult = resultMap.get(i); if (!originalResults.equals(mutantResult)) { result.addKilled(mutants.get(i)); } else { result.addLive(mutants.get(i)); } } executeDropStmts(databaseInteractor); return result; }
@Override public void task() { // Setup if (inputfolder == null) { inputfolder = locationsConfiguration.getResultsDir() + File.separator + "generatedresults" + File.separator; } if (outputfolder == null) { outputfolder = locationsConfiguration.getResultsDir() + File.separator; } // Start results file CSVResult result = new CSVResult(); result.addValue("technique", this.getClass().getSimpleName()); result.addValue("dbms", databaseConfiguration.getDbms()); result.addValue("casestudy", casestudy); result.addValue("trial", trial); // Instantiate the DBMS and related objects DBMS dbms = DBMSFactory.instantiate(databaseConfiguration.getDbms()); SQLWriter sqlWriter = dbms.getSQLWriter(); DatabaseInteractor databaseInteractor = dbms.getDatabaseInteractor(casestudy, databaseConfiguration, locationsConfiguration); if (databaseInteractor.getTableCount() != 0) { LOGGER.log( Level.SEVERE, "Potential dirty database detected: technique={0}, casestudy={1}, trial={2}", new Object[] {this.getClass().getSimpleName(), casestudy, trial}); } // Get the required schema class Schema schema; try { schema = (Schema) Class.forName(casestudy).newInstance(); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ex) { throw new RuntimeException(ex); } // Load the SQLExecutionReport for the non-mutated schema String reportPath = inputfolder + casestudy + ".xml"; SQLExecutionReport originalReport = XMLSerialiser.load(reportPath); // Start mutation timing ExperimentTimer timer = new ExperimentTimer(); timer.start(ExperimentTimer.TimingPoint.TOTAL_TIME); // Get the mutation pipeline and generate mutants timer.start(ExperimentTimer.TimingPoint.MUTATION_TIME); MutationPipeline<Schema> pipeline; try { pipeline = MutationPipelineFactory.<Schema>instantiate( mutationPipeline, schema, databaseConfiguration.getDbms()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException ex) { throw new RuntimeException(ex); } List<Mutant<Schema>> mutants = pipeline.mutate(); timer.stop(ExperimentTimer.TimingPoint.MUTATION_TIME); // Schemata step: Rename the mutants renameMutants(mutants); // Schemata step: Build single drop statement timer.start(ExperimentTimer.TimingPoint.DROPS_TIME); StringBuilder dropBuilder = new StringBuilder(); for (Mutant<Schema> mutant : mutants) { Schema mutantSchema = mutant.getMutatedArtefact(); for (String statement : sqlWriter.writeDropTableStatements(mutantSchema, true)) { dropBuilder.append(statement); dropBuilder.append("; "); dropBuilder.append(System.lineSeparator()); } } String dropStmt = dropBuilder.toString(); timer.stop(ExperimentTimer.TimingPoint.DROPS_TIME); // Schemata step: Build single create statement timer.start(ExperimentTimer.TimingPoint.CREATES_TIME); StringBuilder createBuilder = new StringBuilder(); for (Mutant<Schema> mutant : mutants) { Schema mutantSchema = mutant.getMutatedArtefact(); for (String statement : sqlWriter.writeCreateTableStatements(mutantSchema)) { createBuilder.append(statement); createBuilder.append("; "); createBuilder.append(System.lineSeparator()); } } String createStmt = createBuilder.toString(); timer.stop(ExperimentTimer.TimingPoint.CREATES_TIME); // Schemata step: Drop existing tables before iterating mutants timer.start(ExperimentTimer.TimingPoint.DROPS_TIME); if (dropfirst) { databaseInteractor.executeUpdate(dropStmt); } timer.stop(ExperimentTimer.TimingPoint.DROPS_TIME); // Schemata step: Create table before iterating mutants timer.start(ExperimentTimer.TimingPoint.CREATES_TIME); Integer res = databaseInteractor.executeUpdate(createStmt); boolean quasiSchema = false; if (res.intValue() == -1) { quasiSchema = true; } timer.stop(ExperimentTimer.TimingPoint.CREATES_TIME); // Only do mutation analysis if the schema is valid int killed = 0; if (!quasiSchema) { // Begin mutation analysis for (int id = 0; id < mutants.size(); id++) { Schema mutant = mutants.get(id).getMutatedArtefact(); LOGGER.log(Level.INFO, "Mutant {0}", id); // Schemata step: Generate insert prefix string String schemataPrefix = "INSERT INTO mutant_" + (id + 1) + "_"; // Insert the test data timer.start(ExperimentTimer.TimingPoint.INSERTS_TIME); List<SQLInsertRecord> insertStmts = originalReport.getInsertStatements(); ArrayList<String> groupedStatements = new ArrayList<>(); for (SQLInsertRecord insertRecord : insertStmts) { // Schemata step: Rewrite insert for mutant ID String insertStmt = insertRecord.getStatement().replaceAll("INSERT INTO ", schemataPrefix); if (insertRecord.isSatisfying()) { groupedStatements.add(insertStmt); } else { if (!groupedStatements.isEmpty()) { int returnCount = databaseInteractor.executeUpdatesAsTransaction(groupedStatements); groupedStatements.clear(); if (returnCount == 0) { killed++; break; } } int returnCount = databaseInteractor.executeUpdate(insertStmt); if (returnCount != insertRecord.getReturnCode()) { killed++; break; // Stop once killed } } } if (!groupedStatements.isEmpty()) { int returnCount = databaseInteractor.executeUpdatesAsTransaction(groupedStatements); groupedStatements.clear(); if (returnCount == 0) { killed++; } } timer.stop(ExperimentTimer.TimingPoint.INSERTS_TIME); } } // Schemata step: Drop tables after iterating mutants timer.start(ExperimentTimer.TimingPoint.DROPS_TIME); databaseInteractor.executeUpdate(dropStmt); timer.stop(ExperimentTimer.TimingPoint.DROPS_TIME); timer.stopAll(); timer.finalise(); result.addValue("scorenumerator", (!quasiSchema) ? killed : mutants.size()); result.addValue("scoredenominator", mutants.size()); result.addValue("mutationpipeline", mutationPipeline.replaceAll(",", "|")); result.addValue("threads", 1); result.addValue("totaltime", timer.getTime(ExperimentTimer.TimingPoint.TOTAL_TIME)); result.addValue("dropstime", timer.getTime(ExperimentTimer.TimingPoint.DROPS_TIME)); result.addValue("createstime", timer.getTime(ExperimentTimer.TimingPoint.CREATES_TIME)); result.addValue("insertstime", timer.getTime(ExperimentTimer.TimingPoint.INSERTS_TIME)); result.addValue("mutationtime", timer.getTime(ExperimentTimer.TimingPoint.MUTATION_TIME)); result.addValue("paralleltime", timer.getTime(ExperimentTimer.TimingPoint.PARALLEL_TIME)); if (resultsToFile) { if (resultsToOneFile) { new CSVFileWriter(outputfolder + "mutationanalysis.dat").write(result); } else { new CSVFileWriter(outputfolder + casestudy + ".dat").write(result); } } if (resultsToDatabase) { new CSVDatabaseWriter(databaseConfiguration, new ExperimentConfiguration()).write(result); } }