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 
32 import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket;
33 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands;
34 import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants;
35 import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket;
36 import org.apache.harmony.jpda.tests.jdwp.share.JDWPSyncTestCase;
37 import org.apache.harmony.jpda.tests.share.JPDADebuggeeSynchronizer;
38 
39 /**
40  * JDWP Unit test for VirtualMachine.RedefineClasses command.
41  */
42 public class RedefineClassesTest extends JDWPSyncTestCase {
43 
44     static final int testStatusPassed = 0;
45     static final int testStatusFailed = -1;
46     static final String thisCommandName = "VirtualMachine::RedefineClasses command";
47     static final String checkedClassSignature
48         = "Lorg/apache/harmony/jpda/tests/jdwp/VirtualMachine/RedefineClass_Debuggee;";
49     static final String byteCodeToRedefineFile = "RedefineByteCode_Debuggee001";
50 
getDebuggeeClassName()51     protected String getDebuggeeClassName() {
52         return "org.apache.harmony.jpda.tests.jdwp.VirtualMachine.RedefineClassesDebuggee";
53     }
54 
findNewClassByteCode()55     File findNewClassByteCode() {
56         File foundFile = null;
57         String nameSeparator = File.separator;
58         String pathSeparator = File.pathSeparator;
59         String byteCodeFileNameSuffix = "org" + nameSeparator + "apache" + nameSeparator
60             + "harmony" + nameSeparator + "jpda" + nameSeparator + "tests" + nameSeparator
61             + "jdwp" + nameSeparator + "VirtualMachine"
62             + nameSeparator + byteCodeToRedefineFile;
63         String byteCodeFileName = null;
64         String classPaths = System.getProperty("java.class.path");
65         int begPos = 0;
66         int classPathsLength = classPaths.length();;
67 
68         for (int i = 0; i <= classPathsLength; i++) {
69             if ( i == classPathsLength ) {
70                 if ( begPos == i ) {
71                  break;
72                 }
73             } else {
74                 if ( ! pathSeparator.equals(classPaths.substring(i,i+1))) {
75                     continue;
76                 }
77                 if ( begPos == i ) {
78                     begPos++;
79                     continue;
80                 }
81             }
82             byteCodeFileName = classPaths.substring(begPos,i);
83             if ( ! nameSeparator.equals(classPaths.substring(i-1,i)) ) {
84                 byteCodeFileName = byteCodeFileName + nameSeparator;
85             }
86             byteCodeFileName = byteCodeFileName + byteCodeFileNameSuffix;
87             foundFile = new File(byteCodeFileName);
88             if ( foundFile.exists() ) {
89                 break;
90             }
91             foundFile = null;
92             begPos = i+1;
93         }
94        return foundFile;
95     }
96 
97     /**
98      * This testcase exercises VirtualMachine.RedefineClasses command.
99      * <BR>At first the test starts RedefineClassesDebuggee which invokes
100      * the 'testMethod()' of RedefineClass_Debuggee class and prints the string
101      * returned by this method before redefining.
102      * <BR> Then the test performs VirtualMachine.RedefineClasses command
103      * for RedefineClass_Debuggee class - the 'testMethod()' is redefined.
104      * Next, the debuggee invokes the 'testMethod()' again and it is expected
105      * that the method returns another resulting string.
106      * The test checks that this resulting string is expected string.
107      */
testRedefineClasses001()108     public void testRedefineClasses001() {
109         String thisTestName = "testClassObject001";
110 
111         //check capability, relevant for this test
112         logWriter.println("=> Check capability: canRedefineClasses");
113         debuggeeWrapper.vmMirror.capabilities();
114         boolean isCapability = debuggeeWrapper.vmMirror.targetVMCapabilities.canRedefineClasses;
115         if (!isCapability) {
116             logWriter.println("##WARNING: this VM doesn't possess capability: canRedefineClasses");
117             return;
118         }
119 
120         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
121         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
122         File newClassByteCodeFile = findNewClassByteCode();
123         if ( newClassByteCodeFile == null ) {
124             logWriter.println
125             ("===> Can NOT find out byte code file for redefine:");
126             logWriter.println
127             ("===> File name = " + byteCodeToRedefineFile);
128             logWriter.println
129             ("===> Test can NOT be run!");
130             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
131             return;
132         }
133 
134         logWriter.println
135         ("\n=> Send VirtualMachine::ClassesBySignature command and and get checked class referenceTypeID...");
136         logWriter.println("=> checkedClassSignature = " + checkedClassSignature);
137         CommandPacket classesBySignatureCommand = new CommandPacket(
138             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
139             JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand);
140         classesBySignatureCommand.setNextValueAsString(checkedClassSignature);
141 
142         ReplyPacket classesBySignatureReply = debuggeeWrapper.vmMirror.performCommand(classesBySignatureCommand);
143         classesBySignatureCommand = null;
144 
145         checkReplyPacket(classesBySignatureReply, "VirtualMachine::ClassesBySignature command");
146 
147         int returnedClassesNumber = classesBySignatureReply.getNextValueAsInt();
148         logWriter.println("=> ReturnedClassesNumber = " + returnedClassesNumber);
149         if ( returnedClassesNumber != 1 ) {
150             // Number of returned reference types - is NOt used here
151             printErrorAndFail("Unexpected number of classes is returned: " +
152                     returnedClassesNumber +
153                     ", Expected number = 1");
154         }
155 
156         classesBySignatureReply.getNextValueAsByte();
157         // refTypeTag of class - is NOt used here
158 
159         long refTypeID = classesBySignatureReply.getNextValueAsReferenceTypeID();
160         classesBySignatureReply = null;
161 
162         logWriter.println("=> Checked class referenceTypeID = " + refTypeID);
163 
164         logWriter.println("\n=> Preparing info for " + thisCommandName);
165         logWriter.println
166         ("=> File name with new class byte code to redefine = " + byteCodeToRedefineFile);
167         FileInputStream newClassByteCodeFileInputStream = null;
168         try {
169             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
170         } catch (Throwable thrown) {
171             logWriter.println
172             ("===> Can NOT create FileInputStream for byte code file:");
173             logWriter.println("===> File name = " + byteCodeToRedefineFile);
174             logWriter.println("===> Exception is thrown: " + thrown);
175             logWriter.println("===> Test can NOT be run!");
176             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
177             return;
178         }
179         int newClassByteCodeSize = 0;
180         try {
181             newClassByteCodeSize = (int)newClassByteCodeFileInputStream.skip(Long.MAX_VALUE);
182         } catch (Throwable thrown) {
183             logWriter.println
184             ("===> Can NOT do FileInputStream.skip() to the end of file:");
185             logWriter.println("===> File name = " + byteCodeToRedefineFile);
186             logWriter.println("===> Exception is thrown: " + thrown);
187             logWriter.println("===> Test can NOT be run!");
188             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
189             return;
190         }
191         logWriter.println("=> newClassByteCodeSize = " + newClassByteCodeSize);
192         try {
193             newClassByteCodeFileInputStream.close();
194         } catch (Throwable thrown) {
195             logWriter.println
196             ("===> WARNING: Can NOT close FileInputStream for byte code file:");
197             logWriter.println("===> File name = " + byteCodeToRedefineFile);
198             logWriter.println("===> Exception is thrown: " + thrown);
199         }
200         newClassByteCodeFileInputStream = null;
201 
202         try {
203             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
204         } catch (Throwable thrown) {
205             logWriter.println
206             ("===> Can NOT re-create FileInputStream for byte code file:");
207             logWriter.println("===> File name = " + byteCodeToRedefineFile);
208             logWriter.println("===> Exception is thrown: " + thrown);
209             logWriter.println("===> Test can NOT be run!");
210             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
211             return;
212         }
213 
214         CommandPacket checkedCommand = new CommandPacket(
215             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
216             JDWPCommands.VirtualMachineCommandSet.RedefineClassesCommand);
217         checkedCommand.setNextValueAsInt(1); // number of classes to redefine
218         checkedCommand.setNextValueAsReferenceTypeID(refTypeID);
219         checkedCommand.setNextValueAsInt(newClassByteCodeSize);
220         int writtenBytes = 0;
221         int currentByte = 0;
222         while ( true ) {
223             try {
224                 currentByte = newClassByteCodeFileInputStream.read();
225             } catch (Throwable thrown) {
226                 logWriter.println
227                 ("===> Can NOT read current byte from byte code file:");
228                 logWriter.println("===> File name = " + byteCodeToRedefineFile);
229                 logWriter.println("===> Byte number = " + writtenBytes);
230                 logWriter.println("===> Exception is thrown: " + thrown);
231                 logWriter.println("===> Test can NOT be run!");
232                 logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
233                 return;
234             }
235             if ( currentByte == -1 ) { // EOF is reached
236                break;
237             }
238             checkedCommand.setNextValueAsByte((byte)currentByte);
239             writtenBytes++;
240         }
241         logWriter.println("=> Number of written bytes as new class file = " + writtenBytes);
242         if ( newClassByteCodeSize != writtenBytes ) {
243             logWriter.println("===> WARNING: Number of written bytes != newClassByteCodeSize");
244             logWriter.println("===> Test can NOT be run!");
245             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
246             return;
247         }
248 
249         logWriter.println("\n=> Send " + thisCommandName + " and check reply...");
250 
251         ReplyPacket checkedReply = debuggeeWrapper.vmMirror.performCommand(checkedCommand);
252         checkedCommand = null;
253         int[] expectedErrors = {
254             JDWPConstants.Error.NOT_IMPLEMENTED,
255         };
256         short errorCode = checkedReply.getErrorCode();
257         if ( errorCode != JDWPConstants.Error.NONE ) {
258             if ( errorCode != JDWPConstants.Error.UNSUPPORTED_VERSION ) {
259                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
260                 printErrorAndFail(
261                     "## WARNING: A class file for redefine has a version number not supported by this VM" +
262                     "\n## File name with byte code = " + byteCodeToRedefineFile +
263                     "\n## It should be re-created");
264             }
265             boolean expectedErr = false;
266             for (int i=0; i < expectedErrors.length; i++) {
267                 if ( errorCode == expectedErrors[i] ) {
268                     expectedErr = true;
269                     break;
270                 }
271             }
272             if ( expectedErr ) {
273                 logWriter.println("=> " +  thisCommandName
274                         + " returns expected ERROR = " + errorCode
275                         + "(" + JDWPConstants.Error.getName(errorCode) + ")");
276                 logWriter.println
277                     ("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
278                 return;
279             } else {
280                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
281                 printErrorAndFail(thisCommandName
282                     + " returns unexpected ERROR = " + errorCode
283                     + "(" + JDWPConstants.Error.getName(errorCode) + ")");
284             }
285         }
286         logWriter.println("=> " +  thisCommandName + " returns reply without any error");
287 
288         assertAllDataRead(checkedReply);
289 
290         logWriter.println("\n=> Send Debuggee signal to continue and execute redefined testMethod");
291         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
292 
293         String testMethodResult = synchronizer.receiveMessage();
294         logWriter.println("=> Redefined testMethod result = \"" + testMethodResult + "\"");
295         if ( testMethodResult.equals("testMethod_Result_After_Redefine") ) {
296             logWriter.println("=> OK - it is expected result");
297         } else {
298             printErrorAndFail("it is NOT expected result" +
299                     "\n Expected result = \"testMethod_Result_After_Redefine\"");
300         }
301 
302         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
303     }
304 }
305