All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.evosuite.setup.EnvironmentTestClusterAugmenter Maven / Gradle / Ivy

/**
 * Copyright (C) 2010-2018 Gordon Fraser, Andrea Arcuri and EvoSuite
 * contributors
 *
 * This file is part of EvoSuite.
 *
 * EvoSuite is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3.0 of the License, or
 * (at your option) any later version.
 *
 * EvoSuite is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with EvoSuite. If not, see .
 */
package org.evosuite.setup;

import org.evosuite.Properties;
import org.evosuite.TestGenerationContext;
import org.evosuite.runtime.*;
import org.evosuite.runtime.System;
import org.evosuite.runtime.annotation.*;
import org.evosuite.runtime.javaee.JeeData;
import org.evosuite.runtime.javaee.TestDataJavaEE;
import org.evosuite.runtime.javaee.javax.servlet.EvoServletState;
import org.evosuite.runtime.mock.javax.naming.EvoNamingContext;
import org.evosuite.runtime.testdata.*;
import org.evosuite.runtime.util.JOptionPaneInputs;
import org.evosuite.runtime.util.JOptionPaneInputs.GUIAction;
import org.evosuite.runtime.util.SystemInUtil;
import org.evosuite.runtime.vfs.VirtualFileSystem;
import org.evosuite.runtime.vnet.EndPointInfo;
import org.evosuite.runtime.vnet.VirtualNetwork;
import org.evosuite.testcase.TestCase;
import org.evosuite.utils.generic.GenericAccessibleObject;
import org.evosuite.utils.generic.GenericClass;
import org.evosuite.utils.generic.GenericConstructor;
import org.evosuite.utils.generic.GenericMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 *
 * This class is responsible to augment {@link org.evosuite.setup.TestCluster}
 * with search operators based on the environment the SUT interacts with
 *
 * Created by arcuri on 6/10/14.
 */
public class EnvironmentTestClusterAugmenter {

	private static final Logger logger = LoggerFactory.getLogger(EnvironmentTestClusterAugmenter.class);

	private volatile boolean hasAddedRandom;
	private volatile boolean hasAddedSystem;
	private volatile boolean hasAddedFiles;
	private volatile boolean hasAddedSystemIn;

	private volatile boolean hasAddedRemoteURLs;
	private volatile boolean hasAddedUdpSupport;
	private volatile boolean hasAddedTcpListeningSupport;
	private volatile boolean hasAddedTcpRemoteSupport;

	private final TestCluster cluster;
	private TestClusterGenerator testClusterGenerator;

	/**
	 * Keep track of all EvoSuite classes that have been already fully handled
	 * (via recursion)
	 */
	private final Set handledClasses;

	public EnvironmentTestClusterAugmenter(TestCluster cluster) {
		this.cluster = cluster;
		testClusterGenerator = TestGenerationContext.getInstance().getTestClusterGenerator();
		// testClusterGenerator = new TestClusterGenerator(cluster.getInheritanceTree());
		this.handledClasses = new LinkedHashSet<>();
	}

	/**
	 *
	 * 

* If access to certain classes was observed at runtime, this method adds * test calls to the test cluster which may lead to covering more branches. * For example, if file access was observed, statements will be introduced * that perform mutations on the accessed files like content modification. * *

* (Idea by Gordon, JavaDoc written by Daniel) * * @see org.evosuite.runtime.Random * @see org.evosuite.runtime.System */ public void handleRuntimeAccesses(TestCase test) { if(testClusterGenerator == null) { testClusterGenerator = TestGenerationContext.getInstance().getTestClusterGenerator(); // Initialisation might not be ready yet if(testClusterGenerator == null) return; } // important, as test might have been changed since last update (eg // mutation) test.getAccessedEnvironment().clear(); if (Properties.REPLACE_CALLS) { handleReplaceCalls(); } if (Properties.VIRTUAL_FS) { handleVirtualFS(test); } if (Properties.REPLACE_SYSTEM_IN) { handleSystemIn(); } if (Properties.REPLACE_GUI) { handleGUI(); } if (Properties.VIRTUAL_NET) { handleNetwork(test); } if (Properties.JEE) { handleJEE(test); } } private boolean hasAddedJOptionPaneInputsForStrings = false; private boolean hasAddedJOptionPaneYesNoCancelSelection = false; private boolean hasAddedJOptionPaneYesNoSelection = false; private boolean hasAddedJOptionPaneOkCancelSelection = false; private boolean hasAddedJOptionPaneOptionSelection = false; private void handleGUI() { if (!hasAddedJOptionPaneInputsForStrings && JOptionPaneInputs.getInstance().hasDialog(GUIAction.STRING_INPUT)) { hasAddedJOptionPaneInputsForStrings = true; try { final Class clazz = JOptionPaneInputs.class; final String ENQUEUE_INPUT_STRING = "enqueueInputString"; final Method method_to_call = clazz.getMethod(ENQUEUE_INPUT_STRING, new Class[] { String.class }); final GenericClass genericClass = new GenericClass(clazz); final GenericMethod genericMethod = new GenericMethod(method_to_call, genericClass); // adds JOptionPaneInputs.enqueueString() to the palette of // methods that can be used TestCluster.getInstance().addEnvironmentTestCall(genericMethod); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } if (!hasAddedJOptionPaneYesNoCancelSelection && JOptionPaneInputs.getInstance().hasDialog(GUIAction.YES_NO_CANCEL_SELECTION)) { hasAddedJOptionPaneYesNoCancelSelection = true; try { final Class clazz = JOptionPaneInputs.class; final String ENQUEUE_YES_NO_CANCEL_SELECTION = "enqueueYesNoCancelSelection"; final Method method_to_call = clazz.getMethod(ENQUEUE_YES_NO_CANCEL_SELECTION, new Class[] { int.class }); final GenericClass genericClass = new GenericClass(clazz); final GenericMethod genericMethod = new GenericMethod(method_to_call, genericClass); // adds JOptionPaneInputs.enqueueString() to the palette of // methods that can be used TestCluster.getInstance().addEnvironmentTestCall(genericMethod); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } if (!hasAddedJOptionPaneYesNoSelection && JOptionPaneInputs.getInstance().hasDialog(GUIAction.YES_NO_SELECTION)) { hasAddedJOptionPaneYesNoSelection = true; try { final Class clazz = JOptionPaneInputs.class; final String ENQUEUE_YES_NO_SELECTION = "enqueueYesNoSelection"; final Method method_to_call = clazz.getMethod(ENQUEUE_YES_NO_SELECTION, new Class[] { int.class }); final GenericClass genericClass = new GenericClass(clazz); final GenericMethod genericMethod = new GenericMethod(method_to_call, genericClass); // adds JOptionPaneInputs.enqueueString() to the palette of // methods that can be used TestCluster.getInstance().addEnvironmentTestCall(genericMethod); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } if (!hasAddedJOptionPaneOkCancelSelection && JOptionPaneInputs.getInstance().hasDialog(GUIAction.OK_CANCEL_SELECTION)) { hasAddedJOptionPaneOkCancelSelection = true; try { final Class clazz = JOptionPaneInputs.class; final String ENQUEUE_OK_CANCEL_SELECTION = "enqueueOkCancelSelection"; final Method method_to_call = clazz.getMethod(ENQUEUE_OK_CANCEL_SELECTION, new Class[] { int.class }); final GenericClass genericClass = new GenericClass(clazz); final GenericMethod genericMethod = new GenericMethod(method_to_call, genericClass); // adds JOptionPaneInputs.enqueueString() to the palette of // methods that can be used TestCluster.getInstance().addEnvironmentTestCall(genericMethod); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } if (!hasAddedJOptionPaneOptionSelection && JOptionPaneInputs.getInstance().hasDialog(GUIAction.OPTION_SELECTION)) { hasAddedJOptionPaneOptionSelection = true; try { final Class clazz = JOptionPaneInputs.class; final String ENQUEUE_OPTION_SELECTION = "enqueueOptionSelection"; final Method method_to_call = clazz.getMethod(ENQUEUE_OPTION_SELECTION, new Class[] { int.class }); final GenericClass genericClass = new GenericClass(clazz); final GenericMethod genericMethod = new GenericMethod(method_to_call, genericClass); // adds JOptionPaneInputs.enqueueString() to the palette of // methods that can be used TestCluster.getInstance().addEnvironmentTestCall(genericMethod); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } } private void handleJEE(TestCase test) { JeeData jeeData = TestDataJavaEE.getInstance().getJeeData(); test.getAccessedEnvironment().setJeeData(jeeData); if (jeeData.lookedUpContextNames.size() > 0) { addEnvironmentClassToCluster(EvoNamingContext.class); // TODO add method with right input type } if (!Properties.HANDLE_SERVLETS) { /* * Started to prepare custom mocks for Servlets, but then realized * that their behavior is very basic. As such, most likely they are * not needed, as they could be much better replaced by functional * mocks with Mockito... */ return; } if (jeeData.wasAServletInitialized) { addEnvironmentClassToCluster(EvoServletState.class); } // TODO TestDataJavaEE data for Servlets } /** * Add the given klass to the test cluster. Also recursively add (as * modifiers) all the other EvoSuite classes for which the given class is a * generator * * @param klass */ private boolean addEnvironmentClassToCluster(Class klass) { if (handledClasses.contains(klass.getCanonicalName()) || !TestClusterUtils.isEvoSuiteClass(klass)) { return false; // already handled, or not valid } handledClasses.add(klass.getCanonicalName()); boolean excludeClass = klass.getAnnotation(EvoSuiteClassExclude.class) != null; // only consider public constructors/methods for (Constructor c : klass.getConstructors()) { // first check if it should be skipped if (shouldSkip(excludeClass, c)) { continue; } GenericAccessibleObject gc = new GenericConstructor(c, klass); TestCluster.getInstance().addEnvironmentTestCall(gc); GenericClass genclass = new GenericClass(klass); TestCluster.getInstance().invalidateGeneratorCache(genclass); TestCluster.getInstance().addGenerator(genclass, gc); testClusterGenerator.addNewDependencies(Arrays.asList(c.getParameterTypes())); } for (Method m : klass.getMethods()) { if (shouldSkip(excludeClass, m)) { continue; } GenericAccessibleObject gm = new GenericMethod(m, klass); TestCluster.getInstance().addEnvironmentTestCall(gm); testClusterGenerator.addNewDependencies(Arrays.asList(m.getParameterTypes())); Class returnType = m.getReturnType(); if (!returnType.equals(Void.TYPE)) { GenericClass genclass = new GenericClass(returnType); TestCluster.getInstance().invalidateGeneratorCache(genclass); TestCluster.getInstance().addGenerator(genclass, gm); addEnvironmentDependency(returnType); } } return true; } private void addEnvironmentDependency(Class klass) { if (handledClasses.contains(klass.getCanonicalName()) || !TestClusterUtils.isEvoSuiteClass(klass)) { return; // already handled, or not valid } handledClasses.add(klass.getCanonicalName()); boolean excludeClass = klass.getAnnotation(EvoSuiteClassExclude.class) != null; // do not consider constructors for (Method m : klass.getMethods()) { if (shouldSkip(excludeClass, m)) { continue; } GenericAccessibleObject gm = new GenericMethod(m, klass); GenericClass gc = new GenericClass(klass); TestCluster.getInstance().addModifier(gc, gm); testClusterGenerator.addNewDependencies(Arrays.asList(m.getParameterTypes())); Class returnType = m.getReturnType(); if (!returnType.equals(Void.TYPE)) { GenericClass genclass = new GenericClass(returnType); TestCluster.getInstance().invalidateGeneratorCache(genclass); TestCluster.getInstance().addGenerator(genclass, gm); addEnvironmentDependency(returnType); } } } private boolean isObjectMethod(AccessibleObject ao) { if (!(ao instanceof Method)) { return false; } /* * Note: this check is not 100% precise (one could have new completely * unrelated method with same name from Object but different signature). * However, as we only apply it on EvoSuite methods, should be fine */ Method m = (Method) ao; String name = m.getName(); switch (name) { case "clone": case "equals": case "finalize": case "getClass": case "hashCode": case "notify": case "notifyAll": case "toString": case "wait": return true; default: return false; } } private boolean shouldSkip(boolean excludeClass, AccessibleObject c) { if (isObjectMethod(c)) { return true; } if (excludeClass) { boolean include = c.getAnnotation(EvoSuiteInclude.class) != null; if (!include) { return true; } } else { boolean exclude = c.getAnnotation(EvoSuiteExclude.class) != null || c.getAnnotation(EvoSuiteAssertionOnly.class) != null; if (exclude) { return true; } } Constraints constraints = c.getAnnotation(Constraints.class); if (constraints != null && constraints.noDirectInsertion()) { return true; } return false; } private void handleNetwork(TestCase test) { /* * there are several things that are mocked in the network. based on * what the SUT used, we might only need a subset of methods used to * manipulate the mocked network */ // TODO might need more stuff once we handle assertion generation test.getAccessedEnvironment() .addLocalListeningPorts(VirtualNetwork.getInstance().getViewOfLocalListeningPorts()); test.getAccessedEnvironment().addRemoteURLs(VirtualNetwork.getInstance().getViewOfRemoteAccessedFiles()); test.getAccessedEnvironment() .addRemoteContactedPorts(VirtualNetwork.getInstance().getViewOfRemoteContactedPorts()); if (!hasAddedRemoteURLs && test.getAccessedEnvironment().getViewOfRemoteURLs().size() > 0) { hasAddedRemoteURLs = true; try { TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( NetworkHandling.class.getMethod("createRemoteTextFile", new Class[] { EvoSuiteURL.class, String.class }), new GenericClass(NetworkHandling.class))); } catch (Exception e) { logger.error("Error while handling hasAddedRemoteURLs: " + e.getMessage(), e); } } boolean openedTCP = false; boolean openedUDP = false; for (EndPointInfo info : test.getAccessedEnvironment().getViewOfLocalListeningPorts()) { if (info.getType().equals(VirtualNetwork.ConnectionType.TCP)) { openedTCP = true; } else if (info.getType().equals(VirtualNetwork.ConnectionType.UDP)) { openedUDP = true; } if (openedTCP && openedUDP) { break; } } if (!hasAddedUdpSupport && openedUDP) { hasAddedUdpSupport = true; try { TestCluster.getInstance() .addEnvironmentTestCall( new GenericMethod( NetworkHandling.class.getMethod("sendUdpPacket", new Class[] { EvoSuiteLocalAddress.class, EvoSuiteRemoteAddress.class, byte[].class }), new GenericClass(NetworkHandling.class))); TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( NetworkHandling.class.getMethod("sendUdpPacket", new Class[] { EvoSuiteLocalAddress.class, byte[].class }), new GenericClass(NetworkHandling.class))); } catch (Exception e) { logger.error("Error while handling hasAddedUdpSupport: " + e.getMessage(), e); } } if (!hasAddedTcpListeningSupport && openedTCP) { hasAddedTcpListeningSupport = true; try { TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( NetworkHandling.class.getMethod("sendDataOnTcp", new Class[] { EvoSuiteLocalAddress.class, byte[].class }), new GenericClass(NetworkHandling.class))); TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( NetworkHandling.class.getMethod("sendMessageOnTcp", new Class[] { EvoSuiteLocalAddress.class, String.class }), new GenericClass(NetworkHandling.class))); } catch (Exception e) { logger.error("Error while handling hasAddedTcpListeningSupport: " + e.getMessage(), e); } } if (!hasAddedTcpRemoteSupport && test.getAccessedEnvironment().getViewOfRemoteContactedPorts().size() > 0) { hasAddedTcpRemoteSupport = true; try { TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( NetworkHandling.class.getMethod("openRemoteTcpServer", new Class[] { EvoSuiteRemoteAddress.class }), new GenericClass(NetworkHandling.class))); } catch (Exception e) { logger.error("Error while handling hasAddedTcpRemoteSupport: " + e.getMessage(), e); } } } /** * If System.in was used, add methods to handle/simulate it */ private void handleSystemIn() { if (!hasAddedSystemIn && SystemInUtil.getInstance().hasBeenUsed()) { hasAddedSystemIn = true; try { TestCluster.getInstance() .addEnvironmentTestCall(new GenericMethod( SystemInUtil.class.getMethod("addInputLine", new Class[] { String.class }), new GenericClass(SystemInUtil.class))); } catch (SecurityException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } } private void handleVirtualFS(TestCase test) { test.getAccessedEnvironment().addLocalFiles(VirtualFileSystem.getInstance().getAccessedFiles()); if (!hasAddedFiles && VirtualFileSystem.getInstance().getAccessedFiles().size() > 0) { logger.info("Adding EvoSuiteFile calls to cluster"); hasAddedFiles = true; addEnvironmentClassToCluster(FileSystemHandling.class); } } private void handleReplaceCalls() { if (!hasAddedRandom && Random.wasAccessed()) { hasAddedRandom = true; try { cluster.addTestCall( new GenericMethod(Random.class.getMethod("setNextRandom", new Class[] { int.class }), new GenericClass(Random.class))); } catch (SecurityException | NoSuchMethodException e) { logger.error("Error while handling Random: " + e.getMessage(), e); } } if (!hasAddedSystem && org.evosuite.runtime.System.wasTimeAccessed()) { hasAddedSystem = true; try { cluster.addTestCall( new GenericMethod(System.class.getMethod("setCurrentTimeMillis", new Class[] { long.class }), new GenericClass(System.class))); } catch (SecurityException e) { logger.error("Error while handling System: " + e.getMessage(), e); } catch (NoSuchMethodException e) { logger.error("Error while handling System: " + e.getMessage(), e); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy