diff options
Diffstat (limited to 'test-runner')
12 files changed, 254 insertions, 105 deletions
diff --git a/test-runner/android/test/ActivityInstrumentationTestCase.java b/test-runner/android/test/ActivityInstrumentationTestCase.java index e5a9991..f6b31ad 100644 --- a/test-runner/android/test/ActivityInstrumentationTestCase.java +++ b/test-runner/android/test/ActivityInstrumentationTestCase.java @@ -40,7 +40,11 @@ public abstract class ActivityInstrumentationTestCase<T extends Activity> boolean mInitialTouchMode = false; /** - * @param pkg The package of the instrumentation. + * <b>NOTE:</b> The parameter <i>pkg</i> must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public ActivityInstrumentationTestCase(String pkg, Class<T> activityClass) { @@ -48,7 +52,11 @@ public abstract class ActivityInstrumentationTestCase<T extends Activity> } /** - * @param pkg The package of the instrumentation. + * <b>NOTE:</b> The parameter <i>pkg</i> must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. * @param initialTouchMode true = in touch mode */ diff --git a/test-runner/android/test/ActivityInstrumentationTestCase2.java b/test-runner/android/test/ActivityInstrumentationTestCase2.java index 7a84eca..679f634 100644 --- a/test-runner/android/test/ActivityInstrumentationTestCase2.java +++ b/test-runner/android/test/ActivityInstrumentationTestCase2.java @@ -46,7 +46,11 @@ public abstract class ActivityInstrumentationTestCase2<T extends Activity> Intent mActivityIntent = null; /** - * @param pkg The package of the instrumentation. + * <b>NOTE:</b> The parameter <i>pkg</i> must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public ActivityInstrumentationTestCase2(String pkg, Class<T> activityClass) { diff --git a/test-runner/android/test/InstrumentationCoreTestRunner.java b/test-runner/android/test/InstrumentationCoreTestRunner.java index 3f77a60..ff99a74 100644 --- a/test-runner/android/test/InstrumentationCoreTestRunner.java +++ b/test-runner/android/test/InstrumentationCoreTestRunner.java @@ -49,7 +49,15 @@ import android.util.Log; */ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { + /** + * Convenience definition of our log tag. + */ private static final String TAG = "InstrumentationCoreTestRunner"; + + /** + * True if (and only if) we are running in single-test mode (as opposed to + * batch mode). + */ private boolean singleTest = false; @Override @@ -57,6 +65,7 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { // We might want to move this to /sdcard, if is is mounted/writable. File cacheDir = getTargetContext().getCacheDir(); + // Set some properties that the core tests absolutely need. System.setProperty("user.language", "en"); System.setProperty("user.region", "US"); @@ -74,38 +83,66 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { super.onCreate(arguments); } + @Override protected AndroidTestRunner getAndroidTestRunner() { AndroidTestRunner runner = super.getAndroidTestRunner(); runner.addTestListener(new TestListener() { + /** + * The last test class we executed code from. + */ private Class<?> lastClass; + /** + * The minimum time we expect a test to take. + */ + private static final int MINIMUM_TIME = 100; + + /** + * The start time of our current test in System.currentTimeMillis(). + */ + private long startTime; + public void startTest(Test test) { if (test.getClass() != lastClass) { + lastClass = test.getClass(); printMemory(test.getClass()); } Thread.currentThread().setContextClassLoader( test.getClass().getClassLoader()); + + startTime = System.currentTimeMillis(); } public void endTest(Test test) { if (test instanceof TestCase) { - if (lastClass == null) { - lastClass = test.getClass(); - } else { - if (test.getClass() != lastClass) { - cleanup(lastClass); - lastClass = test.getClass(); + cleanup((TestCase)test); + + /* + * Make sure all tests take at least MINIMUM_TIME to + * complete. If they don't, we wait a bit. The Cupcake + * Binder can't handle too many operations in a very + * short time, which causes headache for the CTS. + */ + long timeTaken = System.currentTimeMillis() - startTime; + + if (timeTaken < MINIMUM_TIME) { + try { + Thread.sleep(MINIMUM_TIME - timeTaken); + } catch (InterruptedException ignored) { + // We don't care. } } } } public void addError(Test test, Throwable t) { + // This space intentionally left blank. } public void addFailure(Test test, AssertionFailedError t) { + // This space intentionally left blank. } /** @@ -125,30 +162,31 @@ public class InstrumentationCoreTestRunner extends InstrumentationTestRunner { } /** - * Nulls all static reference fields in the given test class. This - * method helps us with those test classes that don't have an + * Nulls all non-static reference fields in the given test class. + * This method helps us with those test classes that don't have an * explicit tearDown() method. Normally the garbage collector should * take care of everything, but since JUnit keeps references to all * test cases, a little help might be a good idea. */ - private void cleanup(Class<?> clazz) { - if (clazz != TestCase.class) { + private void cleanup(TestCase test) { + Class<?> clazz = test.getClass(); + + while (clazz != TestCase.class) { Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; if (!f.getType().isPrimitive() && - Modifier.isStatic(f.getModifiers())) { + !Modifier.isStatic(f.getModifiers())) { try { f.setAccessible(true); - f.set(null, null); + f.set(test, null); } catch (Exception ignored) { // Nothing we can do about it. } } } - // don't cleanup the superclass for now - //cleanup(clazz.getSuperclass()); + clazz = clazz.getSuperclass(); } } diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java index d5e6459..6658fb0 100644 --- a/test-runner/android/test/InstrumentationTestRunner.java +++ b/test-runner/android/test/InstrumentationTestRunner.java @@ -118,7 +118,8 @@ import java.util.List; * <b>To generate EMMA code coverage:</b> * -e coverage true * Note: this requires an emma instrumented build. By default, the code coverage results file - * will be saved as /sdcard/coverage.ec, unless overridden by coverageFile flag (see below) + * will be saved in a /data/<app>/coverage.ec file, unless overridden by coverageFile flag (see + * below) * <p/> * <b> To specify EMMA code coverage results file path:</b> * -e coverageFile /sdcard/myFile.ec @@ -218,6 +219,11 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu */ private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment"; /** + * If included in the status or final bundle sent to an IInstrumentationWatcher, this key + * identifies the path to the generated code coverage file. + */ + private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath"; + /** * The test is starting. */ public static final int REPORT_VALUE_RESULT_START = 1; @@ -240,7 +246,8 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu */ public static final String REPORT_KEY_STACK = "stack"; - private static final String DEFAULT_COVERAGE_FILE_PATH = "/sdcard/coverage.ec"; + // Default file name for code coverage + private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec"; private static final String LOG_TAG = "InstrumentationTestRunner"; @@ -456,14 +463,20 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu private void generateCoverageReport() { // use reflection to call emma dump coverage method, to avoid // always statically compiling against emma jar - java.io.File coverageFile = new java.io.File(getCoverageFilePath()); + String coverageFilePath = getCoverageFilePath(); + java.io.File coverageFile = new java.io.File(coverageFilePath); try { Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT"); Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData", coverageFile.getClass(), boolean.class, boolean.class); dumpCoverageMethod.invoke(null, coverageFile, false, false); - + // output path to generated coverage file so it can be parsed by a test harness if + // needed + mResults.putString(REPORT_KEY_COVERAGE_PATH, coverageFilePath); + // also output a more user friendly msg + mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, + String.format("Generated code coverage data to %s", coverageFilePath)); } catch (ClassNotFoundException e) { reportEmmaError("Is emma jar on classpath?", e); } catch (SecurityException e) { @@ -481,8 +494,9 @@ public class InstrumentationTestRunner extends Instrumentation implements TestSu private String getCoverageFilePath() { if (mCoverageFilePath == null) { - return DEFAULT_COVERAGE_FILE_PATH; - } + return getTargetContext().getFilesDir().getAbsolutePath() + File.separator + + DEFAULT_COVERAGE_FILE_NAME; + } else { return mCoverageFilePath; } diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java index 2866666..859b2e5 100644 --- a/test-runner/android/test/IsolatedContext.java +++ b/test-runner/android/test/IsolatedContext.java @@ -13,6 +13,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import java.util.List; +import java.io.File; /** * A mock context which prevents its users from talking to the rest of the device while @@ -82,4 +83,8 @@ public class IsolatedContext extends ContextWrapper { return null; } + @Override + public File getFilesDir() { + return new File("/dev/null"); + } } diff --git a/test-runner/android/test/MoreAsserts.java b/test-runner/android/test/MoreAsserts.java index 2e74644..9e0d018 100644 --- a/test-runner/android/test/MoreAsserts.java +++ b/test-runner/android/test/MoreAsserts.java @@ -24,6 +24,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.ArrayList; import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -316,8 +317,11 @@ public final class MoreAsserts { */ public static void assertContentsInOrder( String message, Iterable<?> actual, Object... expected) { - Assert.assertEquals(message, - Arrays.asList(expected), Lists.newArrayList(actual)); + ArrayList actualList = new ArrayList(); + for (Object o : actual) { + actualList.add(o); + } + Assert.assertEquals(message, Arrays.asList(expected), actualList); } /** diff --git a/test-runner/android/test/ProviderTestCase2.java b/test-runner/android/test/ProviderTestCase2.java index ac17ebf..a923d2a 100644 --- a/test-runner/android/test/ProviderTestCase2.java +++ b/test-runner/android/test/ProviderTestCase2.java @@ -3,6 +3,7 @@ package android.test; import android.content.ContentProvider; import android.content.ContentResolver; import android.content.Context; +import android.content.res.Resources; import android.test.mock.MockContext; import android.test.mock.MockContentResolver; import android.database.DatabaseUtils; @@ -26,6 +27,14 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro private IsolatedContext mProviderContext; private MockContentResolver mResolver; + private class MockContext2 extends MockContext { + + @Override + public Resources getResources() { + return getContext().getResources(); + } + } + public ProviderTestCase2(Class<T> providerClass, String providerAuthority) { mProviderClass = providerClass; mProviderAuthority = providerAuthority; @@ -47,7 +56,7 @@ public abstract class ProviderTestCase2<T extends ContentProvider> extends Andro mResolver = new MockContentResolver(); final String filenamePrefix = "test."; RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext( - new MockContext(), // The context that most methods are delegated to + new MockContext2(), // The context that most methods are delegated to getContext(), // The context that file methods are delegated to filenamePrefix); mProviderContext = new IsolatedContext(mResolver, targetContextWrapper); diff --git a/test-runner/android/test/SingleLaunchActivityTestCase.java b/test-runner/android/test/SingleLaunchActivityTestCase.java index 8d43b73..b63b3ce 100644 --- a/test-runner/android/test/SingleLaunchActivityTestCase.java +++ b/test-runner/android/test/SingleLaunchActivityTestCase.java @@ -37,7 +37,11 @@ public abstract class SingleLaunchActivityTestCase<T extends Activity> private static boolean sActivityLaunchedFlag = false; /** - * @param pkg The package of the instrumentation. + * <b>NOTE:</b> The parameter <i>pkg</i> must refer to the package identifier of the + * package hosting the activity to be launched, which is specified in the AndroidManifest.xml + * file. This is not necessarily the same as the java package name. + * + * @param pkg The package hosting the activity to be launched. * @param activityClass The activity to test. */ public SingleLaunchActivityTestCase(String pkg, Class<T> activityClass) { diff --git a/test-runner/android/test/SyncBaseInstrumentation.java b/test-runner/android/test/SyncBaseInstrumentation.java index c1d2507..772d75c 100644 --- a/test-runner/android/test/SyncBaseInstrumentation.java +++ b/test-runner/android/test/SyncBaseInstrumentation.java @@ -18,12 +18,10 @@ package android.test; import android.content.ContentResolver; import android.content.Context; -import android.content.ContentValues; import android.os.Bundle; +import android.os.RemoteException; import android.os.SystemClock; -import android.provider.Sync; import android.net.Uri; -import java.util.Map; /** * If you would like to test sync a single provider with an @@ -75,11 +73,11 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { } protected void cancelSyncsandDisableAutoSync() { - Sync.Settings.QueryMap mSyncSettings = - new Sync.Settings.QueryMap(mContentResolver, true, null); - mSyncSettings.setListenForNetworkTickles(false); + try { + ContentResolver.getContentService().setListenForNetworkTickles(false); + } catch (RemoteException e) { + } mContentResolver.cancelSync(null); - mSyncSettings.close(); } /** @@ -88,34 +86,11 @@ public class SyncBaseInstrumentation extends InstrumentationTestCase { * @return */ private boolean isSyncActive(String account, String authority) { - Sync.Pending.QueryMap pendingQueryMap = null; - Sync.Active.QueryMap activeQueryMap = null; try { - pendingQueryMap = new Sync.Pending.QueryMap(mContentResolver, false, null); - activeQueryMap = new Sync.Active.QueryMap(mContentResolver, false, null); - - if (pendingQueryMap.isPending(account, authority)) { - return true; - } - if (isActiveInActiveQueryMap(activeQueryMap, account, authority)) { - return true; - } + return ContentResolver.getContentService().isSyncActive(account, + authority); + } catch (RemoteException e) { return false; - } finally { - activeQueryMap.close(); - pendingQueryMap.close(); - } - } - - private boolean isActiveInActiveQueryMap(Sync.Active.QueryMap activemap, String account, - String authority) { - Map<String, ContentValues> rows = activemap.getRows(); - for (ContentValues values : rows.values()) { - if (values.getAsString("account").equals(account) - && values.getAsString("authority").equals(authority)) { - return true; - } } - return false; } } diff --git a/test-runner/android/test/TestLocationProvider.java b/test-runner/android/test/TestLocationProvider.java index 00c1ce8..2ea020e 100644 --- a/test-runner/android/test/TestLocationProvider.java +++ b/test-runner/android/test/TestLocationProvider.java @@ -18,16 +18,20 @@ package android.test; import android.location.Criteria; +import android.location.ILocationManager; +import android.location.ILocationProvider; import android.location.Location; -import android.location.LocationProviderImpl; +import android.location.LocationProvider; import android.os.Bundle; +import android.os.RemoteException; import android.os.SystemClock; +import android.util.Log; /** * @hide - This is part of a framework that is under development and should not be used for * active development. */ -public class TestLocationProvider extends LocationProviderImpl { +public class TestLocationProvider extends ILocationProvider.Stub { public static final String PROVIDER_NAME = "test"; public static final double LAT = 0; @@ -35,92 +39,139 @@ public class TestLocationProvider extends LocationProviderImpl { public static final double ALTITUDE = 10000; public static final float SPEED = 10; public static final float BEARING = 1; - public static final int STATUS = AVAILABLE; + public static final int STATUS = LocationProvider.AVAILABLE; + private static final long LOCATION_INTERVAL = 1000; + private static final String TAG = "TestLocationProvider"; + + private final ILocationManager mLocationManager; private Location mLocation; private boolean mEnabled; - - public TestLocationProvider() { - super(PROVIDER_NAME); + private TestLocationProviderThread mThread; + + private class TestLocationProviderThread extends Thread { + + private boolean mDone = false; + + public TestLocationProviderThread() { + super("TestLocationProviderThread"); + } + + public void run() { + // thread exits after disable() is called + synchronized (this) { + while (!mDone) { + try { + wait(LOCATION_INTERVAL); + } catch (InterruptedException e) { + } + + if (!mDone) { + TestLocationProvider.this.updateLocation(); + } + } + } + } + + synchronized void setDone() { + mDone = true; + notify(); + } + } + + public TestLocationProvider(ILocationManager locationManager) { + mLocationManager = locationManager; mLocation = new Location(PROVIDER_NAME); - updateLocation(); } - //LocationProvider methods - - @Override public int getAccuracy() { return Criteria.ACCURACY_COARSE; } - @Override public int getPowerRequirement() { return Criteria.NO_REQUIREMENT; } - @Override public boolean hasMonetaryCost() { return false; } - @Override public boolean requiresCell() { return false; } - @Override public boolean requiresNetwork() { return false; } - @Override public boolean requiresSatellite() { return false; } - @Override public boolean supportsAltitude() { return true; } - @Override public boolean supportsBearing() { return true; } - @Override public boolean supportsSpeed() { return true; } - //LocationProviderImpl methods - @Override - public void disable() { + public synchronized void disable() { mEnabled = false; + if (mThread != null) { + mThread.setDone(); + try { + mThread.join(); + } catch (InterruptedException e) { + } + mThread = null; + } } - @Override - public void enable() { - mEnabled = true; + public synchronized void enable() { + mEnabled = true; + mThread = new TestLocationProviderThread(); + mThread.start(); } - @Override public boolean isEnabled() { return mEnabled; } - @Override - public boolean getLocation(Location l) { - updateLocation(); - l.set(mLocation); - return true; - } - - @Override public int getStatus(Bundle extras) { return STATUS; } + public long getStatusUpdateTime() { + return 0; + } + + public void enableLocationTracking(boolean enable) { + } + + public void setMinTime(long minTime) { + } + + public void updateNetworkState(int state) { + } + + public void updateLocation(Location location) { + } + + public boolean sendExtraCommand(String command, Bundle extras) { + return false; + } + + public void addListener(int uid) { + } + + public void removeListener(int uid) { + } + private void updateLocation() { long time = SystemClock.uptimeMillis(); long multiplier = (time/5000)%500000; @@ -134,6 +185,11 @@ public class TestLocationProvider extends LocationProviderImpl { extras.putInt("extraTest", 24); mLocation.setExtras(extras); mLocation.setTime(time); + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling updateLocation"); + } } } diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java index e733dd1..9fb1e61 100644 --- a/test-runner/android/test/mock/MockContext.java +++ b/test-runner/android/test/mock/MockContext.java @@ -24,6 +24,7 @@ import android.content.IntentFilter; import android.content.BroadcastReceiver; import android.content.ServiceConnection; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Resources; @@ -100,10 +101,21 @@ public class MockContext extends Context { } @Override + public ApplicationInfo getApplicationInfo() { + throw new UnsupportedOperationException(); + } + + @Override public String getPackageResourcePath() { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public File getSharedPrefsFile(String name) { + throw new UnsupportedOperationException(); + } + @Override public String getPackageCodePath() { throw new UnsupportedOperationException(); @@ -386,4 +398,9 @@ public class MockContext extends Context { throws PackageManager.NameNotFoundException { throw new UnsupportedOperationException(); } + + @Override + public boolean isRestricted() { + throw new UnsupportedOperationException(); + } } diff --git a/test-runner/android/test/mock/MockPackageManager.java b/test-runner/android/test/mock/MockPackageManager.java index ea190e2..d5cd6ef 100644 --- a/test-runner/android/test/mock/MockPackageManager.java +++ b/test-runner/android/test/mock/MockPackageManager.java @@ -16,10 +16,10 @@ package android.test.mock; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Intent; import android.content.IntentFilter; +import android.content.IntentSender; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDeleteObserver; @@ -57,11 +57,10 @@ public class MockPackageManager extends PackageManager { } @Override - public Intent getLaunchIntentForPackage(String packageName) - throws NameNotFoundException { + public Intent getLaunchIntentForPackage(String packageName) { throw new UnsupportedOperationException(); } - + @Override public int[] getPackageGids(String packageName) throws NameNotFoundException { throw new UnsupportedOperationException(); @@ -284,9 +283,20 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ @Override public void installPackage(Uri packageURI, IPackageInstallObserver observer, - int flags) { + int flags, String installerPackageName) { + throw new UnsupportedOperationException(); + } + + /** + * @hide - to match hiding in superclass + */ + @Override + public String getInstallerPackageName(String packageName) { throw new UnsupportedOperationException(); } @@ -316,13 +326,13 @@ public class MockPackageManager extends PackageManager { long idealStorageSize, IPackageDataObserver observer) { throw new UnsupportedOperationException(); } - + /** * @hide - to match hiding in superclass */ @Override public void freeStorage( - long idealStorageSize, PendingIntent onFinishedIntent) { + long idealStorageSize, IntentSender pi) { throw new UnsupportedOperationException(); } @@ -377,6 +387,16 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** + * @hide - to match hiding in superclass + */ + @Override + public void replacePreferredActivity(IntentFilter filter, + int match, ComponentName[] set, ComponentName activity) { + throw new UnsupportedOperationException(); + } + + @Override public void clearPackagePreferredActivities(String packageName) { throw new UnsupportedOperationException(); @@ -391,11 +411,6 @@ public class MockPackageManager extends PackageManager { } @Override - public void installPackage(Uri packageURI) { - throw new UnsupportedOperationException(); - } - - @Override public int getPreferredActivities(List<IntentFilter> outFilters, List<ComponentName> outActivities, String packageName) { throw new UnsupportedOperationException(); |