jdk/test/com/sun/jdi/redefine/RedefineTest.java
author iignatyev
Wed, 15 Mar 2017 22:48:59 -0700
changeset 44423 306c020eb154
parent 30376 2ccf2cf7ea48
permissions -rw-r--r--
8176176: fix @modules in jdk_svc tests Reviewed-by: shurailine, sspitsyn

/*
 * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/**
 * @test
 * @bug 4287595
 * @bug 4462989
 * @bug 4531511
 * @summary Test class redefinition
 *
 * @author Robert Field
 *
 * @library ..
 *
 * @run build TestScaffold VMConnection TargetListener TargetAdapter
 * @run compile -g RedefineTest.java
 * @run shell RedefineSetUp.sh
 * @run driver RedefineTest
 */
import com.sun.jdi.*;
import com.sun.jdi.event.*;
import com.sun.jdi.request.*;
import java.util.*;
import java.io.*;

    /********** target program **********/

class RedefineTarg {
    public static void show(String where){
        System.out.println("Returned: " + where);
    }

    public static void lastly(String where){
    }

    public static void main(String[] args){
        RedefineSubTarg sub = new RedefineSubTarg();
        String where = "";
        for (int i = 0; i < 5; ++i) {
            where = sub.foo(where);
            show(where);
        }
        lastly(where);
    }
}

    /********** test program **********/

public class RedefineTest extends TestScaffold {
    ReferenceType targetClass;
    static final String expected ="Boring Boring Different Boring Different ";
    int repetitionCount = 0;
    boolean beforeRedefine = true;

    RedefineTest (String args[]) {
        super(args);
    }

    public static void main(String[] args)      throws Exception {
        new RedefineTest(args).startTests();
    }

    /********** event handlers **********/

    public void methodEntered(MethodEntryEvent event) {
        Method meth = event.location().method();
        ThreadReference thread = event.thread();

        if (meth.name().equals("foo")) {
            ++repetitionCount;
            beforeRedefine = true;
            try {
                expectNonObsolete(thread);
                inspectLineNumber(event, thread.frame(0));

                doRedefine(thread);
                beforeRedefine = false;

                switch (repetitionCount) {
                case 1:
                case 5:
                    expectNonObsolete(thread);
                    inspectLineNumber(event, thread.frame(0));
                    break;
                case 2:
                case 3:
                case 4:
                    expectObsolete(thread);
                    inspectLineNumber(event, thread.frame(0));
                    break;
                }


            } catch (Exception exc) {
                failure("Test Failure: unexpected exception - " + exc);
                exc.printStackTrace();
            }
        }
    }

    public void breakpointReached(BreakpointEvent event) {
        ThreadReference thread = event.thread();
        try {
            StackFrame frame = thread.frame(0);
            LocalVariable lv = frame.visibleVariableByName("where");
            Value vWhere = frame.getValue(lv);
            String remoteWhere = ((StringReference)vWhere).value();
            println("Value of where: " + remoteWhere);
            if (!remoteWhere.equals(expected)) {
                failure("FAIL: expected result string: '" + expected +
                        "' got: '" + remoteWhere + "'");
            }
        } catch (Exception thr) {
            failure("Test Failure: unexpected exception: " + thr);
        }
    }

    /********** test assists **********/

    void expectNonObsolete(ThreadReference thread) throws Exception {
        if (isObsolete(thread)) {
            failure("FAIL: Method should NOT be obsolete");
        } else {
            println("as it should be, not obsolete");
        }
    }

    void expectObsolete(ThreadReference thread) throws Exception {
        if (isObsolete(thread)) {
            println("obsolete like it should be");
        } else {
            failure("FAIL: Method should be obsolete");
        }
    }

    void inspectLineNumber(LocatableEvent event, StackFrame frame) throws Exception {
        /*
         * For each value of repetitionCount, use the beforeRedefine
         * boolean to distinguish the time before and after the actual
         * redefinition takes place.  Line numbers are inspected both
         * before and after each redefine.
         */
        int n = -1;
        int expectedLine = -1;
        switch (repetitionCount) {
        case 1:
            expectedLine = 4;
            break;
        case 2:
            expectedLine = beforeRedefine ? 4:21;
            break;
        case 3:
            expectedLine = beforeRedefine ? 21:4;
            break;
        case 4:
            expectedLine = beforeRedefine ? 4:21;
            break;
        case 5:
            /* The class won't be redefined on this iteration (look
             * for a java.lang.UnsupportedOperationException instead)
             * so expected line stays the same as last successful
             * redefine.
             */
            expectedLine = 21;
            break;
        }
        Method method = event.location().method();
        if (frame.location().method().isObsolete()) {
            /*
             * Then skip. Obsolete methods are not interesting to
             * inspect.
             */
            println("inspectLineNumber skipping obsolete method " + method.name());
        } else {
            n = method.location().lineNumber();
            int m = frame.location().lineNumber();
            if ((n != expectedLine) || (n != m)) {
                failure("Test Failure: line number disagreement: " +
                        n + " (event) versus " + m + " (frame) versus " + expectedLine +
                        " (expected)");
            } else {
                println("inspectLineNumber in method " + method.name() + " at line " + n);
            }
        }
    }

    boolean isObsolete(ThreadReference thread) throws Exception {
        StackFrame frame = thread.frame(0);
        Method meth = frame.location().method();
        return meth.isObsolete();
    }

    void doRedefine(ThreadReference thread) throws Exception {
        Exception receivedException = null;
        String fileName = "notThis";

        switch (repetitionCount) {
        case 1:
            fileName = "RedefineSubTarg.class";
            break;
        case 2:
            fileName = "Different_RedefineSubTarg.class";
            break;
        case 3:
            fileName = "RedefineSubTarg.class";
            break;
        case 4:
            fileName = "Different_RedefineSubTarg.class";
            break;
        case 5:
            fileName = "SchemaChange_RedefineSubTarg.class";
            break;
        }
        File phyl = new File(fileName);
        byte[] bytes = new byte[(int)phyl.length()];
        InputStream in = new FileInputStream(phyl);
        in.read(bytes);
        in.close();

        Map map = new HashMap();
        map.put(findReferenceType("RedefineSubTarg"), bytes);

        println(System.getProperty("line.separator") + "Iteration # " + repetitionCount +
                " ------ Redefine as: " + fileName);
        try {
            vm().redefineClasses(map);
        } catch (Exception thr) {
            receivedException = thr;
        }
        switch (repetitionCount) {
        case 5:
            if (receivedException == null) {
                failure("FAIL: no exception; expected: UnsupportedOperationException");
            } else if (receivedException instanceof UnsupportedOperationException) {
                println("Received expected exception: " + receivedException);
            } else {
                failure("FAIL: got exception: " + receivedException +
                        ", expected: UnsupportedOperationException");
            }
            break;
        default:
            if (receivedException != null) {
                failure("FAIL: unexpected exception: " +
                        receivedException);
            }
            break;
        }
        return;
    }

    /********** test core **********/

    protected void runTests() throws Exception {

        BreakpointEvent bpe = startToMain("RedefineTarg");
        targetClass = bpe.location().declaringType();
        EventRequestManager erm = vm().eventRequestManager();

        /*
         * Method entry in sub targ
         */
        MethodEntryRequest mee = erm.createMethodEntryRequest();
        mee.addClassFilter("RedefineSubTarg");
        mee.enable();

        /*
         * BP at end to get value
         */
        List lastlys = targetClass.methodsByName("lastly");
        if (lastlys.size() != 1) {
            throw new Exception ("TestFailure: Expected one 'lastly' method, found: " +
                                 lastlys);
        }
        Location loc = ((Method)(lastlys.get(0))).location();
        EventRequest req = erm.createBreakpointRequest(loc);
        req.enable();

        // Allow application to complete and shut down
        listenUntilVMDisconnect();

        /*
         * deal with results of test
         * if anything has called failure("foo") testFailed will be true
         */
        if (!testFailed) {
            println("RedefineTest: passed");
        } else {
            throw new Exception("RedefineTest: failed");
        }
    }
}