blob: 773439770104f0d056879c4cf81d5c56725ba129 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.core;
import junit.framework.Assert;
import junit.framework.TestCase;
import java.io.File;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Random;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;
import java.util.zip.Deflater;
import java.util.zip.Inflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.test.suitebuilder.annotation.LargeTest;
public class MiscRegressionTest extends TestCase {
// Regression test for #857840: want JKS key store
@SmallTest
public void testDefaultKeystore() {
String type = KeyStore.getDefaultType();
Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type);
try {
KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
Assert.assertNotNull("Keystore must not be null", store);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
try {
KeyStore store = KeyStore.getInstance("BKS");
Assert.assertNotNull("Keystore must not be null", store);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Regression test for #951285: Suitable LogHandler should be chosen
// depending on the environment.
@MediumTest
public void testAndroidLogHandler() throws Exception {
Logger.global.severe("This has logging Level.SEVERE, should become ERROR");
Logger.global.warning("This has logging Level.WARNING, should become WARN");
Logger.global.info("This has logging Level.INFO, should become INFO");
Logger.global.config("This has logging Level.CONFIG, should become DEBUG");
Logger.global.fine("This has logging Level.FINE, should become VERBOSE");
Logger.global.finer("This has logging Level.FINER, should become VERBOSE");
Logger.global.finest("This has logging Level.FINEST, should become VERBOSE");
}
// Regression test for Issue 5697:
// getContextClassLoader returns a non-application classloader
// http://code.google.com/p/android/issues/detail?id=5697
//
@MediumTest
public void testJavaContextClassLoader() throws Exception {
Assert.assertNotNull("Must hava a Java context ClassLoader",
Thread.currentThread().getContextClassLoader());
}
// Regression test for #1045939: Different output for Method.toString()
@SmallTest
public void testMethodToString() {
try {
Method m1 = Object.class.getMethod("notify", new Class[] { });
Method m2 = Object.class.getMethod("toString", new Class[] { });
Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class });
Method m4 = Object.class.getMethod("equals", new Class[] { Object.class });
Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class });
Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class });
assertEquals("Method.toString() must match expectations",
"public final native void java.lang.Object.notify()",
m1.toString());
assertEquals("Method.toString() must match expectations",
"public java.lang.String java.lang.Object.toString()",
m2.toString());
assertEquals("Method.toString() must match expectations",
"public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException",
m3.toString());
assertEquals("Method.toString() must match expectations",
"public boolean java.lang.Object.equals(java.lang.Object)",
m4.toString());
assertEquals("Method.toString() must match expectations",
"public static java.lang.String java.lang.String.valueOf(char[])",
m5.toString());
assertEquals("Method.toString() must match expectations",
"public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException",
m6.toString());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Regression test for #1062200: Enum fails to deserialize. Actual problem
// was that Class.isEnum() erroneously returned true for indirect
// descendants of Enum.
enum TrafficLights {
RED,
YELLOW {},
GREEN {
@SuppressWarnings("unused")
int i;
@SuppressWarnings("unused")
void foobar() {}
};
}
@SmallTest
public void testClassIsEnum() {
Class<?> trafficClass = TrafficLights.class;
Class<?> redClass = TrafficLights.RED.getClass();
Class<?> yellowClass = TrafficLights.YELLOW.getClass();
Class<?> greenClass = TrafficLights.GREEN.getClass();
Assert.assertSame("Classes must be equal", trafficClass, redClass);
Assert.assertNotSame("Classes must be different", trafficClass, yellowClass);
Assert.assertNotSame("Classes must be different", trafficClass, greenClass);
Assert.assertNotSame("Classes must be different", yellowClass, greenClass);
Assert.assertTrue("Must be an enum", trafficClass.isEnum());
Assert.assertTrue("Must be an enum", redClass.isEnum());
Assert.assertFalse("Must not be an enum", yellowClass.isEnum());
Assert.assertFalse("Must not be an enum", greenClass.isEnum());
Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants());
Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants());
Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants());
}
// Regression test for #1046174: JarEntry.getCertificates() is really slow.
public void checkJarCertificates(File file) {
try {
JarFile jarFile = new JarFile(file);
JarEntry je = jarFile.getJarEntry("AndroidManifest.xml");
byte[] readBuffer = new byte[1024];
long t0 = System.currentTimeMillis();
// We must read the stream for the JarEntry to retrieve
// its certificates.
InputStream is = jarFile.getInputStream(je);
while (is.read(readBuffer, 0, readBuffer.length) != -1) {
// not using
}
is.close();
Certificate[] certs = je != null ? je.getCertificates() : null;
long t1 = System.currentTimeMillis();
android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms");
if (certs == null) {
android.util.Log.d("TestHarness", "We have no certificates");
} else {
android.util.Log.d("TestHarness", "We have " + certs.length + " certificates");
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
@LargeTest
public void testJarCertificates() {
File[] files = new File("/system/app").listFiles();
for (int i = 0; i < files.length; i++) {
checkJarCertificates(files[i]);
}
}
// Regression test for #1120750: Reflection for static long fields is broken
private static final long MY_LONG = 5073258162644648461L;
@SmallTest
public void testLongFieldReflection() {
try {
Field field = getClass().getDeclaredField("MY_LONG");
assertEquals(5073258162644648461L, field.getLong(null));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Regression test for Harmony LinkedHashMap bug. Copied from core, just
// to make sure it doesn't get lost.
@SmallTest
public void testLinkedHashMap() {
// we want to test the LinkedHashMap in access ordering mode.
LinkedHashMap map = new LinkedHashMap<String, String>(10, 0.75f, true);
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
Iterator iterator = map.keySet().iterator();
String id = (String) iterator.next();
map.get(id);
try {
iterator.next();
// A LinkedHashMap is supposed to throw this Exception when a
// iterator.next() Operation takes place after a get
// Operation. This is because the get Operation is considered
// a structural modification if the LinkedHashMap is in
// access order mode.
fail("expected ConcurrentModificationException was not thrown.");
} catch(ConcurrentModificationException e) {
// expected
}
LinkedHashMap mapClone = (LinkedHashMap) map.clone();
iterator = map.keySet().iterator();
id = (String) iterator.next();
mapClone.get(id);
try {
iterator.next();
} catch(ConcurrentModificationException e) {
fail("expected ConcurrentModificationException was not thrown.");
}
}
// Regression test for #1212257: Boot-time package scan is slow. Not
// expected to fail. Please see log if you are interested in the results.
@LargeTest
public void testZipStressManifest() {
android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
long time0 = System.currentTimeMillis();
try {
File[] files = new File("/system/app").listFiles();
byte[] buffer = new byte[512];
if (files != null) {
for (int i = 0; i < files.length; i++) {
android.util.Log.d("MiscRegressionTest",
"ZIP stress test processing " + files[i] + "...");
ZipFile zip = new ZipFile(files[i]);
ZipEntry entry = zip.getEntry("AndroidManifest.xml");
InputStream stream = zip.getInputStream(entry);
int j = stream.read(buffer);
while (j != -1) {
j = stream.read(buffer);
}
stream.close();
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
long time1 = System.currentTimeMillis();
android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
"time was " + (time1- time0) + "ms");
}
@LargeTest
public void testZipStressAllFiles() {
android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
long time0 = System.currentTimeMillis();
try {
File[] files = new File("/system/app").listFiles();
byte[] buffer = new byte[512];
if (files != null) {
for (int i = 0; i < files.length; i++) {
android.util.Log.d("MiscRegressionTest",
"ZIP stress test processing " + files[i] + "...");
ZipFile zip = new ZipFile(files[i]);
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
InputStream stream = zip.getInputStream(entries.nextElement());
int j = stream.read(buffer);
while (j != -1) {
j = stream.read(buffer);
}
stream.close();
}
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
long time1 = System.currentTimeMillis();
android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
"time was " + (time1- time0) + "ms");
}
@SmallTest
public void testOsEncodingProperty() {
long time0 = System.currentTimeMillis();
String[] files = new File("/system/app").list();
long time1 = System.currentTimeMillis();
android.util.Log.d("MiscRegressionTest", "File.list() test finished, " +
"time was " + (time1- time0) + "ms");
}
// -------------------------------------------------------------------------
// Regression test for #1185084: Native memory allocated by
// java.util.zip.Deflater in system_server. The fix reduced some internal
// ZLIB buffers in size, so this test is trying to execute a lot of
// deflating to ensure that things are still working properly.
private void assertEquals(byte[] a, byte[] b) {
assertEquals("Arrays must have same length", a.length, b.length);
for (int i = 0; i < a.length; i++) {
assertEquals("Array elements #" + i + " must be equal", a[i], b[i]);
}
}
@LargeTest
public void testZipDeflateInflateStress() {
final int DATA_SIZE = 16384;
Random random = new Random(42); // Seed makes test reproducible
try {
// Outer loop selects "mode" of test.
for (int j = 1; j <=2 ; j++) {
byte[] input = new byte[DATA_SIZE];
if (j == 1) {
// Totally random content
random.nextBytes(input);
} else {
// Random contents with longer repetitions
int pos = 0;
while (pos < input.length) {
byte what = (byte)random.nextInt(256);
int howMany = random.nextInt(32);
if (pos + howMany >= input.length) {
howMany = input.length - pos;
}
Arrays.fill(input, pos, pos + howMany, what);
pos += howMany;
}
}
// Inner loop tries all 9 compression levels.
for (int i = 1; i <= 9; i++) {
android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")...");
byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure...
Deflater deflater = new Deflater(i);
deflater.setInput(input);
deflater.finish();
deflater.deflate(zipped);
byte[] output = new byte[DATA_SIZE];
Inflater inflater = new Inflater();
inflater.setInput(zipped);
inflater.finished();
inflater.inflate(output);
assertEquals(input, output);
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// -------------------------------------------------------------------------
// Regression test for #1252043: Thread.getStackTrace() is broken
class MyThread extends Thread {
public MyThread(String name) {
super(name);
}
@Override
public void run() {
doSomething();
}
public void doSomething() {
for (int i = 0; i < 20;) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
}
}
class MyOtherThread extends Thread {
public int visibleTraces;
public MyOtherThread(ThreadGroup group, String name) {
super(group, name);
}
@Override
public void run() {
visibleTraces = Thread.getAllStackTraces().size();
}
}
@LargeTest
public void testThreadGetStackTrace() {
MyThread t1 = new MyThread("t1");
t1.start();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
StackTraceElement[] traces = t1.getStackTrace();
StackTraceElement trace = traces[traces.length - 2];
// Expect to find MyThread.doSomething in the trace
assertTrue("Must find MyThread.doSomething in trace",
trace.getClassName().endsWith("$MyThread") &&
trace.getMethodName().equals("doSomething"));
ThreadGroup g1 = new ThreadGroup("1");
MyOtherThread t2 = new MyOtherThread(g1, "t2");
t2.start();
try {
t2.join();
} catch (InterruptedException ex) {
}
// Expect to see the traces of all threads (not just t2)
assertTrue("Must have traces for all threads", t2.visibleTraces > 1);
}
}