1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @summary Unit test for libjimage JIMAGE_Open/Read/Close 27 * @modules java.base/jdk.internal.jimage 28 */ 29 30import java.io.File; 31import java.io.FileWriter; 32import java.io.IOException; 33import java.nio.ByteBuffer; 34import java.nio.ByteOrder; 35import java.nio.file.Files; 36import java.nio.file.Path; 37import java.nio.file.Paths; 38import java.util.Arrays; 39 40import jdk.internal.jimage.BasicImageReader; 41import jdk.internal.jimage.ImageReader; 42import jdk.internal.jimage.ImageLocation; 43 44import org.testng.annotations.DataProvider; 45import org.testng.annotations.Optional; 46import org.testng.annotations.Parameters; 47import org.testng.annotations.Test; 48import org.testng.Assert; 49import org.testng.TestNG; 50 51@Test 52public class JImageReadTest { 53 54 static String javaHome = System.getProperty("java.home"); 55 static Path imageFile = Paths.get(javaHome, "lib", "modules"); 56 57 @DataProvider(name="classes") 58 static Object[][] loadClasses() { 59 return new Object[][] { 60 {"java.base", "java/lang/String.class"}, 61 {"java.base", "java/lang/Object.class"}, 62 {"java.base", "sun/reflect/generics/tree/TypeArgument.class"}, 63 {"java.base", "sun/net/www/content-types.properties"}, 64 {"java.logging", "java/util/logging/Logger.class"}, 65 {"java.base", "java/NOSUCHCLASS/yyy.class"}, // non-existent 66 {"NOSUCHMODULE", "java/lang/Class.class"}, // non-existent 67 }; 68 } 69 70 /** 71 * Test a class is correctly accessible from the image in a module. 72 * 73 * @param moduleName the module name 74 * @param className the classname 75 * @throws Exception is thrown if there is a test error 76 */ 77 @Test(dataProvider="classes") 78 public static void test1_ReadClasses(String moduleName, String className) throws Exception { 79 final int classMagic = 0xCAFEBABE; 80 81 if (!Files.exists(imageFile)) { 82 System.out.printf("Test skipped; no jimage file"); 83 return; 84 } 85 86 BasicImageReader reader = BasicImageReader.open(imageFile); 87 Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); 88 89 ImageLocation location = reader.findLocation(moduleName, className); 90 91 if (location != null && !location.verify("/" + moduleName + "/" + className)) { 92 location = null; 93 } 94 95 long size = location != null ? location.getUncompressedSize() : 0; 96 97 System.out.printf("reading: module: %s, path: %s, size: %d%n", 98 moduleName, className, size); 99 if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) { 100 Assert.assertTrue(location == null, 101 "location found for non-existing module: " 102 + moduleName 103 + ", or class: " + className); 104 return; // no more to test for non-existing class 105 } else { 106 Assert.assertTrue(location != null, "location not found: " + className); 107 Assert.assertTrue(size > 0, "size of should be > 0: " + className); 108 } 109 110 // positive: read whole class 111 ByteBuffer buffer = reader.getResourceBuffer(location); 112 Assert.assertTrue(buffer != null, "bytes read not equal bytes requested"); 113 114 if (className.endsWith(".class")) { 115 int m = buffer.getInt(); 116 Assert.assertEquals(m, classMagic, "Classfile has bad magic number"); 117 } 118 119 reader.close(); 120 } 121 122 /** 123 * For all the resource names, check the name and approximate count. 124 * 125 * @throws IOException thrown if an error occurs 126 */ 127 @Test 128 static void test2_ImageResources() throws IOException { 129 if (!Files.exists(imageFile)) { 130 System.out.printf("Test skipped; no jimage file"); 131 return; 132 } 133 134 BasicImageReader reader = BasicImageReader.open(imageFile); 135 Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); 136 137 String[] names = reader.getEntryNames(); 138 139 // Repeat with count available 140 int count = names.length; 141 142 System.out.printf(" count: %d, a class: %s\n", count, names[0]); 143 144 int minEntryCount = 16000; 145 Assert.assertTrue(minEntryCount < count, 146 "unexpected count of entries, count: " + count 147 + ", min: " + minEntryCount); 148 for (int i = 0; i < count; i++) { 149 checkFullName(names[i]); 150 } 151 152 reader.close(); 153 } 154 155 static void checkFullName(String path) { 156 if (path.startsWith("/packages") || path.startsWith("/modules")) { 157 return; 158 } 159 160 int next = 0; 161 String m = null; 162 String p = null; 163 String b = null; 164 String e = null; 165 if (path.startsWith("/")) { 166 next = path.indexOf('/', 1); 167 m = path.substring(1, next); 168 next = next + 1; 169 } 170 int lastSlash = path.lastIndexOf('/'); 171 if (lastSlash > next) { 172 // has a parent 173 p = path.substring(next, lastSlash); 174 next = lastSlash + 1; 175 } 176 int period = path.indexOf('.', next); 177 if (period > next) { 178 b = path.substring(next, period); 179 e = path.substring(period + 1); 180 } else { 181 b = path.substring(next); 182 } 183 Assert.assertNotNull(m, "module must be non-empty"); 184 Assert.assertNotNull(b, "base name must be non-empty"); 185 } 186 187 /** 188 * Verify that all of the resource names from BasicImageReader 189 * match those returned from the native JIMAGE_Resources iterator. 190 * Names that start with /modules, /packages, and bootmodules.jdata 191 * must appear in the names from JIMAGE_Resource iterator; 192 * from the BasicImageReader they are ignored. 193 */ 194 @Test 195 static void test3_verifyNames() { 196 if (!Files.exists(imageFile)) { 197 System.out.printf("Test skipped; no jimage file"); 198 return; 199 } 200 201 try { 202 String[] names = BasicImageReader_Names(); 203 //writeNames("/tmp/basic-names.txt", names); // debug 204 205 // Read all the names from the native JIMAGE API 206 String[] nativeNames = JIMAGE_Names(); 207 //writeNames("/tmp/native-names.txt", nativeNames); // debug 208 209 210 int modCount = 0; 211 int pkgCount = 0; 212 int otherCount = 0; 213 for (String n : nativeNames) { 214 if (n.startsWith("/modules/")) { 215 modCount++; 216 } else if (n.startsWith("/packages/")) { 217 pkgCount++; 218 } else { 219 otherCount++; 220 } 221 } 222 System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n", 223 names.length, modCount, pkgCount, otherCount); 224 225 // Sort and merge the two arrays. Every name should appear exactly twice. 226 Arrays.sort(names); 227 Arrays.sort(nativeNames); 228 String[] combined = Arrays.copyOf(names, nativeNames.length + names.length); 229 System.arraycopy(nativeNames,0, combined, names.length, nativeNames.length); 230 Arrays.sort(combined); 231 int missing = 0; 232 for (int i = 0; i < combined.length; i++) { 233 String s = combined[i]; 234 if (isMetaName(s)) { 235 // Ignore /modules and /packages in BasicImageReader names 236 continue; 237 } 238 239 if (i < combined.length - 1 && s.equals(combined[i + 1])) { 240 i++; // string appears in both java and native 241 continue; 242 } 243 244 missing++; 245 int ndx = Arrays.binarySearch(names, s); 246 String which = (ndx >= 0) ? "java BasicImageReader" : "native JIMAGE_Resources"; 247 System.out.printf("Missing Resource: %s found only via %s%n", s, which); 248 } 249 Assert.assertEquals(missing, 0, "Resources missing"); 250 251 } catch (IOException ioe) { 252 Assert.fail("I/O exception", ioe); 253 } 254 } 255 256 /** 257 * Return true if the name is one of the meta-data names 258 * @param name a name 259 * @return return true if starts with either /packages or /modules 260 */ 261 static boolean isMetaName(String name) { 262 return name.startsWith("/modules") 263 || name.startsWith("/packages") 264 || name.startsWith("META-INF") 265 || name.equals("bootmodules.jdata"); 266 } 267 268 /** 269 * Return all of the names from BasicImageReader. 270 * @return the names returned from BasicImageReader 271 */ 272 static String[] BasicImageReader_Names() throws IOException { 273 String[] names = null; 274 try (BasicImageReader reader = BasicImageReader.open(imageFile)) { 275 names = reader.getEntryNames(); 276 } catch (IOException ioe) { 277 Assert.fail("I/O exception", ioe); 278 } 279 return names; 280 } 281 282 /** 283 * Returns an array of all of the names returned from JIMAGE_Resources 284 */ 285 static String[] JIMAGE_Names() throws IOException { 286 287 BasicImageReader reader = BasicImageReader.open(imageFile); 288 Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); 289 290 String[] names = reader.getEntryNames(); 291 292 reader.close(); 293 294 return names; 295 } 296 297 // Write an array of names to a file for debugging 298 static void writeNames(String fname, String[] names) throws IOException { 299 try (FileWriter wr = new FileWriter(new File(fname))) { 300 for (String s : names) { 301 wr.write(s); 302 wr.write("\n"); 303 } 304 305 } 306 System.out.printf(" %s: %d names%n", fname, names.length); 307 } 308 309 //@Test 310 static void test4_nameTooLong() throws IOException { 311 long[] size = new long[1]; 312 String moduleName = "FictiousModuleName"; 313 String className = String.format("A%09999d", 1); 314 315 BasicImageReader reader = BasicImageReader.open(imageFile); 316 Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); 317 318 String name = "/" + moduleName + "/" + className; 319 ImageLocation location = reader.findLocation(name); 320 321 if (location != null && !location.verify(name)) { 322 location = null; 323 } 324 Assert.assertTrue(location == null, "Too long name should have failed"); 325 326 reader.close(); 327 } 328 329 /** 330 * Verify that the ImageReader returned by ImageReader.open has the 331 * the requested endianness or fails with an IOException if not. 332 */ 333 @Test 334 static void test5_imageReaderEndianness() throws IOException { 335 ImageReader nativeReader = ImageReader.open(imageFile); 336 Assert.assertEquals(nativeReader.getByteOrder(), ByteOrder.nativeOrder()); 337 338 try { 339 ImageReader leReader = ImageReader.open(imageFile, ByteOrder.LITTLE_ENDIAN); 340 Assert.assertEquals(leReader.getByteOrder(), ByteOrder.LITTLE_ENDIAN); 341 leReader.close(); 342 } catch (IOException io) { 343 // IOException expected if LITTLE_ENDIAN not the nativeOrder() 344 Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN); 345 } 346 347 try { 348 ImageReader beReader = ImageReader.open(imageFile, ByteOrder.BIG_ENDIAN); 349 Assert.assertEquals(beReader.getByteOrder(), ByteOrder.BIG_ENDIAN); 350 beReader.close(); 351 } catch (IOException io) { 352 // IOException expected if LITTLE_ENDIAN not the nativeOrder() 353 Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.BIG_ENDIAN); 354 } 355 356 nativeReader.close(); 357 } 358 // main method to run standalone from jtreg 359 360 @Test(enabled=false) 361 @Parameters({"x"}) 362 @SuppressWarnings("raw_types") 363 public static void main(@Optional String[] args) { 364 Class<?>[] testclass = { JImageReadTest.class}; 365 TestNG testng = new TestNG(); 366 testng.setTestClasses(testclass); 367 testng.run(); 368 } 369 370} 371