/**
* Copyright (C) 2010-2017 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 <http://www.gnu.org/licenses/>.
*/
package org.evosuite.runtime.agent;
import java.io.File;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.reflect.Constructor;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLStreamHandler;
import com.examples.with.different.packagename.agent.*;
import org.evosuite.runtime.instrumentation.InstrumentedClass;
import org.evosuite.runtime.instrumentation.MethodCallReplacementCache;
import org.evosuite.runtime.instrumentation.MethodCallReplacementClassAdapter;
import org.evosuite.runtime.mock.java.net.EvoURLStreamHandler;
import org.evosuite.runtime.mock.java.net.URLUtil;
import org.junit.*;
import org.evosuite.runtime.Runtime;
import org.evosuite.runtime.RuntimeSettings;
import org.evosuite.runtime.agent.InstrumentingAgent;
import org.evosuite.runtime.mock.MockFramework;
import org.evosuite.runtime.mock.java.io.MockFile;
/**
* Note: this needs be run as an integration test (IT), as it requires
* the creation of the jar file first.
* This is automatically set up in the pom file, but the test might fail
* if run directly from an IDE
*
* @author arcuri
*
*/
public class InstrumentingAgent_IntTest {
private final boolean replaceCalls = RuntimeSettings.mockJVMNonDeterminism;
private final boolean vfs = RuntimeSettings.useVFS;
private final boolean vnet = RuntimeSettings.useVNET;
@BeforeClass
public static void initClass(){
InstrumentingAgent.initialize();
}
@Before
public void storeValues() {
RuntimeSettings.mockJVMNonDeterminism = true;
RuntimeSettings.useVFS = true;
RuntimeSettings.useVNET = true;
MethodCallReplacementCache.resetSingleton();
Runtime.getInstance().resetRuntime();
}
@After
public void resetValues() {
RuntimeSettings.mockJVMNonDeterminism = replaceCalls;
RuntimeSettings.useVFS = vfs;
RuntimeSettings.useVNET = vnet;
}
@Test
public void testTransformationInClassExtendingAbstract() throws Exception{
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
InstrumentingAgent.activate();
//even if re-instrument, they should be fine
InstrumentingAgent.getInstrumentation().retransformClasses(AbstractTime.class,ConcreteTime.class);
ConcreteTime time = new ConcreteTime();
/*
* Using abstract class here would fail without retransformClasses, as it would be loaded
* by JUnit before any method (static, BeforeClass) of this test
* suite is executed, and so it would not get instrumented
*/
//AbstractTime time = new ConcreteTime();
Assert.assertEquals(expected, time.getTime());
} finally {
InstrumentingAgent.deactivate();
}
}
@Test
public void checkRetransformIsSupported(){
Assert.assertTrue(InstrumentingAgent.getInstrumentation().isRetransformClassesSupported());
}
@Test
public void testFailingTransformation() throws UnmodifiableClassException{
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
InstrumentingAgent.activate();
InstrumentingAgent.getInstrumentation().retransformClasses(SecondAbstractTime.class,SecondConcreteTime.class);
Assert.fail();
} catch(UnsupportedOperationException e){
/*
* this is expected, as default instrumentation adds methods (eg hashCode in this case), and
* that is currently not permitted in Java.
*
* Note: once we change instrumentation to do not add any method, or Java will support this kind
* of re-transformation, then this check should be changed
*/
}finally {
InstrumentingAgent.deactivate();
}
try{
InstrumentingAgent.activate();
SecondAbstractTime time = new SecondConcreteTime();
/*
* Using abstract class here fails, as it would be loaded
* by JUnit before any method (static, BeforeClass) of this test
* suite is executed, and so it is not instrumented
*/
Assert.assertNotEquals(expected, time.getTime());
} finally {
InstrumentingAgent.deactivate();
}
/*
Note: following check does not apply any more, as we now are adding an interface to each
instrumented class, which makes retransformation not possible any more.
anyway, retransformation is kind of deprecated, as we do not really use it anymore (but
left code if in the future Java ll have better support)
*/
/*
//to do re-instrumentation without adding new methods, we need to set it up with setRetransformingMode
try{
InstrumentingAgent.activate();
InstrumentingAgent.setRetransformingMode(true);
InstrumentingAgent.getInstumentation().retransformClasses(SecondAbstractTime.class,SecondConcreteTime.class);
//finally it should work
SecondAbstractTime time = new SecondConcreteTime();
Assert.assertEquals(expected, time.getTime());
} finally {
InstrumentingAgent.setRetransformingMode(false);
InstrumentingAgent.deactivate();
}
*/
}
@Test
public void testTime(){
long now = System.currentTimeMillis();
Assert.assertTrue("",TimeB.getTime() >= now);
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
InstrumentingAgent.activate();
Assert.assertEquals(expected, TimeA.getTime());
} finally {
InstrumentingAgent.deactivate();
}
}
@Test
public void testTransformationInAbstractClass(){
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
/*
* Note: this does not work, but we found a work around
* by forcing loading before JUnit test execution
* with a customized Runner
*/
InstrumentingAgent.activate();
//com.examples.with.different.packagename.agent.AbstractTime time = new com.examples.with.different.packagename.agent.ConcreteTime();
//Assert.assertEquals(expected, time.getTime());
} finally {
InstrumentingAgent.deactivate();
}
}
@Test
public void testTransformation(){
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
InstrumentingAgent.activate();
TimeC time = new TimeC();
Assert.assertEquals(expected, time.getTime());
} finally {
InstrumentingAgent.deactivate();
}
}
@Test
public void testTransformationInExtendingClass(){
long expected = 42;
org.evosuite.runtime.System.setCurrentTimeMillis(expected);
try{
InstrumentingAgent.activate();
ExtendingTimeC time = new ExtendingTimeC();
Assert.assertEquals(expected, time.getTime());
} finally {
InstrumentingAgent.deactivate();
}
}
@Test
public void testInstrumentation() throws Exception{
try{
InstrumentingAgent.activate();
Instrumentation inst = InstrumentingAgent.getInstrumentation();
Assert.assertNotNull(inst);
ClassLoader loader = this.getClass().getClassLoader();
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(TimeA.class.getName())));
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(TimeB.class.getName())));
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(TimeC.class.getName())));
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(ExtendingTimeC.class.getName())));
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(ConcreteTime.class.getName())));
Assert.assertTrue(inst.isModifiableClass(loader.loadClass(AbstractTime.class.getName())));
} finally{
InstrumentingAgent.deactivate();
}
}
@Test
public void testMockFramework_OverrideMock(){
Object obj = null;
try{
InstrumentingAgent.activate();
obj = new GetFile();
} finally {
InstrumentingAgent.deactivate();
}
GetFile gf = (GetFile) obj;
MockFramework.enable();
Assert.assertTrue(gf.get() instanceof MockFile);
//now disable
MockFramework.disable();
//even if GetFile is instrumented, should not return a mock now
Assert.assertFalse(gf.get() instanceof MockFile);
}
@Test
public void testMockFramework_StaticReplacementMock(){
try{
InstrumentingAgent.activate();
new SumRuntime();
} finally {
InstrumentingAgent.deactivate();
}
MockFramework.enable();
Assert.assertEquals(1101, SumRuntime.getSum());
//now disable
MockFramework.disable();
//even if SumRuntime is instrumented, should not return a mock sum now.
// note: it should be _extremely_ unlikely that original code returns such value by chance
Assert.assertFalse(SumRuntime.getSum() == 1101);
}
@Test
public void testMockFramework_StaticReplacementMock_ofConstructors() throws MalformedURLException {
try{
InstrumentingAgent.activate();
new GetURL();
} finally {
InstrumentingAgent.deactivate();
}
//first disable
MockFramework.disable();
String url = "http://www.evosuite.org";
URL res = GetURL.get(url);
URLStreamHandler handler = URLUtil.getHandler(res);
Assert.assertFalse(handler instanceof EvoURLStreamHandler);
//now enable
MockFramework.enable();
res = GetURL.get(url);
handler = URLUtil.getHandler(res);
Assert.assertTrue(handler instanceof EvoURLStreamHandler);
}
@Test
public void testMockFramework_StaticReplacementMock_2() throws Exception{
try{
InstrumentingAgent.activate();
new GetURL();
} finally {
InstrumentingAgent.deactivate();
}
//first disable
MockFramework.disable();
String url = "http://www.evosuite.org";
URL res = GetURL.getFromUri(url);
URLStreamHandler handler = URLUtil.getHandler(res);
Assert.assertFalse(handler instanceof EvoURLStreamHandler);
//now enable
MockFramework.enable();
res = GetURL.getFromUri(url);
handler = URLUtil.getHandler(res);
Assert.assertTrue(handler instanceof EvoURLStreamHandler);
}
@Test
public void testAddingInstrumentedClassInterface(){
Object obj = null;
try{
InstrumentingAgent.activate();
obj = new GetURL();
} finally {
InstrumentingAgent.deactivate();
}
Assert.assertTrue(obj instanceof InstrumentedClass);
}
@Test
public void testMockFramework_noAgent(){
/*
* OverrideMocks should default even if called
* directly.
*/
MockFramework.enable();
MockFile file = new MockFile("bar/foo");
File parent = file.getParentFile();
Assert.assertTrue(parent instanceof MockFile);
//now, disable
MockFramework.disable();
parent = file.getParentFile();
//should rollback to original behavior
Assert.assertFalse(parent instanceof MockFile);
}
}