• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
18 
19 /**
20  * @author Anatoly F. Bondarenko
21  */
22 
23 /**
24  * Created on 30.03.2005
25  */
26 package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;
27 
28 
29 
30 import java.io.*;
31 import java.util.Base64;
32 
33 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
34 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
35 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
36 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
37 import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
38 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
39 
40 /**
41  * JDWP Unit test for VirtualMachine.RedefineClasses command.
42  */
43 public class RedefineClassesTest extends JDWPSyncTestCase {
44 
45     static final int testStatusPassed = 0;
46     static final int testStatusFailed = -1;
47     static final String thisCommandName = "VirtualMachine::RedefineClasses command";
48     static final String checkedClassSignature =
49             getClassSignature(RedefineClassesDebuggee.class).replace("RedefineClassesDebuggee",
50                     "RedefineClass_Debuggee");
51     static final String byteCodeToRedefineFile = "RedefineByteCode_Debuggee001";
52     private static String thisTestName;
53 
54     @Override
getDebuggeeClassName()55     protected String getDebuggeeClassName() {
56         return RedefineClassesDebuggee.class.getName();
57     }
58 
findNewClassByteCode()59     File findNewClassByteCode() {
60         File foundFile = null;
61         String nameSeparator = File.separator;
62         String pathSeparator = File.pathSeparator;
63         String byteCodeFileNameSuffix = "org" + nameSeparator + "apache" + nameSeparator
64             + "harmony" + nameSeparator + "jpda" + nameSeparator + "tests" + nameSeparator
65             + "jdwp" + nameSeparator + "VirtualMachine"
66             + nameSeparator + byteCodeToRedefineFile;
67         String byteCodeFileName = null;
68         String classPaths = System.getProperty("java.class.path");
69         int begPos = 0;
70         int classPathsLength = classPaths.length();
71 
72         for (int i = 0; i <= classPathsLength; i++) {
73             if ( i == classPathsLength ) {
74                 if ( begPos == i ) {
75                  break;
76                 }
77             } else {
78                 if ( ! pathSeparator.equals(classPaths.substring(i,i+1))) {
79                     continue;
80                 }
81                 if ( begPos == i ) {
82                     begPos++;
83                     continue;
84                 }
85             }
86             byteCodeFileName = classPaths.substring(begPos,i);
87             if ( ! nameSeparator.equals(classPaths.substring(i-1,i)) ) {
88                 byteCodeFileName = byteCodeFileName + nameSeparator;
89             }
90             byteCodeFileName = byteCodeFileName + byteCodeFileNameSuffix;
91             foundFile = new File(byteCodeFileName);
92             if ( foundFile.exists() ) {
93                 break;
94             }
95             foundFile = null;
96             begPos = i+1;
97         }
98        return foundFile;
99     }
100 
getNewClassBytesClass()101     private byte[] getNewClassBytesClass() {
102         File newClassByteCodeFile = findNewClassByteCode();
103         if ( newClassByteCodeFile == null ) {
104             logWriter.println
105             ("===> Can NOT find out byte code file for redefine:");
106             logWriter.println
107             ("===> File name = " + byteCodeToRedefineFile);
108             logWriter.println
109             ("===> Test can NOT be run!");
110             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
111             return null;
112         }
113 
114         logWriter.println("=> File name with new class byte code to redefine = " +
115                           byteCodeToRedefineFile);
116         FileInputStream newClassByteCodeFileInputStream = null;
117         try {
118             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
119         } catch (Throwable thrown) {
120             logWriter.println("===> Can NOT create FileInputStream for byte code file:");
121             logWriter.println("===> File name = " + byteCodeToRedefineFile);
122             logWriter.println("===> Exception is thrown: " + thrown);
123             logWriter.println("===> Test can NOT be run!");
124             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
125             return null;
126         }
127         int newClassByteCodeSize = 0;
128         try {
129             newClassByteCodeSize = (int)newClassByteCodeFileInputStream.skip(Long.MAX_VALUE);
130         } catch (Throwable thrown) {
131             logWriter.println("===> Can NOT do FileInputStream.skip() to the end of file:");
132             logWriter.println("===> File name = " + byteCodeToRedefineFile);
133             logWriter.println("===> Exception is thrown: " + thrown);
134             logWriter.println("===> Test can NOT be run!");
135             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
136             return null;
137         }
138         logWriter.println("=> newClassByteCodeSize = " + newClassByteCodeSize);
139         try {
140             newClassByteCodeFileInputStream.close();
141         } catch (Throwable thrown) {
142             logWriter.println
143             ("===> WARNING: Can NOT close FileInputStream for byte code file:");
144             logWriter.println("===> File name = " + byteCodeToRedefineFile);
145             logWriter.println("===> Exception is thrown: " + thrown);
146         }
147         newClassByteCodeFileInputStream = null;
148 
149         try {
150             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
151         } catch (Throwable thrown) {
152             logWriter.println
153             ("===> Can NOT re-create FileInputStream for byte code file:");
154             logWriter.println("===> File name = " + byteCodeToRedefineFile);
155             logWriter.println("===> Exception is thrown: " + thrown);
156             logWriter.println("===> Test can NOT be run!");
157             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
158             return null;
159         }
160         byte[] res = new byte[newClassByteCodeSize];
161         int totalRead = 0;
162         try {
163             totalRead = newClassByteCodeFileInputStream.read(res);
164         } catch (Throwable thrown) {
165             logWriter.println("===> Can NOT read current byte code file:");
166             logWriter.println("===> File name = " + byteCodeToRedefineFile);
167             logWriter.println("===> Exception is thrown: " + thrown);
168             logWriter.println("===> Test can NOT be run!");
169             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
170             return null;
171         }
172         if ( totalRead != newClassByteCodeSize) { // EOF is reached
173             logWriter.println("===> Could not read full bytecode file:");
174             logWriter.println("===> File name = " + byteCodeToRedefineFile);
175             logWriter.println("===> expected to read: " + newClassByteCodeSize);
176             logWriter.println("===> actually read: " + totalRead);
177             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
178             return null;
179         }
180         return res;
181     }
182 
getNewClassBytesDex()183     private byte[] getNewClassBytesDex() {
184       // This is a base64 dex-file for the following class
185       // package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;
186       // class RedefineClass_Debuggee {
187       //   static String testMethod() {
188       //     return "testMethod_Result_After_Redefine";
189       //   }
190       // }
191       logWriter.println("===> Redefining class " + checkedClassSignature + " to:");
192       logWriter.println("====> package org.apache.harmony.jpda.tests.jdwp.VirtualMachine;");
193       logWriter.println("====> class RedefineClass_Debuggee {");
194       logWriter.println("====>   static String testMethod() {");
195       logWriter.println("====>     return \"testMethod_Result_After_Redefine\";");
196       logWriter.println("====>   }");
197       logWriter.println("====> }");
198       return Base64.getDecoder().decode(
199           "ZGV4CjAzNQAVa34RK7cHNNGCveP4LGffC0tLZFeb7KuUAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAJ" +
200           "AAAAcAAAAAQAAACUAAAAAgAAAKQAAAAAAAAAAAAAAAMAAAC8AAAAAQAAANQAAACgAQAA9AAAACQB" +
201           "AAAsAQAALwEAAEMBAABXAQAAowEAAMABAADDAQAAzwEAAAIAAAADAAAABAAAAAYAAAABAAAAAQAA" +
202           "AAAAAAAGAAAAAwAAAAAAAAAAAAEAAAAAAAIAAQAAAAAAAgAAAAcAAAACAAAAAAAAAAAAAAAAAAAA" +
203           "BQAAAAAAAAD7AQAAAAAAAAEAAQABAAAA8QEAAAQAAABwEAAAAAAOAAEAAAAAAAAA9gEAAAMAAAAa" +
204           "AAgAEQAAAAY8aW5pdD4AAUwAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7" +
205           "AEpMb3JnL2FwYWNoZS9oYXJtb255L2pwZGEvdGVzdHMvamR3cC9WaXJ0dWFsTWFjaGluZS9SZWRl" +
206           "ZmluZUNsYXNzX0RlYnVnZ2VlOwAbUmVkZWZpbmVDbGFzc19EZWJ1Z2dlZS5qYXZhAAFWAAp0ZXN0" +
207           "TWV0aG9kACB0ZXN0TWV0aG9kX1Jlc3VsdF9BZnRlcl9SZWRlZmluZQADAAcOAAYABw4AAAACAAGA" +
208           "gAT0AQEIjAIAAAALAAAAAAAAAAEAAAAAAAAAAQAAAAkAAABwAAAAAgAAAAQAAACUAAAAAwAAAAIA" +
209           "AACkAAAABQAAAAMAAAC8AAAABgAAAAEAAADUAAAAASAAAAIAAAD0AAAAAiAAAAkAAAAkAQAAAyAA" +
210           "AAIAAADxAQAAACAAAAEAAAD7AQAAABAAAAEAAAAMAgAA");
211     }
212 
getNewClassBytes()213     private byte[] getNewClassBytes() {
214       if (debuggeeWrapper.vmMirror.canRedefineClasses()) {
215         return getNewClassBytesClass();
216       } else {
217         return getNewClassBytesDex();
218       }
219     }
220 
221     /**
222      * This testcase exercises VirtualMachine.RedefineClasses command.
223      * <BR>At first the test starts RedefineClassesDebuggee which invokes
224      * the 'testMethod()' of RedefineClass_Debuggee class and prints the string
225      * returned by this method before redefining.
226      * <BR> Then the test performs VirtualMachine.RedefineClasses command
227      * for RedefineClass_Debuggee class - the 'testMethod()' is redefined.
228      * Next, the debuggee invokes the 'testMethod()' again and it is expected
229      * that the method returns another resulting string.
230      * The test checks that this resulting string is expected string.
231      */
testRedefineClasses001()232     public void testRedefineClasses001() {
233         thisTestName = "testClassObject001";
234 
235         //check capability, relevant for this test
236         logWriter.println("=> Check capability: canRedefineClasses");
237         if (!debuggeeWrapper.vmMirror.canRedefineClasses() &&
238             !debuggeeWrapper.vmMirror.canRedefineDexClasses()) {
239             logWriter.println("##WARNING: this VM doesn't possess capability: canRedefineClasses");
240             return;
241         }
242 
243         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
244         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
245         logWriter.println
246         ("\n=> Send VirtualMachine::ClassesBySignature command and and get checked class referenceTypeID...");
247         logWriter.println("=> checkedClassSignature = " + checkedClassSignature);
248         CommandPacket classesBySignatureCommand = new CommandPacket(
249             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
250             JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand);
251         classesBySignatureCommand.setNextValueAsString(checkedClassSignature);
252 
253         ReplyPacket classesBySignatureReply = debuggeeWrapper.vmMirror.performCommand(classesBySignatureCommand);
254         classesBySignatureCommand = null;
255 
256         checkReplyPacket(classesBySignatureReply, "VirtualMachine::ClassesBySignature command");
257 
258         int returnedClassesNumber = classesBySignatureReply.getNextValueAsInt();
259         logWriter.println("=> ReturnedClassesNumber = " + returnedClassesNumber);
260         if ( returnedClassesNumber != 1 ) {
261             // Number of returned reference types - is NOt used here
262             printErrorAndFail("Unexpected number of classes is returned: " +
263                     returnedClassesNumber +
264                     ", Expected number = 1");
265         }
266 
267         classesBySignatureReply.getNextValueAsByte();
268         // refTypeTag of class - is NOt used here
269 
270         long refTypeID = classesBySignatureReply.getNextValueAsReferenceTypeID();
271         classesBySignatureReply = null;
272 
273         logWriter.println("=> Checked class referenceTypeID = " + refTypeID);
274 
275         logWriter.println("\n=> Preparing info for " + thisCommandName);
276         byte[] newClass = getNewClassBytes();
277         if (newClass == null) {
278           // Wasn't able to get new file. Just continue and return.
279           synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
280           return;
281         }
282 
283         CommandPacket checkedCommand = new CommandPacket(
284             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
285             JDWPCommands.VirtualMachineCommandSet.RedefineClassesCommand);
286         checkedCommand.setNextValueAsInt(1); // number of classes to redefine
287         checkedCommand.setNextValueAsReferenceTypeID(refTypeID);
288         checkedCommand.setNextValueAsInt(newClass.length);
289         for (byte currentByte: newClass) {
290             checkedCommand.setNextValueAsByte(currentByte);
291         }
292         logWriter.println("=> Number of written bytes as new class file = " + newClass.length);
293         logWriter.println("\n=> Send " + thisCommandName + " and check reply...");
294 
295         ReplyPacket checkedReply = debuggeeWrapper.vmMirror.performCommand(checkedCommand);
296         checkedCommand = null;
297         int[] expectedErrors = {
298             JDWPConstants.Error.NOT_IMPLEMENTED,
299         };
300         short errorCode = checkedReply.getErrorCode();
301         if ( errorCode != JDWPConstants.Error.NONE ) {
302             if ( errorCode != JDWPConstants.Error.UNSUPPORTED_VERSION ) {
303                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
304                 printErrorAndFail(
305                     "## WARNING: A class file for redefine has a version number not supported by this VM" +
306                     "\n## It should be re-created");
307             }
308             boolean expectedErr = false;
309             for (int i=0; i < expectedErrors.length; i++) {
310                 if ( errorCode == expectedErrors[i] ) {
311                     expectedErr = true;
312                     break;
313                 }
314             }
315             if ( expectedErr ) {
316                 logWriter.println("=> " +  thisCommandName
317                         + " returns expected ERROR = " + errorCode
318                         + "(" + JDWPConstants.Error.getName(errorCode) + ")");
319                 logWriter.println
320                     ("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
321                 return;
322             } else {
323                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
324                 printErrorAndFail(thisCommandName
325                     + " returns unexpected ERROR = " + errorCode
326                     + "(" + JDWPConstants.Error.getName(errorCode) + ")");
327             }
328         }
329         logWriter.println("=> " +  thisCommandName + " returns reply without any error");
330 
331         assertAllDataRead(checkedReply);
332 
333         logWriter.println("\n=> Send Debuggee signal to continue and execute redefined testMethod");
334         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
335 
336         String testMethodResult = synchronizer.receiveMessage();
337         logWriter.println("=> Redefined testMethod result = \"" + testMethodResult + "\"");
338         if ( testMethodResult.equals("testMethod_Result_After_Redefine") ) {
339             logWriter.println("=> OK - it is expected result");
340         } else {
341             printErrorAndFail("it is NOT expected result" +
342                     "\n Expected result = \"testMethod_Result_After_Redefine\"");
343         }
344 
345         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
346     }
347 }
348