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