MiscRegressionTest.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.core; 18 19import junit.framework.Assert; 20import junit.framework.TestCase; 21 22import java.io.File; 23import java.io.InputStream; 24import java.io.ObjectInputStream; 25import java.lang.reflect.Field; 26import java.lang.reflect.Method; 27import java.security.KeyStore; 28import java.security.cert.Certificate; 29import java.util.Arrays; 30import java.util.ConcurrentModificationException; 31import java.util.Enumeration; 32import java.util.Iterator; 33import java.util.LinkedHashMap; 34import java.util.Random; 35import java.util.jar.JarEntry; 36import java.util.jar.JarFile; 37import java.util.logging.Logger; 38import java.util.zip.Deflater; 39import java.util.zip.Inflater; 40import java.util.zip.ZipEntry; 41import java.util.zip.ZipFile; 42import android.test.suitebuilder.annotation.MediumTest; 43import android.test.suitebuilder.annotation.SmallTest; 44import android.test.suitebuilder.annotation.LargeTest; 45 46public class MiscRegressionTest extends TestCase { 47 48 // Regression test for #857840: want JKS key store 49 @SmallTest 50 public void testDefaultKeystore() { 51 String type = KeyStore.getDefaultType(); 52 Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type); 53 54 try { 55 KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType()); 56 Assert.assertNotNull("Keystore must not be null", store); 57 } catch (Exception ex) { 58 throw new RuntimeException(ex); 59 } 60 61 try { 62 KeyStore store = KeyStore.getInstance("BKS"); 63 Assert.assertNotNull("Keystore must not be null", store); 64 } catch (Exception ex) { 65 throw new RuntimeException(ex); 66 } 67 } 68 69 // Regression test for #1061945: negative Shorts do not 70 // serialize/deserialize correctly 71 @SmallTest 72 public void testShortSerialization() throws Exception { 73 // create an instance of ObjectInputStream 74 String x = new String("serialize_foobar"); 75 java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); 76 (new java.io.ObjectOutputStream(baos)).writeObject(x); 77 ObjectInputStream ois = new java.io.ObjectInputStream( 78 new java.io.ByteArrayInputStream(baos.toByteArray())); 79 80 // get the setField(...,, short val) method in question 81 Class<ObjectInputStream> oClass = ObjectInputStream.class; 82 Method m = oClass.getDeclaredMethod("setField", new Class[] { Object.class, Class.class, String.class, short.class}); 83 // compose args 84 short start = 123; 85 short origval = -1; // 0xffff 86 Short obj = new Short(start); 87 Class<Short> declaringClass = Short.class; 88 String fieldDescName = "value"; 89 90 // test the initial value 91 assertEquals(obj.shortValue(), start); 92 // invoke native method to set the field "value" of type short to the newval 93 m.setAccessible(true); // since the method is private 94 m.invoke(ois, new Object[]{ obj, declaringClass, fieldDescName, new Short(origval)} ); 95 // test the set value 96 short res = obj.shortValue(); 97 assertEquals("Read and written values must be equal", origval, res); 98 } 99 100 // Regression test for #951285: Suitable LogHandler should be chosen 101 // depending on the environment. 102 @MediumTest 103 public void testAndroidLogHandler() throws Exception { 104 Logger.global.severe("This has logging Level.SEVERE, should become ERROR"); 105 Logger.global.warning("This has logging Level.WARNING, should become WARN"); 106 Logger.global.info("This has logging Level.INFO, should become INFO"); 107 Logger.global.config("This has logging Level.CONFIG, should become DEBUG"); 108 Logger.global.fine("This has logging Level.FINE, should become VERBOSE"); 109 Logger.global.finer("This has logging Level.FINER, should become VERBOSE"); 110 Logger.global.finest("This has logging Level.FINEST, should become VERBOSE"); 111 } 112 113 // Regression test for #1045939: Different output for Method.toString() 114 @SmallTest 115 public void testMethodToString() { 116 try { 117 Method m1 = Object.class.getMethod("notify", new Class[] { }); 118 Method m2 = Object.class.getMethod("toString", new Class[] { }); 119 Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class }); 120 Method m4 = Object.class.getMethod("equals", new Class[] { Object.class }); 121 Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class }); 122 Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class }); 123 124 assertEquals("Method.toString() must match expectations", 125 "public final native void java.lang.Object.notify()", 126 m1.toString()); 127 128 assertEquals("Method.toString() must match expectations", 129 "public java.lang.String java.lang.Object.toString()", 130 m2.toString()); 131 132 assertEquals("Method.toString() must match expectations", 133 "public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException", 134 m3.toString()); 135 136 assertEquals("Method.toString() must match expectations", 137 "public boolean java.lang.Object.equals(java.lang.Object)", 138 m4.toString()); 139 140 assertEquals("Method.toString() must match expectations", 141 "public static java.lang.String java.lang.String.valueOf(char[])", 142 m5.toString()); 143 144 assertEquals("Method.toString() must match expectations", 145 "public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException", 146 m6.toString()); 147 148 } catch (Exception ex) { 149 throw new RuntimeException(ex); 150 } 151 152 } 153 154 // Regression test for #1062200: Enum fails to deserialize. Actual problem 155 // was that Class.isEnum() erroneously returned true for indirect 156 // descendants of Enum. 157 enum TrafficLights { 158 RED, 159 YELLOW {}, 160 GREEN { 161 @SuppressWarnings("unused") 162 int i; 163 @SuppressWarnings("unused") 164 void foobar() {} 165 }; 166 } 167 168 @SmallTest 169 public void testClassIsEnum() { 170 Class<?> trafficClass = TrafficLights.class; 171 172 Class<?> redClass = TrafficLights.RED.getClass(); 173 Class<?> yellowClass = TrafficLights.YELLOW.getClass(); 174 Class<?> greenClass = TrafficLights.GREEN.getClass(); 175 176 Assert.assertSame("Classes must be equal", trafficClass, redClass); 177 Assert.assertNotSame("Classes must be different", trafficClass, yellowClass); 178 Assert.assertNotSame("Classes must be different", trafficClass, greenClass); 179 Assert.assertNotSame("Classes must be different", yellowClass, greenClass); 180 181 Assert.assertTrue("Must be an enum", trafficClass.isEnum()); 182 Assert.assertTrue("Must be an enum", redClass.isEnum()); 183 Assert.assertFalse("Must not be an enum", yellowClass.isEnum()); 184 Assert.assertFalse("Must not be an enum", greenClass.isEnum()); 185 186 Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants()); 187 Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants()); 188 Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants()); 189 } 190 191 // Regression test for #1046174: JarEntry.getCertificates() is really slow. 192 public void checkJarCertificates(File file) { 193 try { 194 JarFile jarFile = new JarFile(file); 195 JarEntry je = jarFile.getJarEntry("AndroidManifest.xml"); 196 byte[] readBuffer = new byte[1024]; 197 198 long t0 = System.currentTimeMillis(); 199 200 // We must read the stream for the JarEntry to retrieve 201 // its certificates. 202 InputStream is = jarFile.getInputStream(je); 203 while (is.read(readBuffer, 0, readBuffer.length) != -1) { 204 // not using 205 } 206 is.close(); 207 Certificate[] certs = je != null ? je.getCertificates() : null; 208 209 long t1 = System.currentTimeMillis(); 210 android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms"); 211 if (certs == null) { 212 android.util.Log.d("TestHarness", "We have no certificates"); 213 } else { 214 android.util.Log.d("TestHarness", "We have " + certs.length + " certificates"); 215 } 216 } catch (Exception ex) { 217 throw new RuntimeException(ex); 218 } 219 } 220 221 @LargeTest 222 public void testJarCertificates() { 223 File[] files = new File("/system/app").listFiles(); 224 for (int i = 0; i < files.length; i++) { 225 checkJarCertificates(files[i]); 226 } 227 } 228 229 // Regression test for #1120750: Reflection for static long fields is broken 230 private static final long MY_LONG = 5073258162644648461L; 231 232 @SmallTest 233 public void testLongFieldReflection() { 234 try { 235 Field field = getClass().getDeclaredField("MY_LONG"); 236 assertEquals(5073258162644648461L, field.getLong(null)); 237 } catch (Exception ex) { 238 throw new RuntimeException(ex); 239 } 240 } 241 242 // Regression test for Harmony LinkedHashMap bug. Copied from core, just 243 // to make sure it doesn't get lost. 244 @SmallTest 245 public void testLinkedHashMap() { 246 // we want to test the LinkedHashMap in access ordering mode. 247 LinkedHashMap map = new LinkedHashMap<String, String>(10, 0.75f, true); 248 249 map.put("key1", "value1"); 250 map.put("key2", "value2"); 251 map.put("key3", "value3"); 252 253 Iterator iterator = map.keySet().iterator(); 254 String id = (String) iterator.next(); 255 map.get(id); 256 try { 257 iterator.next(); 258 // A LinkedHashMap is supposed to throw this Exception when a 259 // iterator.next() Operation takes place after a get 260 // Operation. This is because the get Operation is considered 261 // a structural modification if the LinkedHashMap is in 262 // access order mode. 263 fail("expected ConcurrentModificationException was not thrown."); 264 } catch(ConcurrentModificationException e) { 265 // expected 266 } 267 268 LinkedHashMap mapClone = (LinkedHashMap) map.clone(); 269 270 iterator = map.keySet().iterator(); 271 id = (String) iterator.next(); 272 mapClone.get(id); 273 try { 274 iterator.next(); 275 } catch(ConcurrentModificationException e) { 276 fail("expected ConcurrentModificationException was not thrown."); 277 } 278 } 279 280 // Regression test for #1212257: Boot-time package scan is slow. Not 281 // expected to fail. Please see log if you are interested in the results. 282 @LargeTest 283 public void testZipStressManifest() { 284 android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); 285 286 long time0 = System.currentTimeMillis(); 287 288 try { 289 File[] files = new File("/system/app").listFiles(); 290 291 byte[] buffer = new byte[512]; 292 293 if (files != null) { 294 for (int i = 0; i < files.length; i++) { 295 android.util.Log.d("MiscRegressionTest", 296 "ZIP stress test processing " + files[i] + "..."); 297 298 ZipFile zip = new ZipFile(files[i]); 299 300 ZipEntry entry = zip.getEntry("AndroidManifest.xml"); 301 InputStream stream = zip.getInputStream(entry); 302 303 int j = stream.read(buffer); 304 while (j != -1) { 305 j = stream.read(buffer); 306 } 307 308 stream.close(); 309 } 310 } 311 } catch (Exception ex) { 312 throw new RuntimeException(ex); 313 } 314 315 long time1 = System.currentTimeMillis(); 316 317 android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + 318 "time was " + (time1- time0) + "ms"); 319 } 320 321 @LargeTest 322 public void testZipStressAllFiles() { 323 android.util.Log.d("MiscRegressionTest", "ZIP stress test started"); 324 325 long time0 = System.currentTimeMillis(); 326 327 try { 328 File[] files = new File("/system/app").listFiles(); 329 330 byte[] buffer = new byte[512]; 331 332 if (files != null) { 333 for (int i = 0; i < files.length; i++) { 334 android.util.Log.d("MiscRegressionTest", 335 "ZIP stress test processing " + files[i] + "..."); 336 337 ZipFile zip = new ZipFile(files[i]); 338 339 Enumeration<? extends ZipEntry> entries = zip.entries(); 340 while (entries.hasMoreElements()) { 341 InputStream stream = zip.getInputStream(entries.nextElement()); 342 343 int j = stream.read(buffer); 344 while (j != -1) { 345 j = stream.read(buffer); 346 } 347 348 stream.close(); 349 } 350 } 351 } 352 } catch (Exception ex) { 353 throw new RuntimeException(ex); 354 } 355 356 long time1 = System.currentTimeMillis(); 357 358 android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " + 359 "time was " + (time1- time0) + "ms"); 360 } 361 362 @SmallTest 363 public void testOsEncodingProperty() { 364 long time0 = System.currentTimeMillis(); 365 String[] files = new File("/system/app").list(); 366 long time1 = System.currentTimeMillis(); 367 android.util.Log.d("MiscRegressionTest", "File.list() test finished, " + 368 "time was " + (time1- time0) + "ms"); 369 } 370 371 // ------------------------------------------------------------------------- 372 // Regression test for #1185084: Native memory allocated by 373 // java.util.zip.Deflater in system_server. The fix reduced some internal 374 // ZLIB buffers in size, so this test is trying to execute a lot of 375 // deflating to ensure that things are still working properly. 376 private void assertEquals(byte[] a, byte[] b) { 377 assertEquals("Arrays must have same length", a.length, b.length); 378 379 for (int i = 0; i < a.length; i++) { 380 assertEquals("Array elements #" + i + " must be equal", a[i], b[i]); 381 } 382 } 383 384 @LargeTest 385 public void testZipDeflateInflateStress() { 386 387 final int DATA_SIZE = 16384; 388 389 Random random = new Random(42); // Seed makes test reproducible 390 391 try { 392 // Outer loop selects "mode" of test. 393 for (int j = 1; j <=2 ; j++) { 394 395 byte[] input = new byte[DATA_SIZE]; 396 397 if (j == 1) { 398 // Totally random content 399 random.nextBytes(input); 400 } else { 401 // Random contents with longer repetitions 402 int pos = 0; 403 while (pos < input.length) { 404 byte what = (byte)random.nextInt(256); 405 int howMany = random.nextInt(32); 406 if (pos + howMany >= input.length) { 407 howMany = input.length - pos; 408 } 409 Arrays.fill(input, pos, pos + howMany, what); 410 pos += howMany; 411 } 412 } 413 414 // Inner loop tries all 9 compression levels. 415 for (int i = 1; i <= 9; i++) { 416 android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")..."); 417 418 byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure... 419 420 Deflater deflater = new Deflater(i); 421 deflater.setInput(input); 422 deflater.finish(); 423 424 deflater.deflate(zipped); 425 426 byte[] output = new byte[DATA_SIZE]; 427 428 Inflater inflater = new Inflater(); 429 inflater.setInput(zipped); 430 inflater.finished(); 431 432 inflater.inflate(output); 433 434 assertEquals(input, output); 435 } 436 } 437 } catch (Exception ex) { 438 throw new RuntimeException(ex); 439 } 440 } 441 442 // ------------------------------------------------------------------------- 443 // Regression test for #1252043: Thread.getStackTrace() is broken 444 class MyThread extends Thread { 445 public MyThread(String name) { 446 super(name); 447 } 448 449 @Override 450 public void run() { 451 doSomething(); 452 } 453 454 public void doSomething() { 455 for (int i = 0; i < 20;) { 456 try { 457 Thread.sleep(100); 458 } catch (InterruptedException ex) { 459 } 460 } 461 } 462 } 463 464 class MyOtherThread extends Thread { 465 public int visibleTraces; 466 467 public MyOtherThread(ThreadGroup group, String name) { 468 super(group, name); 469 } 470 471 @Override 472 public void run() { 473 visibleTraces = Thread.getAllStackTraces().size(); 474 } 475 } 476 477 @LargeTest 478 public void testThreadGetStackTrace() { 479 MyThread t1 = new MyThread("t1"); 480 t1.start(); 481 482 try { 483 Thread.sleep(1000); 484 } catch (InterruptedException ex) { 485 } 486 487 StackTraceElement[] traces = t1.getStackTrace(); 488 StackTraceElement trace = traces[traces.length - 2]; 489 490 // Expect to find MyThread.doSomething in the trace 491 assertTrue("Must find MyThread.doSomething in trace", 492 trace.getClassName().endsWith("$MyThread") && 493 trace.getMethodName().equals("doSomething")); 494 495 ThreadGroup g1 = new ThreadGroup("1"); 496 MyOtherThread t2 = new MyOtherThread(g1, "t2"); 497 t2.start(); 498 try { 499 t2.join(); 500 } catch (InterruptedException ex) { 501 } 502 503 // Expect to see the traces of all threads (not just t2) 504 assertTrue("Must have traces for all threads", t2.visibleTraces > 1); 505 } 506} 507