diff --git a/datacapturing/src/androidTest/AndroidManifest.xml b/datacapturing/src/androidTest/AndroidManifest.xml index 17e10d362..aba8dfc12 100644 --- a/datacapturing/src/androidTest/AndroidManifest.xml +++ b/datacapturing/src/androidTest/AndroidManifest.xml @@ -12,5 +12,18 @@ android:process=":persistence_process" android:syncable="true" tools:replace="android:authorities"/> + + + + + + + + + diff --git a/datacapturing/src/androidTest/java/de/cyface/datacapturing/DataCapturingServiceTest.java b/datacapturing/src/androidTest/java/de/cyface/datacapturing/DataCapturingServiceTest.java index c45944e8c..218035e4d 100644 --- a/datacapturing/src/androidTest/java/de/cyface/datacapturing/DataCapturingServiceTest.java +++ b/datacapturing/src/androidTest/java/de/cyface/datacapturing/DataCapturingServiceTest.java @@ -99,6 +99,7 @@ */ @RunWith(AndroidJUnit4.class) @LargeTest +@FlakyTest(detail = "The tests only work on the Emulator (tested w/ API 33) not on a real device") public class DataCapturingServiceTest { /** diff --git a/persistence/src/androidTest/java/de/cyface/persistence/TestUtils.java b/persistence/src/androidTest/java/de/cyface/persistence/TestUtils.java new file mode 100644 index 000000000..dda46272a --- /dev/null +++ b/persistence/src/androidTest/java/de/cyface/persistence/TestUtils.java @@ -0,0 +1,115 @@ +/* + * Copyright 2017 Cyface GmbH + * + * This file is part of the Cyface SDK for Android. + * + * The Cyface SDK for Android is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Cyface SDK for Android is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Cyface SDK for Android. If not, see . + */ +package de.cyface.persistence; + +import static junit.framework.TestCase.fail; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; + +import android.content.ContentResolver; +import android.content.ContentValues; +import android.database.Cursor; +import android.net.Uri; +import android.provider.BaseColumns; + +import de.cyface.utils.Validate; + +/** + * A utility class with static methods for supporting tests on the persistence code. + * + * @author Klemens Muthmann + * @version 2.0.3 + * @since 1.0.0 + */ +class TestUtils { + + static final String AUTHORITY = "de.cyface.persistence.test.provider"; + + private static void compareCursorWithValues(final Cursor cursor, final List contentValues) { + assertThat(contentValues.size() <= cursor.getCount(), is(equalTo(true))); + for (ContentValues values : contentValues) { + cursor.moveToNext(); + for (String key : values.keySet()) { + int cursorColumnIndex = cursor.getColumnIndex(key); + assertNotEquals(cursorColumnIndex, -1); + int dataType = cursor.getType(cursorColumnIndex); + switch (dataType) { + case Cursor.FIELD_TYPE_FLOAT: + assertEquals(values.getAsDouble(key), cursor.getDouble(cursorColumnIndex), 0.01); + break; + case Cursor.FIELD_TYPE_INTEGER: + assertEquals((long)values.getAsLong(key), cursor.getLong(cursorColumnIndex)); + break; + case Cursor.FIELD_TYPE_STRING: + assertEquals(values.getAsString(key), cursor.getString(cursorColumnIndex)); + default: + fail(); + } + } + } + } + + static long create(final ContentResolver mockResolver, final Uri contentUri, final ContentValues entry) { + final Uri result = mockResolver.insert(contentUri, entry); + Validate.notNull(result); + assertThat("Unable to create new entry.", result.getLastPathSegment(), is(not("-1"))); + Validate.notNull(result.getLastPathSegment()); + long identifier = Long.parseLong(result.getLastPathSegment()); + assertThat("Entry inserted under wrong id.", identifier > 0L, is(true)); + return identifier; + } + + static void read(final ContentResolver mockResolver, final Uri contentUri, final ContentValues entry) { + try (Cursor cursor = mockResolver.query(contentUri, null, null, null, null);) { + List fixture = new ArrayList<>(); + fixture.add(entry); + Validate.notNull(cursor); + TestUtils.compareCursorWithValues(cursor, fixture); + } + } + + static void update(final ContentResolver mockResolver, final Uri contentUri, final long identifier, + final String columnName, final double changedValue) { + ContentValues changedValues = new ContentValues(); + changedValues.put(columnName, changedValue); + + final int rowsUpdated = mockResolver.update(contentUri, changedValues, BaseColumns._ID + "=?", + new String[] {Long.valueOf(identifier).toString()}); + assertEquals("Update of rotation point was unsuccessful.", 1, rowsUpdated); + } + + static void delete(final ContentResolver mockResolver, final Uri contentUri, final long identifier) { + final int rowsDeleted = mockResolver.delete(contentUri, BaseColumns._ID + "=?", + new String[] {String.valueOf(identifier)}); + assertEquals("Delete was unsuccessful for uri " + contentUri, 1, rowsDeleted); + } + + static int count(final ContentResolver mockResolver, final Uri contentUri) { + final Cursor cursor = mockResolver.query(contentUri, null, null, null, null); + Validate.notNull(cursor); + return cursor.getCount(); + } +} diff --git a/persistence/src/test/java/de/cyface/persistence/TestUtils.java b/persistence/src/test/java/de/cyface/persistence/TestUtils.java index c5d3264a0..2b52baa9a 100644 --- a/persistence/src/test/java/de/cyface/persistence/TestUtils.java +++ b/persistence/src/test/java/de/cyface/persistence/TestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Cyface GmbH + * Copyright 2018 Cyface GmbH * * This file is part of the Cyface SDK for Android. * @@ -18,99 +18,24 @@ */ package de.cyface.persistence; -import static junit.framework.TestCase.fail; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertThat; - -import java.util.ArrayList; -import java.util.List; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; -import android.provider.BaseColumns; - -import de.cyface.utils.Validate; - /** - * A utility class with static methods for supporting tests on the persistence code. + * Contains constants and utility methods required during testing. * - * @author Klemens Muthmann - * @version 2.0.3 - * @since 1.0.0 + * @author Armin Schnabel + * @version 1.2.1 + * @since 4.0.0 */ -class TestUtils { - - static final String AUTHORITY = "de.cyface.persistence.test.provider"; - - private static void compareCursorWithValues(final Cursor cursor, final List contentValues) { - assertThat(contentValues.size() <= cursor.getCount(), is(equalTo(true))); - for (ContentValues values : contentValues) { - cursor.moveToNext(); - for (String key : values.keySet()) { - int cursorColumnIndex = cursor.getColumnIndex(key); - assertNotEquals(cursorColumnIndex, -1); - int dataType = cursor.getType(cursorColumnIndex); - switch (dataType) { - case Cursor.FIELD_TYPE_FLOAT: - assertEquals(values.getAsDouble(key), cursor.getDouble(cursorColumnIndex), 0.01); - break; - case Cursor.FIELD_TYPE_INTEGER: - assertEquals((long)values.getAsLong(key), cursor.getLong(cursorColumnIndex)); - break; - case Cursor.FIELD_TYPE_STRING: - assertEquals(values.getAsString(key), cursor.getString(cursorColumnIndex)); - default: - fail(); - } - } - } - - } - - static long create(final ContentResolver mockResolver, final Uri contentUri, final ContentValues entry) { - final Uri result = mockResolver.insert(contentUri, entry); - Validate.notNull(result); - assertThat("Unable to create new entry.", result.getLastPathSegment(), is(not("-1"))); - Validate.notNull(result.getLastPathSegment()); - long identifier = Long.parseLong(result.getLastPathSegment()); - assertThat("Entry inserted under wrong id.", identifier > 0L, is(true)); - return identifier; - } - - static void read(final ContentResolver mockResolver, final Uri contentUri, final ContentValues entry) { - try (Cursor cursor = mockResolver.query(contentUri, null, null, null, null);) { - List fixture = new ArrayList<>(); - fixture.add(entry); - Validate.notNull(cursor); - TestUtils.compareCursorWithValues(cursor, fixture); - } - } - - static void update(final ContentResolver mockResolver, final Uri contentUri, final long identifier, - final String columnName, final double changedValue) { - ContentValues changedValues = new ContentValues(); - changedValues.put(columnName, changedValue); - - final int rowsUpdated = mockResolver.update(contentUri, changedValues, BaseColumns._ID + "=?", - new String[] {Long.valueOf(identifier).toString()}); - assertEquals("Update of rotation point was unsuccessful.", 1, rowsUpdated); - } - - static void delete(final ContentResolver mockResolver, final Uri contentUri, final long identifier) { - final int rowsDeleted = mockResolver.delete(contentUri, BaseColumns._ID + "=?", - new String[] {String.valueOf(identifier)}); - assertEquals("Delete was unsuccessful for uri " + contentUri, 1, rowsDeleted); - } - - static int count(final ContentResolver mockResolver, final Uri contentUri) { - final Cursor cursor = mockResolver.query(contentUri, null, null, null, null); - Validate.notNull(cursor); - return cursor.getCount(); +public final class TestUtils { + + /** + * The content provider authority used for testing. + */ + public final static String AUTHORITY = "de.cyface.persistence.provider.test"; + + /** + * Private constructor to avoid instantiation of utility class. + */ + private TestUtils() { + // Nothing to do here. } -} +} \ No newline at end of file diff --git a/synchronization/src/androidTest/AndroidManifest.xml b/synchronization/src/androidTest/AndroidManifest.xml index edd2041cd..1e846bb25 100644 --- a/synchronization/src/androidTest/AndroidManifest.xml +++ b/synchronization/src/androidTest/AndroidManifest.xml @@ -12,5 +12,30 @@ android:process=":persistence_process" android:syncable="true" tools:replace="android:authorities"/> + + + + + + + + + + + + + + + + diff --git a/synchronization/src/androidTest/java/de/cyface/synchronization/CyfaceAuthenticatorTest.java b/synchronization/src/androidTest/java/de/cyface/synchronization/CyfaceAuthenticatorTest.java index d836bbe41..50dc4066a 100644 --- a/synchronization/src/androidTest/java/de/cyface/synchronization/CyfaceAuthenticatorTest.java +++ b/synchronization/src/androidTest/java/de/cyface/synchronization/CyfaceAuthenticatorTest.java @@ -18,6 +18,7 @@ */ package de.cyface.synchronization; +import static de.cyface.synchronization.CyfaceSyncService.AUTH_TOKEN_TYPE; import static de.cyface.synchronization.TestUtils.ACCOUNT_TYPE; import static de.cyface.synchronization.TestUtils.AUTHORITY; import static de.cyface.synchronization.TestUtils.TEST_API_URL; @@ -28,6 +29,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -57,8 +59,8 @@ */ @RunWith(AndroidJUnit4.class) @LargeTest -@FlakyTest // Flaky means (because of build.gradle) that this test is not executed in the Mock flavour (because it - // required an actual api) +// Previously disabled this test via build.gradle > FlakyTest flag. +@Ignore("Requires an actual API.") public class CyfaceAuthenticatorTest { private AccountManager accountManager; @@ -101,7 +103,7 @@ public void testGetAuthToken() throws NetworkErrorException { // Act // Explicitly calling CyfaceAuthenticator.getAuthToken(), see its documentation - Bundle bundle = new CyfaceAuthenticator(context).getAuthToken(null, requestAccount, Constants.AUTH_TOKEN_TYPE, + Bundle bundle = new CyfaceAuthenticator(context).getAuthToken(null, requestAccount, AUTH_TOKEN_TYPE, null); // Assert diff --git a/synchronization/src/androidTest/java/de/cyface/synchronization/MockAuth.java b/synchronization/src/androidTest/java/de/cyface/synchronization/MockAuth.java new file mode 100644 index 000000000..9a5ce5024 --- /dev/null +++ b/synchronization/src/androidTest/java/de/cyface/synchronization/MockAuth.java @@ -0,0 +1,57 @@ +package de.cyface.synchronization; + +import android.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.AccountManager; +import android.accounts.NetworkErrorException; +import android.content.Context; +import android.os.Bundle; + +public class MockAuth extends AbstractAccountAuthenticator { + public MockAuth(Context context) { + super(context); + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + return null; + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + + // Return a bundle containing the token + //Log.v(TAG, "Fresh authToken: **" + freshAuthToken.substring(freshAuthToken.length - 7)) + final var result = new Bundle(); + result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); + result.putString(AccountManager.KEY_AUTHTOKEN, "eyTestToken"); + return result; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return "JWT test token"; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { + return null; + } +} diff --git a/synchronization/src/androidTest/java/de/cyface/synchronization/SyncPerformerTest.java b/synchronization/src/androidTest/java/de/cyface/synchronization/SyncPerformerTest.java index e78e52b54..a13336cb0 100644 --- a/synchronization/src/androidTest/java/de/cyface/synchronization/SyncPerformerTest.java +++ b/synchronization/src/androidTest/java/de/cyface/synchronization/SyncPerformerTest.java @@ -41,6 +41,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -215,7 +216,8 @@ public void updatedProgress(float percent) { * `res/raw/truststore.jks` */ @Test - @FlakyTest // still uses an actual API. Flaky currently means it's not executed in the mock flavour test + // Previously disabled this test via build.gradle > FlakyTest flag. + @Ignore("Requires an actual API.") public void testSendData_toActualApi() throws CursorIsNullException, NoSuchMeasurementException { // Arrange diff --git a/synchronization/src/androidTest/java/de/cyface/synchronization/TestUtils.java b/synchronization/src/androidTest/java/de/cyface/synchronization/TestUtils.java new file mode 100644 index 000000000..b7b60b5a3 --- /dev/null +++ b/synchronization/src/androidTest/java/de/cyface/synchronization/TestUtils.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019 Cyface GmbH + * + * This file is part of the Cyface SDK for Android. + * + * The Cyface SDK for Android is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Cyface SDK for Android is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the Cyface SDK for Android. If not, see . + */ +package de.cyface.synchronization; + +/** + * Contains utility methods and constants required by the tests within the synchronization project. + * + * @author Klemens Muthmann + * @author Armin Schnabel + * @version 2.4.0 + * @since 2.1.0 + */ +public final class TestUtils { + /** + * The tag used to identify Logcat messages from this module. + */ + final static String TAG = Constants.TAG + ".test"; + /** + * The content provider authority used during tests. This must be the same as in the manifest and the authenticator + * configuration. + */ + final static String AUTHORITY = "de.cyface.synchronization.test.provider"; + /** + * The account type used during testing. This must be the same as in the authenticator configuration. + */ + final static String ACCOUNT_TYPE = "de.cyface.synchronization.test"; + /** + * For manual testing this can be replaced with an username available at {@link #TEST_API_URL}. + *

+ * Never use actual APIs credentials in automated tests. + */ + final static String DEFAULT_USERNAME = "REPLACE_WITH_USERNAME"; + /** + * For manual testing this can be replaced with a password available at {@link #TEST_API_URL}. + *

+ * Never use actual APIs credentials in automated tests. + */ + final static String DEFAULT_PASSWORD = "REPLACE_WITH_PASSWORD"; + /** + * For manual testing this can be replaced with a path to an API available for testing. + *

+ * Never use actual APIs in automated tests. + */ + @SuppressWarnings("unused") // because this is used in the cyface flavour + final static String TEST_API_URL = "https://replace.with/url"; // never use a non-numeric port here! +} diff --git a/synchronization/src/androidTest/java/de/cyface/synchronization/UploadProgressTest.java b/synchronization/src/androidTest/java/de/cyface/synchronization/UploadProgressTest.java index eb7d65e38..ced94efe1 100644 --- a/synchronization/src/androidTest/java/de/cyface/synchronization/UploadProgressTest.java +++ b/synchronization/src/androidTest/java/de/cyface/synchronization/UploadProgressTest.java @@ -20,6 +20,7 @@ import static de.cyface.persistence.Utils.getGeoLocationsUri; import static de.cyface.synchronization.BundlesExtrasCodes.SYNC_PERCENTAGE_ID; +import static de.cyface.synchronization.CyfaceSyncService.AUTH_TOKEN_TYPE; import static de.cyface.synchronization.SyncAdapter.MOCK_IS_CONNECTED_TO_RETURN_TRUE; import static de.cyface.synchronization.TestUtils.ACCOUNT_TYPE; import static de.cyface.synchronization.TestUtils.AUTHORITY; @@ -40,9 +41,13 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import android.accounts.AbstractAccountAuthenticator; import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; import android.accounts.AccountManager; +import android.accounts.NetworkErrorException; import android.content.BroadcastReceiver; import android.content.ContentProvider; import android.content.ContentProviderClient; @@ -113,7 +118,8 @@ public void setUp() throws CursorIsNullException { account = new Account(TestUtils.DEFAULT_USERNAME, ACCOUNT_TYPE); accountManager.addAccountExplicitly(account, TestUtils.DEFAULT_PASSWORD, null); - oocut = new SyncAdapter(context, false, new MockedHttpConnection()); + oocut = new SyncAdapter(context, false, new MockedHttpConnection(), + AUTH_TOKEN_TYPE, new MockAuth(context)); } @After