QA团队的系统时钟

时间:2012-05-07 04:43:05

标签: java spring-aop instrumentation spring-batch activiti

我的QA团队正在进行业务生命周期测试(即老化,到期,到期,过期等),这需要移动应用程序时钟。我可以更改所有代码以引用调整后的时钟(我控制)。问题是(Web)应用程序使用多个第三方工具(例如Spring Batch,Activiti等),这些工具依赖于当前时间并通过System.currentTimeMillis()Date直接或间接使用Calendar

选项1 - Spring AOP。当我尝试这个选项时,它似乎只支持Spring加载的bean(?)因为System类是在Spring框架之外加载的,所以无法检测它。

选项2 - JMockit。让JMockit jar超过JUnit有些不同寻常。

选项3 - 使用Java 6检测(选项1和选项2之间的通用部分)。回到基础...(找到下面的相关代码)。

但是,测试代码中的断言始终失败。

我遇到了所有三个选项的障碍。不敢相信以前没有人这样做过,但也找不到合理的解决方案。

提前致谢。

public class InstrumentationAgent {
    private static Instrumentation instrumentation = null;


    /**
     * JVM hook to dynamically load InstrumentationAgent at runtime.
     * 
     * The agent class may have an agentmain method for use when the agent is
     * started after VM startup.
     * 
     * @param agentArgument
     * @param instrumentation
     */
    public static void agentmain(String agentArgument, Instrumentation instrumentation) {
        InstrumentationAgent.instrumentation = instrumentation;
    }

    /**
     * Programmatic hook to dynamically load modified byte codes. This method initializes/load the agent if necessary.
     * 
     * @param definitions
     * @throws Exception
     */
    public static void redefineClasses(ClassDefinition... definitions) throws Exception {
        if (InstrumentationAgent.instrumentation == null) {
            loadAgent();
        }

        InstrumentationAgent.instrumentation.redefineClasses(definitions);
    }

    private synchronized static void loadAgent() throws Exception {
        if (InstrumentationAgent.instrumentation != null) {
            return;
        }

        // Build the agent.jar file
        final File jarFile = File.createTempFile("agent", ".jar");
        jarFile.deleteOnExit();

        final Manifest manifest = new Manifest();
        final Attributes mainAttributes = manifest.getMainAttributes();
        mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
        mainAttributes.put(new Attributes.Name("Agent-Class"), InstrumentationAgent.class.getName());
        mainAttributes.put(new Attributes.Name("Can-Retransform-Classes"), "true");
        mainAttributes.put(new Attributes.Name("Can-Redefine-Classes"), "true");

        final JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest);
        final JarEntry agent = new JarEntry(InstrumentationAgent.class.getName().replace('.', '/') + ".class");
        jos.putNextEntry(agent);
        final ClassPool pool = ClassPool.getDefault();
        final CtClass ctClass = pool.get(InstrumentationAgent.class.getName());
        jos.write(ctClass.toBytecode());
        jos.closeEntry();
        jos.close();

        // Attach to VM and load the agent
        VirtualMachine vm = VirtualMachine.attach(getPidFromRuntimeMBean());
        vm.loadAgent(jarFile.getAbsolutePath());
        vm.detach();
    }

    private static String getPidFromRuntimeMBean() throws Exception {
        RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();
        Field jvmField = mxbean.getClass().getDeclaredField("jvm");

        jvmField.setAccessible(true);
        VMManagement management = (VMManagement) jvmField.get(mxbean);
        Method method = management.getClass().getDeclaredMethod("getProcessId");
        method.setAccessible(true);
        Integer processId = (Integer) method.invoke(management);

        return processId.toString();
    }

}



public class SystemTimeInstrumentation {
    private static long timeAdjustment = 200000L;
    private static byte[] originalClassByteArray;

    public static void startAdjustedClock() {
        ClassPool pool = ClassPool.getDefault();

        CtClass ctClass = null;
        byte[] instrumentedClassByteArray = null;
        try {
            originalClassByteArray = pool.get(System.class.getName()).toBytecode();
            ctClass = pool.makeClass(new java.io.ByteArrayInputStream(originalClassByteArray), false);
            CtMethod ctMethod = ctClass.getDeclaredMethod("currentTimeMillis");

            ctMethod.setBody("return 0L;");

            instrumentedClassByteArray = ctClass.toBytecode();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CannotCompileException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (ctClass != null) {
                ctClass.detach();
            }
        }

        try {
            InstrumentationAgent.redefineClasses(new ClassDefinition[] { new ClassDefinition(System.class,
                    instrumentedClassByteArray) });
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void stopAdjustedClock() {
        if (originalClassByteArray == null) {
            throw new RuntimeException("The stopAdjustedClock() called before startAdjustedClock()");
        } else {
            try {
                InstrumentationAgent.redefineClasses(new ClassDefinition[] { new ClassDefinition(System.class,
                        originalClassByteArray) });
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            originalClassByteArray = null;
        }
    }


public class SystemTimeInstrumentationTest extends TestCase {

    @Test 
    public void testModifiedClock() throws Exception {
        long unmodifiedTime = System.currentTimeMillis();
        SystemTimeInstrumentation.startAdjustedClock();
        long modifiedTime = System.currentTimeMillis();
        SystemTimeInstrumentation.stopAdjustedClock();

        assertTrue("The difference should me more than 200000", (modifiedTime-unmodifiedTime)>200000L);

    }

}

0 个答案:

没有答案