// Copyright 2012 Georg-August-Universität Göttingen, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package de.ugoe.cs.autoquest.plugin.uml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import java.util.logging.Level;
import static org.junit.Assert.*;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.StateMachine;
import org.eclipse.uml2.uml.UMLPackage;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import de.fraunhofer.fokus.testing.ModelUtils;
import de.ugoe.cs.autoquest.eventcore.Event;
import de.ugoe.cs.autoquest.plugin.http.HTTPLogParser;
import de.ugoe.cs.autoquest.plugin.http.SOAPUtils;
import de.ugoe.cs.autoquest.plugin.http.eventcore.SimpleSOAPEventType;
import de.ugoe.cs.autoquest.testgeneration.RandomWalkGenerator;
import de.ugoe.cs.autoquest.usageprofiles.FirstOrderMarkovModel;
import de.ugoe.cs.autoquest.usageprofiles.IStochasticProcess;
import de.ugoe.cs.util.SerializationUtils;
import de.ugoe.cs.util.console.TextConsole;
/**
*
* Tests for AutoQUESTs UMLUtils
*
*
* @author Steffen Herbold
*/
public class UMLUtilsTest {
private final static String OUTPUT_DIR = "target/tmp/test-outputs/";
private final static boolean DELETE_OUTPUTS = false;
// for RLUS
private final static TestData deda_1 = new TestData("deda_rlus_properties.prop",
"deda_usagejournal.log",
"deda_rlus_usageprofile.dat",
"deda_model.uml",
"deda_rlus_model_testsuite.uml",
"deda_rlus_model_scheduling.uml");
// for IXS
private final static TestData deda_2 = new TestData("deda_ixs_properties.prop",
"deda_usagejournal.log",
"deda_ixs_usageprofile.dat",
"deda_model.uml",
"deda_ixs_model_testsuite.uml",
"deda_ixs_model_scheduling.uml");
private final static TestData ita_1 = new TestData("ita_properties.prop",
"ita_usagejournal.log",
"ita_usageprofile.dat", "ita_model.uml",
"ita_model_testsuite.uml",
"ita_model_scheduling.uml");
private static class TestData {
public final String propertiesFile;
public final String usageJournalFile;
public final String usageProfileFile;
public final String dslModelFile;
public final String testSuiteFile;
public final String schedulingFile;
public TestData(String propertiesFile,
String usageJournalFile,
String usageProfileFile,
String dslModelFile,
String testSuiteFile,
String schedulingFile)
{
this.propertiesFile = propertiesFile;
this.usageJournalFile = usageJournalFile;
this.usageProfileFile = usageProfileFile;
this.dslModelFile = dslModelFile;
this.testSuiteFile = testSuiteFile;
this.schedulingFile = schedulingFile;
}
@Override
public String toString() {
StringBuilder strBld = new StringBuilder();
strBld.append("Properties " + propertiesFile + "\n");
strBld.append("Usage Journal " + usageJournalFile + "\n");
strBld.append("Usage Profile " + usageProfileFile + "\n");
strBld.append("DSL Model " + dslModelFile + "\n");
strBld.append("Test Suite " + testSuiteFile + "\n");
strBld.append("Scheduling " + schedulingFile + "\n");
return strBld.toString();
}
}
@BeforeClass
public static void setUpBeforeClass() throws Exception {
new TextConsole(Level.SEVERE);
}
@After
public void tearDown() throws Exception {
if (DELETE_OUTPUTS) {
deleteFiles(new File(OUTPUT_DIR));
}
}
@Test
public void testCreateUMLTransitionSequence_ITA_1() throws Exception {
TestData testdata = ita_1;
/*
* Properties properties = loadProperties(testdata); //Collection> sequences =
* loadAndPreprocessUsageJournal(testdata, properties);
*
* Model model =
* ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
*
* StateMachine stateMachine = (StateMachine)
* model.getPackagedElement("StateMachineTransportService", true,
* UMLPackage.Literals.STATE_MACHINE, true);
*
*
* Collection> umlSequences = new LinkedList<>();
*
* // remove everything but transport from sequences for (List sequence : sequences)
* { for (Iterator eventIter = sequence.iterator(); eventIter.hasNext();) { Event
* event = eventIter.next(); if
* (!"TransportService".equals(SOAPUtils.getServiceNameFromEvent(event))) {
* eventIter.remove(); } } umlSequences.add(UMLUtils.createUMLTransitionSequence(sequence,
* stateMachine)); }
*/
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
StateMachine stateMachine =
(StateMachine) model.getPackagedElement("StateMachineTransportService", true,
UMLPackage.Literals.STATE_MACHINE, true);
List manuallyCreatedSequence = new LinkedList<>();
manuallyCreatedSequence
.add(new Event(new SimpleSOAPEventType("transportInstructionRequest",
"TransportService", "Logistics_Environment",
null)));
manuallyCreatedSequence
.add(new Event(new SimpleSOAPEventType("transportInstructionConfirmationRequest",
"materialSupplierService",
"Logistics_Environment", null)));
// TODO make test case run
//UMLUtils.createUMLTransitionSequence(manuallyCreatedSequence, stateMachine);
}
@Test
public void testConvertStateMachineToUsageProfile__ITA_1() throws Exception {
// TODO make test run
/*TestData testdata = ita_1;
assertTrue("test currently not working", false);
Properties properties = loadProperties(testdata);
Collection> sequences = loadAndPreprocessUsageJournal(testdata, properties);
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
StateMachine stateMachine =
(StateMachine) model.getPackagedElement("StateMachineTransportService", true,
UMLPackage.Literals.STATE_MACHINE, true);
Collection> umlSequences = new LinkedList<>();
// remove everything but transport from sequences
for (List sequence : sequences) {
for (Iterator eventIter = sequence.iterator(); eventIter.hasNext();) {
Event event = eventIter.next();
if (!"TransportService".equals(SOAPUtils.getServiceNameFromEvent(event))) {
eventIter.remove();
}
}
umlSequences.add(UMLUtils.createUMLTransitionSequence(sequence, stateMachine));
}
UMLUtils.convertStateMachineToUsageProfile(umlSequences, stateMachine);
ModelUtils.writeModelToFile(model, OUTPUT_DIR + "ita_v2_result.uml");*/
}
@Test
public void testCreateInteractionFromEventSequence_DEDA_1() throws Exception {
createInteractionFromEventSequenceWorkflow(deda_1);
}
@Test
public void testCreateInteractionFromEventSequence_DEDA_2() throws Exception {
createInteractionFromEventSequenceWorkflow(deda_2);
}
@Test
public void testCreateInteractionFromEventSequence_ITA_1() throws Exception {
createInteractionFromEventSequenceWorkflow(ita_1);
}
@Test
public void testCalculateUsageScore_DEDA_1() throws Exception {
calculateUsageScoreWorkflow(deda_1);
}
@Test
public void testCalculateUsageScore_DEDA_2() throws Exception {
calculateUsageScoreWorkflow(deda_2);
}
@Test
public void testCalculateUsageScore_ITA_1() throws Exception {
calculateUsageScoreWorkflow(ita_1);
}
@Test
public void testCreateScheduling_DEDA_1() throws Exception {
createSchedulingWorkflow(deda_1);
}
@Test
public void testCreateScheduling_DEDA_2() throws Exception {
createSchedulingWorkflow(deda_2);
}
@Test
public void testCreateScheduling_ITA() throws Exception {
createSchedulingWorkflow(ita_1);
}
@Test
public void testValidateModelWithLog_DEDA_1() throws Exception {
validateModelWithLogWorkflow(deda_1);
}
@Test
public void testValidateModelWithLog_DEDA_2() throws Exception {
validateModelWithLogWorkflow(deda_2);
}
@Test
public void testValidateModelWithLog_ITA_1() throws Exception {
validateModelWithLogWorkflow(ita_1);
}
private void validateModelWithLogWorkflow(TestData testdata) throws Exception {
Properties properties = loadProperties(testdata);
Collection> sequences = loadAndPreprocessUsageJournal(testdata, properties);
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
// run validation
int violations =
UMLUtils.validateModelWithLog(sequences, model, properties.getProperty("test.context"));
if (violations == 0) {
System.out.println("No problems found.");
}
else {
System.out.println(violations + " violations found.");
}
}
private void createInteractionFromEventSequenceWorkflow(TestData testdata) throws Exception {
Properties properties = loadProperties(testdata);
Collection> sequences = loadAndPreprocessUsageJournal(testdata, properties);
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
// create a test case for each observed sequence
int i = 0;
for (List sequence : sequences) {
UMLUtils.createInteractionFromEventSequence(sequence, model,
properties.getProperty("testcases.prefix") +
"_" + i,
properties.getProperty("test.context"));
i++;
}
ModelUtils.writeModelToFile(model, OUTPUT_DIR + testdata.testSuiteFile);
}
private void calculateUsageScoreWorkflow(TestData testdata) throws Exception {
Properties properties = loadProperties(testdata);
Collection> sequences = loadAndPreprocessUsageJournal(testdata, properties);
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
IStochasticProcess usageProfile = createUsageProfile(testdata, sequences);
Collection> generatedSequences =
createRandomSequences(usageProfile, properties);
int i = 1;
List interactions = new LinkedList<>();
int[] lengths = new int[generatedSequences.size()];
for (List sequence : generatedSequences) {
interactions.add(UMLUtils
.createInteractionFromEventSequence(sequence, model,
properties.getProperty("testcases.prefix") +
"_" + i,
properties.getProperty("test.context")));
lengths[i - 1] = sequence.size();
i++;
}
for (int j = 0; j < interactions.size(); j++) {
double usageScore = UMLUtils.calculateUsageScore(interactions.get(j), usageProfile);
System.out.format("usage score %02d: %.2f \t %d\n", j + 1, usageScore, lengths[j]);
}
}
private void createSchedulingWorkflow(TestData testdata) throws Exception {
Properties properties = loadProperties(testdata);
Collection> sequences = loadAndPreprocessUsageJournal(testdata, properties);
Model model =
ModelUtils.loadModel(ClassLoader.getSystemResourceAsStream(testdata.dslModelFile));
IStochasticProcess usageProfile = createUsageProfile(testdata, sequences);
Collection> generatedSequences =
createRandomSequences(usageProfile, properties);
int i = 1;
for (List sequence : generatedSequences) {
UMLUtils.createInteractionFromEventSequence(sequence, model,
properties.getProperty("testcases.prefix") +
"_" + i,
properties.getProperty("test.context"));
i++;
}
UMLUtils.createScheduling(model, usageProfile, properties.getProperty("test.context"));
ModelUtils.writeModelToFile(model, OUTPUT_DIR + testdata.schedulingFile);
}
private Properties loadProperties(TestData testdata) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream(ClassLoader.getSystemResource(testdata.propertiesFile)
.getFile()));
return properties;
}
private Collection> loadAndPreprocessUsageJournal(TestData testdata,
Properties properties)
throws Exception
{
// load usage journal
HTTPLogParser parser =
new HTTPLogParser(new File(ClassLoader.getSystemResource(testdata.propertiesFile)
.getFile()));
parser.parseFile(new File(ClassLoader.getSystemResource(testdata.usageJournalFile)
.getFile()));
Collection> sequences = parser.getSequences();
// remove non SOAP events and convert to SimpleSOAPEventType
Collection> simpleSOAPSequences = new LinkedList<>();
for (List sequence : sequences) {
simpleSOAPSequences.add(SOAPUtils.convertToSimpleSOAPEvent(sequence, true));
}
// remove calls to ingored services
Set ignoredServices = new HashSet<>();
String ignoredServicesString = properties.getProperty("test.ignored.services");
if (ignoredServicesString != null) {
for (String service : ignoredServicesString.split(",")) {
ignoredServices.add(service.trim());
}
}
for (List sequence : simpleSOAPSequences) {
for (Iterator eventIter = sequence.iterator(); eventIter.hasNext();) {
Event event = eventIter.next();
SimpleSOAPEventType eventType = (SimpleSOAPEventType) event.getType();
if (ignoredServices.contains(eventType.getServiceName())) {
eventIter.remove();
}
}
}
return simpleSOAPSequences;
}
private IStochasticProcess createUsageProfile(TestData testdata,
Collection> sequences)
throws Exception
{
FirstOrderMarkovModel usageProfile = new FirstOrderMarkovModel(new Random(1));
usageProfile.train(sequences);
FileOutputStream fos = new FileOutputStream(OUTPUT_DIR + testdata.usageProfileFile);
SerializationUtils.serialize(usageProfile, fos);
fos.close();
return usageProfile;
}
private Collection> createRandomSequences(IStochasticProcess usageProfile,
Properties properties) throws Exception
{
int numberOfTestCases = Integer.parseInt(properties.getProperty("testcases.number"));
int testCaseMinLength = Integer.parseInt(properties.getProperty("testcases.minlenth", "1"));
int testCaseMaxLength =
Integer.parseInt(properties.getProperty("testcases.maxlenth", "100"));
int maxIter = numberOfTestCases * 100;
RandomWalkGenerator testGenerator =
new RandomWalkGenerator(numberOfTestCases, testCaseMinLength, testCaseMaxLength, true,
maxIter);
return testGenerator.generateTestSuite(usageProfile);
}
private void deleteFiles(File file) {
if (file.exists()) {
if (file.isDirectory()) {
for (File child : file.listFiles()) {
deleteFiles(child);
}
}
try {
file.delete();
}
catch (Exception e) {
// ignore and delete as much as possible
}
}
}
}