Skip to content

Commit

Permalink
[STAD-578] Remove flavors and fix emulator in CI
Browse files Browse the repository at this point in the history
Remove flavor dimentions
  • Loading branch information
hb0 authored Mar 20, 2024
2 parents 0461707 + be2d00a commit 038aa5b
Show file tree
Hide file tree
Showing 62 changed files with 384 additions and 872 deletions.
68 changes: 58 additions & 10 deletions .github/workflows/gradle_connected-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,46 @@ on:
- 'release-6'

jobs:
build:
androidTest:
# Faster, but MacOS costs 8 ct/min instead of 0.8 ct/min of on Linux.
# Unfortunately, `DataCapturingServiceTest.testDisconnectReconnect` fails on linux stack.
# But as this is a public repository, Github Actions are currently free of charge.
runs-on: macos-latest # as recommended in `actions/android-emulator-runner`
#runs-on: macos-latest # as recommended in `actions/android-emulator-runner`

# To test against multiple APIs
# But we had to add `free-disk-space` to fix emulator flakiness. It only runs on ubuntu.
runs-on: ubuntu-latest

timeout-minutes: 55
strategy:
matrix:
api-level: [ 28 ]

steps:
- uses: actions/checkout@v3
# From https://github.com/android/nowinandroid/pull/1219/files to fix flaky emulator start
# See https://github.com/ReactiveCircus/android-emulator-runner/issues/324#issuecomment-1998737488
- name: Delete unnecessary tools 🔧
uses: jlumbroso/free-disk-space@v1.3.1
with:
android: false # Keep Don't remove Android tools
tool-cache: true # Remove image tool cache - rm -rf "$AGENT_TOOLSDIRECTORY"
dotnet: true # rm -rf /usr/share/dotnet
haskell: true # rm -rf /opt/ghc...
swap-storage: true # rm -f /mnt/swapfile (4GiB)
docker-images: false # Takes 16s (`nowinandroid`), enable if needed in the future
large-packages: false # includes google-cloud-sdk and it's slow

# Set up KVM permissions to enable efficient Android emulator runs by modifying udev rules for universal access.
# From https://github.com/android/nowinandroid/blob/main/.github/workflows/Build.yaml#L142
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
ls /dev/kvm
- name: Checkout
uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v3
with:
Expand All @@ -51,8 +78,9 @@ jobs:
# run: ./gradlew build

# Add caching to speed up connected tests below (see `actions/android-emulator-runner`)
- name: Gradle cache
uses: gradle/gradle-build-action@v2
- name: Setup Gradle
uses: gradle/gradle-build-action@v3

- name: AVD cache
uses: actions/cache@v3
id: avd-cache
Expand All @@ -70,14 +98,34 @@ jobs:
disable-animations: true
script: echo "Generated AVD snapshot for caching."

# From https://github.com/android/nowinandroid/blob/main/.github/workflows/Build.yaml#L142
- name: Build projects before running emulator
run: ./gradlew packageDebugAndroidTest

# Only execute mock tests to exclude `@FlakyTest`s (instead of running `connectedCheck`)
- name: Connected tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: ${{ matrix.api-level }}
force-avd-creation: false
emulator-options: -no-snapshot-save
# From https://github.com/android/nowinandroid >>>
arch: x86_64
disable-animations: true
script: ./gradlew :persistence:connectedDebugAndroidTest :datacapturing:connectedCyfaceMockDebugAndroidTest :synchronization:connectedCyfaceMockDebugAndroidTest :datacapturing:connectedMovebisMockDebugAndroidTest :synchronization:connectedMovebisMockDebugAndroidTest
disk-size: 6000M
heap-size: 600M
# <<<<
# default options are: -no-window -gpu swiftshader_indirect -no-snapshot -noaudio -no-boot-anim
# Action recommendation: -no-snapshot-save -camera-back none
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
#avd-name: ubuntu-avd-28
#force-avd-creation: false
script: ./gradlew :persistence:connectedDebugAndroidTest :datacapturing:connectedDebugAndroidTest :synchronization:connectedDebugAndroidTest --daemon
# To execute a single test class
#script: ./gradlew :datacapturing:connectedCyfaceMockDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=de.cyface.datacapturing.DataCapturingServiceTest
#script: ./gradlew :datacapturing:connectedCyfaceMockDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=de.cyface.datacapturing.DataCapturingServiceTest --daemon

# From https://github.com/android/nowinandroid/blob/main/.github/workflows/Build.yaml#L142
- name: Upload test reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports-${{ matrix.api-level }}
path: '**/build/reports/androidTests'
55 changes: 47 additions & 8 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,8 @@ To use it as a dependency in your app you need to:
+
----
dependencies {
# To use the 'movebis' flavour, use: 'datacapturingMovebis'
implementation "de.cyface:datacapturing:$cyfaceBackendVersion"
# To use the 'movebis' flavour, use: 'synchronizationMovebis'
implementation "de.cyface:synchronization:$cyfaceBackendVersion"
# There is only one 'persistence' flavor
implementation "de.cyface:persistence:$cyfaceBackendVersion"
}
----
Expand Down Expand Up @@ -102,6 +99,48 @@ This SDK is compatible with our https://github.com/cyface-de/data-collector/rele

The following steps are required before you can start coding.

[[authenticator-and-sync-service]]]
==== Authenticator- and Sync Service

The SDK provides the CyfaceAuthenticatorService and CyfaceSyncService which authenticates with and uploads data
to a Cyface Collector API. The SDK implementing app can also implement services for different APIs.

Register the Authenticator- and Sync service which should be called by the system in the SDK
implementing app's `AndroidManifest.xml`, e.g. for the default implementations:

[source,xml]
----
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name="de.cyface.synchronization.CyfaceAuthenticatorService"
android:exported="false"
android:process=":sync">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" />
</service>
<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>
</application>
</manifest>
----

[[truststore]]
==== Truststore

Expand Down Expand Up @@ -151,7 +190,7 @@ application separately.
</manifest>
----

* Define your authority which you must use as parameter in `new Cyface/MovebisDataCapturingService()` (see sample below).
* Define your authority which you must use as parameter in `new Cyface/CustomDataCapturingService()` (see sample below).
This must be the same as defined in the `AndroidManifest.xml` above.

[source,java]
Expand Down Expand Up @@ -180,11 +219,11 @@ public class Constants {

The core of our SDK is the `DataCapturingService` which controls the capturing process.

We provide two interfaces for this service: `CyfaceDataCapturingService` and `MovebisDataCapturingService`.
Unless you are part of the _Movebis project_ `CyfaceDataCapturingService` is your candidate.
We provide a default interfaces for this service: `CyfaceDataCapturingService`.
Unless you need a custom `DataCapturingService` extension, use this one.

To keep this documentation lightweight, we currently only use `MovebisDataCapturingService` in the samples
but the interface for `CyfaceDataCapturingService` is mostly the same.
NOTE: This documentation is out of date as describes a former extension `MovebisDataCapturingService`
in the samples but the interface for `CyfaceDataCapturingService` is mostly the same.

The following steps are required to communicate with this service.

Expand Down
28 changes: 1 addition & 27 deletions datacapturing/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ plugins {
// use `:datacapturing:publishToMavenLocal` instead of `publishToMavenLocal` (see custom task `publishAll`)
// Don't move to root `build.gradle` as this forces SDK and camera_service to define this, too.
// Keep version in sync with other modules!
id 'de.cyface.android-publish' version '1.0.8' // Keep version in sync with other modules!
id 'de.cyface.android-publish' version '1.1.0' // Keep version in sync with other modules!
}

android {
Expand All @@ -43,32 +43,6 @@ android {
testInstrumentationRunner rootProject.ext.testInstrumentationRunner
}

// Specifies the flavor dimensions you want to use. The order in which you
// list each dimension determines its priority, from highest to lowest,
// when Gradle merges variant sources and configurations. You must assign
// each product flavor you configure to one of the flavor dimensions.
flavorDimensions "project", "mode"

productFlavors {
// Configurations in the "project" product flavors override those in "mode"
// flavors and the defaultConfig block. Gradle determines the priority
// between flavor dimensions based on the order in which they appear next
// to the flavorDimensions property above--the first dimension has a higher
// priority than the second, and so on.
movebis {
dimension "project"
}
cyface {
dimension "project"
}
mock {
dimension "mode"
}
full {
dimension "mode"
}
}

buildTypes {
release {
// Enable in app module to generate a single mapping.xml which can be uploaded to PlayStore
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@
package de.cyface.datacapturing;

import static de.cyface.datacapturing.Constants.TAG;
import static de.cyface.synchronization.Constants.AUTH_TOKEN_TYPE;

import java.util.ArrayList;
import java.util.List;

import android.Manifest;
import android.accounts.Account;
Expand All @@ -40,6 +36,9 @@
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import java.util.ArrayList;
import java.util.List;

import de.cyface.datacapturing.backend.DataCapturingBackgroundService;
import de.cyface.datacapturing.exception.CorruptedMeasurementException;
import de.cyface.datacapturing.exception.DataCapturingException;
Expand Down Expand Up @@ -71,7 +70,7 @@
* <p>
* Before you try to measure any data you should provide a valid JWT auth token for data synchronization. You may do
* this using {@link #registerJWTAuthToken(String, String)} with a token for a certain username. To anonymize the user
* is ok to use some garbage username here. If a user is no longer required, you can deregister it using
* is ok to use a dummy username here. If a user is no longer required, you can deregister using
* {@link #deregisterJWTAuthToken(String)}.
*
* @author Klemens Muthmann
Expand All @@ -87,6 +86,7 @@ public class MovebisDataCapturingService extends DataCapturingService {
* running.
*/
private final LocationManager preMeasurementLocationManager;
private final static String AUTH_TOKEN_TYPE = "de.cyface.jwt";
/**
* A listener for location updates, which it passes through to the user interface.
*/
Expand Down Expand Up @@ -153,9 +153,9 @@ public void onProviderDisabled(String provider) {
*/
@SuppressWarnings({"WeakerAccess", "RedundantSuppression"}) // Used by SDK implementing apps (SR)
public MovebisDataCapturingService(@NonNull final Context context, @NonNull final String dataUploadServerAddress,
@NonNull final UIListener uiListener, final long locationUpdateRate,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency)
@NonNull final UIListener uiListener, final long locationUpdateRate,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency)
throws SetupException, CursorIsNullException {
this(context, "de.cyface.provider", "de.cyface", dataUploadServerAddress, uiListener, locationUpdateRate,
eventHandlingStrategy, capturingListener, sensorFrequency);
Expand Down Expand Up @@ -194,10 +194,10 @@ public MovebisDataCapturingService(@NonNull final Context context, @NonNull fina
* @throws CursorIsNullException If {@link ContentProvider} was inaccessible.
*/
MovebisDataCapturingService(@NonNull final Context context, @NonNull final String authority,
@NonNull final String accountType, @NonNull final String dataUploadServerAddress,
@NonNull final UIListener uiListener, final long locationUpdateRate,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency)
@NonNull final String accountType, @NonNull final String dataUploadServerAddress,
@NonNull final UIListener uiListener, final long locationUpdateRate,
@NonNull final EventHandlingStrategy eventHandlingStrategy,
@NonNull final DataCapturingListener capturingListener, final int sensorFrequency)
throws SetupException, CursorIsNullException {
super(context, authority, accountType, dataUploadServerAddress, eventHandlingStrategy,
new PersistenceLayer<>(context, context.getContentResolver(), authority,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
*/
@RunWith(AndroidJUnit4.class)
@MediumTest
public class DataCapturingBackgroundServiceTest {
public class DataCapturingBackgroundServiceAndroidTest {

/**
* Junit rule handling the service connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void shutdownDataCapturingService() throws SynchronisationException {
@SuppressWarnings("unused") // This is called by the SDK implementing app after an account was created
public void startWifiSurveyor() throws SetupException {
try {
// We require SDK users (other than Movebis) to always have exactly one account available
// We require SDK users (other than SR) to always have exactly one account available
final Account account = getWiFiSurveyor().getAccount();
getWiFiSurveyor().startSurveillance(account);
} catch (SynchronisationException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
import de.cyface.persistence.model.Modality;
import de.cyface.synchronization.ConnectionStatusListener;
import de.cyface.synchronization.ConnectionStatusReceiver;
import de.cyface.synchronization.SyncService;
import de.cyface.synchronization.SyncAdapter;
import de.cyface.synchronization.WiFiSurveyor;
import de.cyface.utils.CursorIsNullException;
import de.cyface.utils.Validate;
Expand Down Expand Up @@ -259,7 +259,7 @@ public DataCapturingService(@NonNull final Context context, @NonNull final Strin

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor sharedPreferencesEditor = preferences.edit();
sharedPreferencesEditor.putString(SyncService.SYNC_ENDPOINT_URL_SETTINGS_KEY, dataUploadServerAddress);
sharedPreferencesEditor.putString(SyncAdapter.SYNC_ENDPOINT_URL_SETTINGS_KEY, dataUploadServerAddress);
if (!sharedPreferencesEditor.commit()) {
throw new SetupException("Unable to write preferences!");
}
Expand Down
24 changes: 0 additions & 24 deletions datacapturing/src/main/res/values-it/strings.xml

This file was deleted.

3 changes: 0 additions & 3 deletions documentation/migration-guide_5.0.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,8 @@ To use it as a dependency in your app you need to:
+
----
dependencies {
# To use the 'movebis' flavour, use: 'datacapturingMovebis'
implementation "de.cyface:datacapturing:$cyfaceBackendVersion"
# To use the 'movebis' flavour, use: 'synchronizationMovebis'
implementation "de.cyface:synchronization:$cyfaceBackendVersion"
# There is only one 'persistence' flavor
implementation "de.cyface:persistence:$cyfaceBackendVersion"
}
----
Expand Down
Loading

0 comments on commit 038aa5b

Please sign in to comment.