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         if (!debuggeeWrapper.vmMirror.canRedefineClasses()) {
114             logWriter.println("##WARNING: this VM doesn't possess capability: canRedefineClasses");
115             return;
116         }
117 
118         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": START...");
119         synchronizer.receiveMessage(JPDADebuggeeSynchronizer.SGNL_READY);
120         File newClassByteCodeFile = findNewClassByteCode();
121         if ( newClassByteCodeFile == null ) {
122             logWriter.println
123             ("===> Can NOT find out byte code file for redefine:");
124             logWriter.println
125             ("===> File name = " + byteCodeToRedefineFile);
126             logWriter.println
127             ("===> Test can NOT be run!");
128             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
129             return;
130         }
131 
132         logWriter.println
133         ("\n=> Send VirtualMachine::ClassesBySignature command and and get checked class referenceTypeID...");
134         logWriter.println("=> checkedClassSignature = " + checkedClassSignature);
135         CommandPacket classesBySignatureCommand = new CommandPacket(
136             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
137             JDWPCommands.VirtualMachineCommandSet.ClassesBySignatureCommand);
138         classesBySignatureCommand.setNextValueAsString(checkedClassSignature);
139 
140         ReplyPacket classesBySignatureReply = debuggeeWrapper.vmMirror.performCommand(classesBySignatureCommand);
141         classesBySignatureCommand = null;
142 
143         checkReplyPacket(classesBySignatureReply, "VirtualMachine::ClassesBySignature command");
144 
145         int returnedClassesNumber = classesBySignatureReply.getNextValueAsInt();
146         logWriter.println("=> ReturnedClassesNumber = " + returnedClassesNumber);
147         if ( returnedClassesNumber != 1 ) {
148             // Number of returned reference types - is NOt used here
149             printErrorAndFail("Unexpected number of classes is returned: " +
150                     returnedClassesNumber +
151                     ", Expected number = 1");
152         }
153 
154         classesBySignatureReply.getNextValueAsByte();
155         // refTypeTag of class - is NOt used here
156 
157         long refTypeID = classesBySignatureReply.getNextValueAsReferenceTypeID();
158         classesBySignatureReply = null;
159 
160         logWriter.println("=> Checked class referenceTypeID = " + refTypeID);
161 
162         logWriter.println("\n=> Preparing info for " + thisCommandName);
163         logWriter.println
164         ("=> File name with new class byte code to redefine = " + byteCodeToRedefineFile);
165         FileInputStream newClassByteCodeFileInputStream = null;
166         try {
167             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
168         } catch (Throwable thrown) {
169             logWriter.println
170             ("===> Can NOT create FileInputStream for byte code file:");
171             logWriter.println("===> File name = " + byteCodeToRedefineFile);
172             logWriter.println("===> Exception is thrown: " + thrown);
173             logWriter.println("===> Test can NOT be run!");
174             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
175             return;
176         }
177         int newClassByteCodeSize = 0;
178         try {
179             newClassByteCodeSize = (int)newClassByteCodeFileInputStream.skip(Long.MAX_VALUE);
180         } catch (Throwable thrown) {
181             logWriter.println
182             ("===> Can NOT do FileInputStream.skip() to the end of file:");
183             logWriter.println("===> File name = " + byteCodeToRedefineFile);
184             logWriter.println("===> Exception is thrown: " + thrown);
185             logWriter.println("===> Test can NOT be run!");
186             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
187             return;
188         }
189         logWriter.println("=> newClassByteCodeSize = " + newClassByteCodeSize);
190         try {
191             newClassByteCodeFileInputStream.close();
192         } catch (Throwable thrown) {
193             logWriter.println
194             ("===> WARNING: Can NOT close FileInputStream for byte code file:");
195             logWriter.println("===> File name = " + byteCodeToRedefineFile);
196             logWriter.println("===> Exception is thrown: " + thrown);
197         }
198         newClassByteCodeFileInputStream = null;
199 
200         try {
201             newClassByteCodeFileInputStream = new FileInputStream(newClassByteCodeFile);
202         } catch (Throwable thrown) {
203             logWriter.println
204             ("===> Can NOT re-create FileInputStream for byte code file:");
205             logWriter.println("===> File name = " + byteCodeToRedefineFile);
206             logWriter.println("===> Exception is thrown: " + thrown);
207             logWriter.println("===> Test can NOT be run!");
208             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
209             return;
210         }
211 
212         CommandPacket checkedCommand = new CommandPacket(
213             JDWPCommands.VirtualMachineCommandSet.CommandSetID,
214             JDWPCommands.VirtualMachineCommandSet.RedefineClassesCommand);
215         checkedCommand.setNextValueAsInt(1); // number of classes to redefine
216         checkedCommand.setNextValueAsReferenceTypeID(refTypeID);
217         checkedCommand.setNextValueAsInt(newClassByteCodeSize);
218         int writtenBytes = 0;
219         int currentByte = 0;
220         while ( true ) {
221             try {
222                 currentByte = newClassByteCodeFileInputStream.read();
223             } catch (Throwable thrown) {
224                 logWriter.println
225                 ("===> Can NOT read current byte from byte code file:");
226                 logWriter.println("===> File name = " + byteCodeToRedefineFile);
227                 logWriter.println("===> Byte number = " + writtenBytes);
228                 logWriter.println("===> Exception is thrown: " + thrown);
229                 logWriter.println("===> Test can NOT be run!");
230                 logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
231                 return;
232             }
233             if ( currentByte == -1 ) { // EOF is reached
234                break;
235             }
236             checkedCommand.setNextValueAsByte((byte)currentByte);
237             writtenBytes++;
238         }
239         logWriter.println("=> Number of written bytes as new class file = " + writtenBytes);
240         if ( newClassByteCodeSize != writtenBytes ) {
241             logWriter.println("===> WARNING: Number of written bytes != newClassByteCodeSize");
242             logWriter.println("===> Test can NOT be run!");
243             logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
244             return;
245         }
246 
247         logWriter.println("\n=> Send " + thisCommandName + " and check reply...");
248 
249         ReplyPacket checkedReply = debuggeeWrapper.vmMirror.performCommand(checkedCommand);
250         checkedCommand = null;
251         int[] expectedErrors = {
252             JDWPConstants.Error.NOT_IMPLEMENTED,
253         };
254         short errorCode = checkedReply.getErrorCode();
255         if ( errorCode != JDWPConstants.Error.NONE ) {
256             if ( errorCode != JDWPConstants.Error.UNSUPPORTED_VERSION ) {
257                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
258                 printErrorAndFail(
259                     "## WARNING: A class file for redefine has a version number not supported by this VM" +
260                     "\n## File name with byte code = " + byteCodeToRedefineFile +
261                     "\n## It should be re-created");
262             }
263             boolean expectedErr = false;
264             for (int i=0; i < expectedErrors.length; i++) {
265                 if ( errorCode == expectedErrors[i] ) {
266                     expectedErr = true;
267                     break;
268                 }
269             }
270             if ( expectedErr ) {
271                 logWriter.println("=> " +  thisCommandName
272                         + " returns expected ERROR = " + errorCode
273                         + "(" + JDWPConstants.Error.getName(errorCode) + ")");
274                 logWriter.println
275                     ("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
276                 return;
277             } else {
278                 finalSyncMessage = JPDADebuggeeSynchronizer.SGNL_CONTINUE;
279                 printErrorAndFail(thisCommandName
280                     + " returns unexpected ERROR = " + errorCode
281                     + "(" + JDWPConstants.Error.getName(errorCode) + ")");
282             }
283         }
284         logWriter.println("=> " +  thisCommandName + " returns reply without any error");
285 
286         assertAllDataRead(checkedReply);
287 
288         logWriter.println("\n=> Send Debuggee signal to continue and execute redefined testMethod");
289         synchronizer.sendMessage(JPDADebuggeeSynchronizer.SGNL_CONTINUE);
290 
291         String testMethodResult = synchronizer.receiveMessage();
292         logWriter.println("=> Redefined testMethod result = \"" + testMethodResult + "\"");
293         if ( testMethodResult.equals("testMethod_Result_After_Redefine") ) {
294             logWriter.println("=> OK - it is expected result");
295         } else {
296             printErrorAndFail("it is NOT expected result" +
297                     "\n Expected result = \"testMethod_Result_After_Redefine\"");
298         }
299 
300         logWriter.println("==> " + thisTestName + " for " + thisCommandName + ": FINISH");
301     }
302 }
303