michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: package org.mozilla.gecko.background.helpers; michael@0: michael@0: import android.app.AlarmManager; michael@0: import android.app.PendingIntent; michael@0: import android.app.Service; michael@0: import android.content.Context; michael@0: import android.content.Intent; michael@0: import android.content.SharedPreferences; michael@0: import android.test.ServiceTestCase; michael@0: import java.util.concurrent.BrokenBarrierException; michael@0: import java.util.concurrent.CyclicBarrier; michael@0: import java.util.UUID; michael@0: michael@0: import org.mozilla.gecko.background.common.GlobalConstants; michael@0: michael@0: /** michael@0: * An abstract test class for testing background services. Since we have to wait for background michael@0: * services to finish before asserting the changed state, this class provides much of the michael@0: * functionality to do this. Extending classes need still need to implement some of the components - michael@0: * see {@link TestHealthReportBroadcastService} for an example. michael@0: */ michael@0: public abstract class BackgroundServiceTestCase extends ServiceTestCase { michael@0: private static final String SHARED_PREFS_PREFIX = "BackgroundServiceTestCase-"; michael@0: // Ideally, this would not be static so multiple test classes can be run in parallel. However, michael@0: // mServiceClass can only retrieve this reference statically because mServiceClass cannot get a michael@0: // reference to the Test* class as ServiceTestCase instantiates it via reflection and we can't michael@0: // pass it as a constructor arg. michael@0: protected static String sharedPrefsName; michael@0: michael@0: private final Class mServiceClass; michael@0: michael@0: protected static CyclicBarrier barrier; michael@0: protected Intent intent; michael@0: michael@0: public BackgroundServiceTestCase(Class serviceClass) { michael@0: super(serviceClass); michael@0: mServiceClass = serviceClass; michael@0: } michael@0: michael@0: @Override michael@0: public void setUp() throws Exception { michael@0: barrier = new CyclicBarrier(2); michael@0: intent = new Intent(getContext(), mServiceClass); michael@0: sharedPrefsName = SHARED_PREFS_PREFIX + mServiceClass.getName() + "-" + UUID.randomUUID(); michael@0: } michael@0: michael@0: @Override michael@0: public void tearDown() throws Exception { michael@0: barrier = null; michael@0: intent = null; michael@0: clearSharedPrefs(); // Not necessary but reduces file system cruft. michael@0: } michael@0: michael@0: protected SharedPreferences getSharedPreferences() { michael@0: return getContext().getSharedPreferences(sharedPrefsName, michael@0: GlobalConstants.SHARED_PREFERENCES_MODE); michael@0: } michael@0: michael@0: protected void clearSharedPrefs() { michael@0: getSharedPreferences().edit() michael@0: .clear() michael@0: .commit(); michael@0: } michael@0: michael@0: protected void await() { michael@0: try { michael@0: barrier.await(); michael@0: } catch (InterruptedException e) { michael@0: fail("Test runner thread should not be interrupted."); michael@0: } catch (BrokenBarrierException e) { michael@0: fail("Background services should not timeout or be interrupted"); michael@0: } michael@0: } michael@0: michael@0: protected void cancelAlarm(Intent intent) { michael@0: final AlarmManager am = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); michael@0: final PendingIntent pi = PendingIntent.getService(getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); michael@0: am.cancel(pi); michael@0: pi.cancel(); michael@0: } michael@0: michael@0: protected boolean isServiceAlarmSet(Intent intent) { michael@0: return PendingIntent.getService(getContext(), 0, intent, PendingIntent.FLAG_NO_CREATE) != null; michael@0: } michael@0: }