From f1fbab7dd9c5997dd80317523a2345f9e5c32661 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 27 Apr 2017 07:52:11 +0200 Subject: [PATCH] Revert "Revert "Adjust test case setup and fix failing tests"" This reverts commit b0384e90d520de645a2a60e543359a2bfa10d9b7. --- .../gadgetbridge/GBApplication.java | 39 +++++- .../gadgetbridge/GBEnvironment.java | 15 ++ .../gadgetbridge/LockHandler.java | 5 +- .../externalevents/CalendarReceiver.java | 131 +++++++++--------- .../gadgetbridge/util/FileUtils.java | 9 +- .../freeyourgadget/gadgetbridge/util/GB.java | 11 +- .../gadgetbridge/test/CalendarEventTest.java | 2 + .../gadgetbridge/test/LoggingTest.java | 12 +- .../gadgetbridge/test/TestBase.java | 19 ++- 9 files changed, 139 insertions(+), 104 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index baabf5d19..69b6efc1e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -88,11 +88,18 @@ public class GBApplication extends Application { public static final String ACTION_QUIT = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; + + private static GBApplication app; + private static Logging logging = new Logging() { @Override protected String createLogDirectory() throws IOException { - File dir = FileUtils.getExternalFilesDir(); - return dir.getAbsolutePath(); + if (GBEnvironment.env().isLocalTest()) { + return System.getProperty(Logging.PROP_LOGFILES_DIR); + } else { + File dir = FileUtils.getExternalFilesDir(); + return dir.getAbsolutePath(); + } } }; @@ -110,12 +117,17 @@ public class GBApplication extends Application { // don't do anything here, add it to onCreate instead } + public static Logging getLogging() { + return logging; + } + protected DeviceService createDeviceService() { return new GBDeviceService(this); } @Override public void onCreate() { + app = this; super.onCreate(); if (lockHandler != null) { @@ -137,9 +149,12 @@ public class GBApplication extends Application { setupExceptionHandler(); - GB.environment = GBEnvironment.createDeviceEnvironment(); - - setupDatabase(this); + if (!GBEnvironment.isEnvironmentSetup()) { + GBEnvironment.setupEnvironment(GBEnvironment.createDeviceEnvironment()); + // setup db after the environment is set up, but don't do it in test mode + // in test mode, it's done individually, see TestBase + setupDatabase(); + } deviceManager = new DeviceManager(this); @@ -195,8 +210,14 @@ public class GBApplication extends Application { return prefs.getBoolean("minimize_priority", false); } - static void setupDatabase(Context context) { - DBOpenHelper helper = new DBOpenHelper(context, DATABASE_NAME, null); + public void setupDatabase() { + DaoMaster.OpenHelper helper; + GBEnvironment env = GBEnvironment.env(); + if (env.isTest()) { + helper = new DaoMaster.DevOpenHelper(this, null, null); + } else { + helper = new DBOpenHelper(this, DATABASE_NAME, null); + } SQLiteDatabase db = helper.getWritableDatabase(); DaoMaster daoMaster = new DaoMaster(db); if (lockHandler == null) { @@ -471,4 +492,8 @@ public class GBApplication extends Application { public DeviceManager getDeviceManager() { return deviceManager; } + + public static GBApplication app() { + return app; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java index 315cdddeb..571a0bbc0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBEnvironment.java @@ -20,6 +20,10 @@ package nodomain.freeyourgadget.gadgetbridge; * Some more or less useful utility methods to aid local (non-device) testing. */ public class GBEnvironment { +// DO NOT USE A LOGGER HERE. Will break LoggingTest! +// private static final Logger LOG = LoggerFactory.getLogger(GBEnvironment.class); + + private static GBEnvironment environment; private boolean localTest; private boolean deviceTest; @@ -41,4 +45,15 @@ public class GBEnvironment { return localTest; } + public static synchronized GBEnvironment env() { + return environment; + } + + static synchronized boolean isEnvironmentSetup() { + return environment != null; + } + + public synchronized static void setupEnvironment(GBEnvironment env) { + environment = env; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java index 1d72efecb..d5aff21ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/LockHandler.java @@ -20,7 +20,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; -import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper; import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -36,7 +35,7 @@ public class LockHandler implements DBHandler { public LockHandler() { } - public void init(DaoMaster daoMaster, DBOpenHelper helper) { + public void init(DaoMaster daoMaster, DaoMaster.OpenHelper helper) { if (isValid()) { throw new IllegalStateException("DB must be closed before initializing it again"); } @@ -82,7 +81,7 @@ public class LockHandler implements DBHandler { throw new IllegalStateException("session must be null"); } // this will create completely new db instances and in turn update this handler through #init() - GBApplication.setupDatabase(GBApplication.getContext()); + GBApplication.app().setupDatabase(); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java index 62bfa003a..5d5382483 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/CalendarReceiver.java @@ -34,6 +34,7 @@ import java.util.List; import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncState; @@ -97,76 +98,76 @@ public class CalendarReceiver extends BroadcastReceiver { } public void syncCalendar(List eventList) { - LOG.info("Syncing with calendar."); - Hashtable eventTable = new Hashtable<>(); - try (DBHandler dbHandler = GBApplication.acquireDB()) { DaoSession session = dbHandler.getDaoSession(); - Long deviceId = DBHelper.getDevice(mGBDevice, session).getId(); - - QueryBuilder qb = session.getCalendarSyncStateDao().queryBuilder(); - - - for (CalendarEvents.CalendarEvent e : eventList) { - long id = e.getId(); - eventTable.put(id, e); - if (!eventState.containsKey(e.getId())) { - qb = session.getCalendarSyncStateDao().queryBuilder(); - - CalendarSyncState calendarSyncState = qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(id))) - .build().unique(); - if (calendarSyncState == null) { - eventState.put(id, new EventSyncState(e, EventState.NOT_SYNCED)); - LOG.info("event id=" + id + " is yet unknown to device id=" + deviceId); - } else if (calendarSyncState.getHash() == e.hashCode()) { - eventState.put(id, new EventSyncState(e, EventState.SYNCED)); - LOG.info("event id=" + id + " is up to date on device id=" + deviceId); - } - else { - eventState.put(id, new EventSyncState(e, EventState.NEEDS_UPDATE)); - LOG.info("event id=" + id + " is not up to date on device id=" + deviceId); - } - } - } - - // add all missing calendar ids on the device to sync status (so that they are deleted later) - List CalendarSyncStateList = qb.where(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId)).build().list(); - for (CalendarSyncState CalendarSyncState : CalendarSyncStateList) { - if (!eventState.containsKey(CalendarSyncState.getCalendarEntryId())) { - eventState.put(CalendarSyncState.getCalendarEntryId(), new EventSyncState(null, EventState.NEEDS_DELETE)); - LOG.info("insert null event for orphanded calendar id=" + CalendarSyncState.getCalendarEntryId() + " for device=" + mGBDevice.getName()); - } - } - - Enumeration ids = eventState.keys(); - while (ids.hasMoreElements()) { - qb = session.getCalendarSyncStateDao().queryBuilder(); - Long i = ids.nextElement(); - EventSyncState es = eventState.get(i); - if (eventTable.containsKey(i)) { - if (es.getState() == EventState.SYNCED) { - if (!es.getEvent().equals(eventTable.get(i))) { - eventState.put(i, new EventSyncState(eventTable.get(i), EventState.NEEDS_UPDATE)); - } - } - } else { - if (es.getState() == EventState.NOT_SYNCED) { - // delete for current device only - qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(i))) - .buildDelete().executeDeleteWithoutDetachingEntities(); - eventState.remove(i); - } else { - es.setState(EventState.NEEDS_DELETE); - eventState.put(i, es); - } - } - updateEvents(deviceId, session); - } - } catch (Exception e) { - e.printStackTrace(); + syncCalendar(eventList, session); + } catch (Exception e1) { GB.toast("Database Error while syncing Calendar", Toast.LENGTH_SHORT, GB.ERROR); } + } + public void syncCalendar(List eventList, DaoSession session) { + LOG.info("Syncing with calendar."); + Hashtable eventTable = new Hashtable<>(); + Long deviceId = DBHelper.getDevice(mGBDevice, session).getId(); + QueryBuilder qb = session.getCalendarSyncStateDao().queryBuilder(); + + + for (CalendarEvents.CalendarEvent e : eventList) { + long id = e.getId(); + eventTable.put(id, e); + if (!eventState.containsKey(e.getId())) { + qb = session.getCalendarSyncStateDao().queryBuilder(); + + CalendarSyncState calendarSyncState = qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(id))) + .build().unique(); + if (calendarSyncState == null) { + eventState.put(id, new EventSyncState(e, EventState.NOT_SYNCED)); + LOG.info("event id=" + id + " is yet unknown to device id=" + deviceId); + } else if (calendarSyncState.getHash() == e.hashCode()) { + eventState.put(id, new EventSyncState(e, EventState.SYNCED)); + LOG.info("event id=" + id + " is up to date on device id=" + deviceId); + } + else { + eventState.put(id, new EventSyncState(e, EventState.NEEDS_UPDATE)); + LOG.info("event id=" + id + " is not up to date on device id=" + deviceId); + } + } + } + + // add all missing calendar ids on the device to sync status (so that they are deleted later) + List CalendarSyncStateList = qb.where(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId)).build().list(); + for (CalendarSyncState CalendarSyncState : CalendarSyncStateList) { + if (!eventState.containsKey(CalendarSyncState.getCalendarEntryId())) { + eventState.put(CalendarSyncState.getCalendarEntryId(), new EventSyncState(null, EventState.NEEDS_DELETE)); + LOG.info("insert null event for orphanded calendar id=" + CalendarSyncState.getCalendarEntryId() + " for device=" + mGBDevice.getName()); + } + } + + Enumeration ids = eventState.keys(); + while (ids.hasMoreElements()) { + qb = session.getCalendarSyncStateDao().queryBuilder(); + Long i = ids.nextElement(); + EventSyncState es = eventState.get(i); + if (eventTable.containsKey(i)) { + if (es.getState() == EventState.SYNCED) { + if (!es.getEvent().equals(eventTable.get(i))) { + eventState.put(i, new EventSyncState(eventTable.get(i), EventState.NEEDS_UPDATE)); + } + } + } else { + if (es.getState() == EventState.NOT_SYNCED) { + // delete for current device only + qb.where(qb.and(CalendarSyncStateDao.Properties.DeviceId.eq(deviceId), CalendarSyncStateDao.Properties.CalendarEntryId.eq(i))) + .buildDelete().executeDeleteWithoutDetachingEntities(); + eventState.remove(i); + } else { + es.setState(EventState.NEEDS_DELETE); + eventState.put(i, es); + } + } + updateEvents(deviceId, session); + } } private void updateEvents(Long deviceId, DaoSession session) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index ba6150f01..117887341 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; public class FileUtils { // Don't use slf4j here -- would be a bootstrapping problem @@ -209,9 +210,11 @@ public class FileUtils { // the first directory is also the primary external storage, i.e. the same as Environment.getExternalFilesDir() // TODO: check the mount state of *all* dirs when switching to later API level - if (i == 0 && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - GB.log("ignoring unmounted external storage dir: " + dir, GB.INFO, null); - continue; + if (!GBEnvironment.env().isLocalTest()) { // don't do this with robolectric + if (i == 0 && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + GB.log("ignoring unmounted external storage dir: " + dir, GB.INFO, null); + continue; + } } result.add(dir); // add last } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 42d4fd41d..1a75cd7f0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -60,10 +60,9 @@ public class GB { public static final String DISPLAY_MESSAGE_MESSAGE = "message"; public static final String DISPLAY_MESSAGE_DURATION = "duration"; public static final String DISPLAY_MESSAGE_SEVERITY = "severity"; - public static GBEnvironment environment; public static Notification createNotification(String text, boolean connected, Context context) { - if (env().isLocalTest()) { + if (GBEnvironment.env().isLocalTest()) { return null; } Intent notificationIntent = new Intent(context, ControlCenterv2.class); @@ -227,7 +226,7 @@ public class GB { */ public static void toast(final Context context, final String message, final int displayTime, final int severity, final Throwable ex) { log(message, severity, ex); // log immediately, not delayed - if (env().isLocalTest()) { + if (GBEnvironment.env().isLocalTest()) { return; } Looper mainLooper = Looper.getMainLooper(); @@ -358,7 +357,7 @@ public class GB { } public static void updateBatteryNotification(String text, String bigText, Context context) { - if (env().isLocalTest()) { + if (GBEnvironment.env().isLocalTest()) { return; } Notification notification = createBatteryNotification(text, bigText, context); @@ -369,10 +368,6 @@ public class GB { removeNotification(NOTIFICATION_ID_LOW_BATTERY, context); } - public static GBEnvironment env() { - return environment; - } - public static void assertThat(boolean condition, String errorMessage) { if (!condition) { throw new AssertionError(errorMessage); diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java index 7e7352397..370afe5f3 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/CalendarEventTest.java @@ -6,7 +6,9 @@ import org.junit.Test; import java.util.ArrayList; import java.util.List; +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java index bd586669c..25adcfea3 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/LoggingTest.java @@ -6,8 +6,8 @@ import org.junit.After; import org.junit.Test; import java.io.File; -import java.io.IOException; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; @@ -25,16 +25,12 @@ public class LoggingTest extends TestBase { public LoggingTest() throws Exception { } - private Logging logging = new Logging() { - @Override - protected String createLogDirectory() throws IOException { - return logFilesDir.getAbsolutePath(); - } - }; + private Logging logging = GBApplication.getLogging(); @Override @After - public void tearDown() { + public void tearDown() throws Exception { + super.tearDown(); assertTrue(FileUtils.deleteRecursively(getLogFilesDir())); } diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java index 298c1c382..636f1077c 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/test/TestBase.java @@ -1,7 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.test; import android.content.Context; -import android.database.sqlite.SQLiteDatabase; import org.junit.After; import org.junit.Before; @@ -16,9 +15,9 @@ import java.io.File; import ch.qos.logback.classic.util.ContextInitializer; import nodomain.freeyourgadget.gadgetbridge.BuildConfig; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; import nodomain.freeyourgadget.gadgetbridge.Logging; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; -import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; @@ -46,9 +45,10 @@ public abstract class TestBase { // Make sure logging is set up for all testcases, so that we can debug problems @BeforeClass public static void setupSuite() throws Exception { + GBEnvironment.setupEnvironment(GBEnvironment.createLocalTestEnvironment()); + // print everything going to android.util.Log to System.out System.setProperty("robolectric.logging", "stdout"); -// ShadowLog.stream = System.out; // properties might be preconfigured in build.gradle because of test ordering problems String logDir = System.getProperty(Logging.PROP_LOGFILES_DIR); @@ -69,20 +69,19 @@ public abstract class TestBase { @Before public void setUp() throws Exception { + app = (GBApplication) RuntimeEnvironment.application; assertNotNull(app); assertNotNull(getContext()); -// doesn't work with Robolectric yet -// dbHandler = GBApplication.acquireDB(); -// daoSession = dbHandler.getDaoSession(); - DaoMaster.DevOpenHelper openHelper = new DaoMaster.DevOpenHelper(app, null, null); - SQLiteDatabase db = openHelper.getWritableDatabase(); - daoSession = new DaoMaster(db).newSession(); + app.setupDatabase(); + dbHandler = GBApplication.acquireDB(); + daoSession = dbHandler.getDaoSession(); assertNotNull(daoSession); } @After public void tearDown() throws Exception { -// GBApplication.releaseDB(); + dbHandler.closeDb(); + GBApplication.releaseDB(); } protected GBDevice createDummyGDevice(String macAddress) {