• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.core;
18 
19 import junit.framework.Assert;
20 import junit.framework.TestCase;
21 
22 import java.io.File;
23 import java.io.InputStream;
24 import java.io.ObjectInputStream;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.Method;
27 import java.security.KeyStore;
28 import java.security.cert.Certificate;
29 import java.util.Arrays;
30 import java.util.ConcurrentModificationException;
31 import java.util.Enumeration;
32 import java.util.Iterator;
33 import java.util.LinkedHashMap;
34 import java.util.Random;
35 import java.util.jar.JarEntry;
36 import java.util.jar.JarFile;
37 import java.util.logging.Logger;
38 import java.util.zip.Deflater;
39 import java.util.zip.Inflater;
40 import java.util.zip.ZipEntry;
41 import java.util.zip.ZipFile;
42 import android.test.suitebuilder.annotation.MediumTest;
43 import android.test.suitebuilder.annotation.SmallTest;
44 import android.test.suitebuilder.annotation.LargeTest;
45 
46 public class MiscRegressionTest extends TestCase {
47 
48     // Regression test for #857840: want JKS key store
49     @SmallTest
testDefaultKeystore()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
testShortSerialization()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
testAndroidLogHandler()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
testMethodToString()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")
foobar()164             void foobar() {}
165         };
166     }
167 
168     @SmallTest
testClassIsEnum()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.
checkJarCertificates(File file)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
testJarCertificates()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
testLongFieldReflection()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
testLinkedHashMap()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
testZipStressManifest()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
testZipStressAllFiles()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
testOsEncodingProperty()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.
assertEquals(byte[] a, byte[] b)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
testZipDeflateInflateStress()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 {
MyThread(String name)445         public MyThread(String name) {
446             super(name);
447         }
448 
449         @Override
run()450         public void run() {
451             doSomething();
452         }
453 
doSomething()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 
MyOtherThread(ThreadGroup group, String name)467         public MyOtherThread(ThreadGroup group, String name) {
468             super(group, name);
469         }
470 
471         @Override
run()472         public void run() {
473             visibleTraces = Thread.getAllStackTraces().size();
474         }
475     }
476 
477     @LargeTest
testThreadGetStackTrace()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