Skip to content

Commit

Permalink
Fix the connected tests (disable tests which where skipped before by …
Browse files Browse the repository at this point in the history
…FlakyTest flag)
  • Loading branch information
hb0 committed Mar 20, 2024
1 parent ab9b347 commit 718d5f1
Show file tree
Hide file tree
Showing 10 changed files with 306 additions and 98 deletions.
13 changes: 13 additions & 0 deletions datacapturing/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,18 @@
android:process=":persistence_process"
android:syncable="true"
tools:replace="android:authorities"/>

<!-- Some connected Android tests needs this to create a test account, or else we get -->
<!-- SecurityException: ... cannot explicitly add accounts of type: ... -->
<service android:name="de.cyface.synchronization.CyfaceAuthenticatorService"
android:exported="false"
android:process=":sync"> <!-- should be fine to use the sync process -->
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

/**
Expand Down
115 changes: 115 additions & 0 deletions persistence/src/androidTest/java/de/cyface/persistence/TestUtils.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
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> 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<ContentValues> 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();
}
}
111 changes: 18 additions & 93 deletions persistence/src/test/java/de/cyface/persistence/TestUtils.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017 Cyface GmbH
* Copyright 2018 Cyface GmbH
*
* This file is part of the Cyface SDK for Android.
*
Expand All @@ -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> 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<ContentValues> 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.
}
}
}
25 changes: 25 additions & 0 deletions synchronization/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,30 @@
android:process=":persistence_process"
android:syncable="true"
tools:replace="android:authorities"/>

<!-- Some connected synchronization Android tests need this for the test sync to start -->
<service
android:name="de.cyface.synchronization.CyfaceSyncService"
android:exported="false"
android:process=":sync">
<intent-filter>
<action android:name="android.content.SyncAdapter" />
</intent-filter>
<meta-data
android:name="android.content.SyncAdapter"
android:resource="@xml/sync_adapter" />
</service>
<!-- Some connected Android tests need this to create a test account, or else we get -->
<!-- SecurityException: ... cannot explicitly add accounts of type: ... -->
<service android:name="de.cyface.synchronization.CyfaceAuthenticatorService"
android:exported="false"
android:process=":sync"> <!-- should be fine to use the sync process -->
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
</application>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Loading

0 comments on commit 718d5f1

Please sign in to comment.