Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: more targets #384

Draft
wants to merge 16 commits into
base: staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 36 additions & 16 deletions .github/workflows/build_and_test_sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ on:
- staging

jobs:
setup:
test:
runs-on: ubuntu-latest
name: Build and Test the SDK
strategy:
fail-fast: false
matrix:
api-level: [21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]

steps:
- name: Install Docker to the Runner
run: sudo apt-get install docker

- name: Pull Emulator from the Repo
run: docker pull ${{ env.EMULATOR_REPO }}

- name: Checkout SDK code
uses: actions/checkout@v4

Expand All @@ -40,18 +38,36 @@ jobs:
java-version: ${{ env.JAVA_V }}
distribution: ${{ env.JAVA_DIST }}

- name: Enable KVM
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

- name: Setup Android SDK
uses: android-actions/[email protected]
with:
api-level: ${{ matrix.api-level }}
target: 'google-apis'
arch: 'x86_64'
channel: 'stable'

- name: Start ADB Server
run: adb start-server

- name: Run Android Emulator Container
run: docker run -d -e "ADBKEY=$(cat ~/.android/adbkey)" --device /dev/kvm --publish 5555:5555/tcp ${{ env.EMULATOR_REPO }}

- name: Connect to the Emulator
run: adb connect localhost:5555

- name: Set up AVD (Android Virtual Device)
run: |
sudo apt-get update
sudo apt-get install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils
sdkmanager --install "system-images;android-${{ matrix.api-level }};default;x86_64" "platform-tools" "emulator"
echo "no" | avdmanager create avd -n test -k "system-images;android-${{ matrix.api-level }};default;x86_64" --force
echo "Emulator path is: $ANDROID_HOME/emulator"
$ANDROID_HOME/emulator/emulator -avd test -no-window -no-audio -no-boot-anim -no-snapshot-load &

- name: Wait for Emulator to start
run: |
adb wait-for-device

- name: Build the SDK
if: always()
run: ./gradlew sdk:build
Expand All @@ -60,11 +76,15 @@ jobs:
if: always()
run: ./gradlew sdk:connectedAndroidTest

- name: Stop Emulator
if: always()
run: adb emu kill

- name: Publish Test Results to PR
uses: EnricoMi/publish-unit-test-result-action@v2
if: always()
with:
check_name: "Unit Test Results :rocket:"
comment_title: "Unit Test Results :rocket:"
check_name: "Unit Test Results ${{ matrix.api-level }} :rocket:"
comment_title: "Unit Test Results ${{ matrix.api-level }} :rocket:"
files: |
sdk/build/outputs/androidTest-results/**/*.xml
sdk/build/outputs/androidTest-results/**/*.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.Collections;
import org.json.JSONArray;
import org.json.JSONException;
import org.junit.After;
import org.junit.Before;
Expand Down Expand Up @@ -309,7 +310,7 @@ public void sessionDurationScenario_1() throws InterruptedException, JSONExcepti

TestUtils.validateRequest("ff_merge", TestUtils.map("old_device_id", "1234"), 1);
ModuleEventsTests.validateEventInRQ("ff_merge", "[CLY]_orientation", null, 1, 0.0d, 0.0d, "_CLY_", "_CLY_", "_CLY_", "_CLY_", 2, -1, 0, 1);
TestUtils.validateRequest("ff_merge", TestUtils.map("user_details", "{\"custom\":{\"prop2\":123,\"prop1\":\"string\",\"prop3\":false}}"), 3);
ModuleUserProfileTests.validateUserProfileRequest("ff_merge", 3, 6, TestUtils.map(), TestUtils.map("prop2", 123, "prop1", "string", "prop3", false));
ModuleSessionsTests.validateSessionEndRequest(4, 3, "ff_merge");

Thread.sleep(1000);
Expand Down Expand Up @@ -340,9 +341,9 @@ public void sessionDurationScenario_1() throws InterruptedException, JSONExcepti

assertEquals(11, TestUtils.getCurrentRQ().length);

TestUtils.validateRequest("ff", TestUtils.map("user_details", "{\"custom\":{\"prop4\":[\"sd\"]}}"), 7);
TestUtils.validateRequest("ff", TestUtils.map("user_details", "{\"custom\":{}}"), 8);
TestUtils.validateRequest("ff", TestUtils.map("user_details", "{\"custom\":{\"prop2\":456,\"prop1\":\"string_a\",\"prop3\":true}}"), 9);
ModuleUserProfileTests.validateUserProfileRequest("ff", 7, 11, TestUtils.map(), TestUtils.map("prop4", new JSONArray(Collections.singletonList("sd"))));
ModuleUserProfileTests.validateUserProfileRequest("ff", 8, 11, TestUtils.map(), TestUtils.map());
ModuleUserProfileTests.validateUserProfileRequest("ff", 9, 11, TestUtils.map(), TestUtils.map("prop2", 456, "prop1", "string_a", "prop3", true));

TestUtils.validateRequest("ff_merge", TestUtils.map("old_device_id", "ff"), 10);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ly.count.android.sdk;

import android.os.Build;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -104,7 +105,13 @@ public void customMetricToString() {

String metricString = ModuleAPM.customMetricsToString(customMetrics);

Assert.assertEquals(",\"a11\":2,\"aaa\":23,\"a351\":22,\"a1__f1\":24,\"a114\":21", metricString);
String expected;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
expected = ",\"a1__f1\":24,\"aaa\":23,\"a11\":2,\"a114\":21,\"a351\":22";
} else {
expected = ",\"a11\":2,\"aaa\":23,\"a351\":22,\"a1__f1\":24,\"a114\":21";
}
Assert.assertEquals(expected, metricString);
}

@Test
Expand Down Expand Up @@ -270,9 +277,15 @@ public void internalLimits_customTrace_keyLength_segmentationValues() {
mCountly.apm().endTrace(key, customMetrics);

customMetrics.clear();
customMetrics.put("look_", 3);
customMetrics.put("a_tra", 2);
customMetrics.put("micro", 4);
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
customMetrics.put("micro", 4);
customMetrics.put("berse", 5);
customMetrics.put("look_", 3);
} else {
customMetrics.put("look_", 3);
customMetrics.put("a_tra", 2);
customMetrics.put("micro", 4);
}
verify(requestQueueProvider).sendAPMCustomTrace(eq("a_tra"), anyLong(), anyLong(), anyLong(), eq(customMetricsToString(customMetrics)));
}

Expand Down Expand Up @@ -368,6 +381,7 @@ private String customMetricsToString(Map<String, Integer> customMetrics) {
ret.append(value);
}

System.err.println("ret: " + ret.toString());
return ret.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ly.count.android.sdk;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.Map;
import org.json.JSONException;
import org.junit.After;
import org.junit.Assert;
Expand Down Expand Up @@ -249,13 +250,10 @@ public void initTimeSetConsentRQ_4() throws JSONException {
}

protected static void validateConsentRequest(String deviceId, int idx, boolean[] consents) {
String consentParam = "{\"sessions\":%b,\"crashes\":%b,\"users\":%b,\"push\":%b,\"content\":%b,\"feedback\":%b,\"scrolls\":%b,\"remote-config\":%b,\"attribution\":%b,\"clicks\":%b,\"location\":%b,\"star-rating\":%b,\"events\":%b,\"views\":%b,\"apm\":%b}";
String consentsStr = String.format(consentParam, consents[0], consents[1], consents[2], consents[3], consents[4], consents[5], consents[6], consents[7], consents[8], consents[9], consents[10], consents[11], consents[12], consents[13], consents[14]);
TestUtils.validateRequest(deviceId, TestUtils.map("consent", consentsStr), idx);
}

protected static void validateNoConsentRequest(String deviceId, int idx) {
validateConsentRequest(deviceId, idx, new boolean[] { false, false, false, false, false, false, false, false, false, false, false, false, false, false, false });
Map<String, Object> consentsMap =
TestUtils.map("sessions", consents[0], "crashes", consents[1], "users", consents[2], "push", consents[3], "feedback", consents[4], "scrolls", consents[5], "remote-config", consents[6], "attribution", consents[7], "clicks", consents[8], "location", consents[9], "star-rating",
consents[10], "events", consents[11], "views", consents[12], "apm", consents[13], "content", consents[14]);
TestUtils.validateRequest(deviceId, TestUtils.map("consent", consentsMap), idx);
}

protected static void validateAllConsentRequest(String deviceId, int idx) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ly.count.android.sdk;

import android.os.Build;
import androidx.annotation.NonNull;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
Expand All @@ -10,7 +11,6 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -311,7 +311,13 @@ public void internalLimits_recordException_maxSegmentationValues() throws JSONEx

Exception exception = new Exception("Some message");
countly.crashes().recordHandledException(exception, TestUtils.map("d", "4", "e", "5", "f", "6"));
validateCrash(extractStackTrace(exception), "", false, false, TestUtils.map("e", "5", "f", "6"), 0, new ConcurrentHashMap<>(), new ArrayList<>());
Map<String, Object> segm;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
segm = TestUtils.map("b", "2", "c", "3");
} else {
segm = TestUtils.map("e", "5", "f", "6");
}
validateCrash(extractStackTrace(exception), "", false, false, segm, 0, new ConcurrentHashMap<>(), new ArrayList<>());
}

/**
Expand Down Expand Up @@ -417,8 +423,14 @@ public void internalLimits_recordException_globalCrashFilter_maxSegmentationValu
Exception exception = new Exception("Some message");
countly.crashes().recordHandledException(exception, TestUtils.map("sphinx_no", 324));

validateCrash(extractStackTrace(exception), "", false, false,
TestUtils.map("long", Long.MAX_VALUE, "secret", "Minato"), 8, new HashMap<>(), new ArrayList<>());
Map<String, Object> segm;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
segm = TestUtils.map("int", Integer.MAX_VALUE, "secret", "Minato");
} else {
segm = TestUtils.map("long", Long.MAX_VALUE, "secret", "Minato");
}

validateCrash(extractStackTrace(exception), "", false, false, segm, 8, new HashMap<>(), new ArrayList<>());
}

/**
Expand Down Expand Up @@ -783,6 +795,7 @@ public void recordException_globalCrashFilter_nativeCrash() throws JSONException
cConfig.crashes.setGlobalCrashFilterCallback(crash -> crash.getStackTrace().contains(extractNativeCrash("secret")));

new Countly().init(cConfig);

Assert.assertEquals(2, TestUtils.getCurrentRQ().length);
validateCrash(extractNativeCrash("dump1"), "", true, true, 2, 0, new ConcurrentHashMap<>(), 0, new ConcurrentHashMap<>(), new ArrayList<>());
validateCrash(extractNativeCrash("dump2"), "", true, true, 2, 1, new ConcurrentHashMap<>(), 0, new ConcurrentHashMap<>(), new ArrayList<>());
Expand Down Expand Up @@ -815,7 +828,9 @@ public void recordException_crashFilter_nativeCrash() throws JSONException {
cConfig.setCrashFilterCallback(crash -> crash.contains(extractNativeCrash("secret")));

new Countly().init(cConfig);

Assert.assertEquals(2, TestUtils.getCurrentRQ().length);

validateCrash(extractNativeCrash("dump1"), "", true, true, 2, 0, new ConcurrentHashMap<>(), 0, new ConcurrentHashMap<>(), new ArrayList<>());
validateCrash(extractNativeCrash("dump2"), "", true, true, 2, 1, new ConcurrentHashMap<>(), 0, new ConcurrentHashMap<>(), new ArrayList<>());
}
Expand Down Expand Up @@ -874,7 +889,11 @@ private void validateCrash(@NonNull String error, @NonNull String breadcrumbs, b
paramCount++;
JSONObject custom = crash.getJSONObject("_custom");
for (Map.Entry<String, Object> entry : customSegmentation.entrySet()) {
Assert.assertEquals(entry.getValue(), custom.get(entry.getKey()));
if (entry.getValue().getClass().isArray()) {
Assert.assertEquals(new JSONArray(entry.getValue()), custom.get(entry.getKey()));
} else {
Assert.assertEquals(entry.getValue(), custom.get(entry.getKey()));
}
}
Assert.assertEquals(custom.length(), customSegmentation.size());
}
Expand Down Expand Up @@ -985,7 +1004,7 @@ private String extractStackTrace(Throwable throwable, int lineLength, int maxLin
}

private String extractNativeCrash(String crash) {
return Base64.getEncoder().encodeToString(crash.getBytes());
return android.util.Base64.encodeToString(crash.getBytes(), android.util.Base64.NO_WRAP);
}

@Test(expected = StackOverflowError.class)
Expand Down Expand Up @@ -1155,8 +1174,13 @@ public void internalLimits_globalCrashFilter_sdkInternalLimits() throws JSONExce

Exception exception = new Exception("Some message");
countly.crashes().recordUnhandledException(exception);
validateCrash(extractStackTrace(exception), "Merce\nVVolv\n", true, false, TestUtils.map("an", "EuroT", "ol", "Asset", "po", "DirtR", "af", "Snowr", "mi", "WRCRa"),
12, new HashMap<>(), new ArrayList<>());
Map<String, Object> segm;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
segm = TestUtils.map("af", "Snowr", "po", "DirtR", "pr", "Spint", "ol", "Asset", "in", new int[] { 1, 2 });
} else {
segm = TestUtils.map("an", "EuroT", "ol", "Asset", "po", "DirtR", "af", "Snowr", "mi", "WRCRa");
}
validateCrash(extractStackTrace(exception), "Merce\nVVolv\n", true, false, segm, 12, new HashMap<>(), new ArrayList<>());
}

/**
Expand All @@ -1178,7 +1202,11 @@ public void internalLimits_globalCrashFilter_sdkInternalLimits_withPreValues() t
cConfig.sdkInternalLimits.setMaxValueSize(5).setMaxKeyLength(2).setMaxSegmentationValues(5).setMaxBreadcrumbCount(2);
cConfig.crashes.setCustomCrashSegmentation(TestUtils.map("arr", new int[] { 1, 2, 3, 4, 5 }, "double", Double.MAX_VALUE, "bool", true, "float", 1.1, "object", new Object(), "string", "string_to_become"));
cConfig.crashes.setGlobalCrashFilterCallback(crash -> {
Assert.assertEquals(TestUtils.map("de", "no", "do", Double.MAX_VALUE, "bo", false, "in", Integer.MIN_VALUE, "fl", 1.1), crash.getCrashSegmentation());
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
TestUtils.assertEqualsMap(TestUtils.map("ar", new int[] { 1, 2, 3, 4, 5 }, "do", Double.MAX_VALUE, "de", "no", "fl", 1.1, "in", Integer.MIN_VALUE), crash.getCrashSegmentation());
} else {
TestUtils.assertEqualsMap(TestUtils.map("de", "no", "do", Double.MAX_VALUE, "bo", false, "in", Integer.MIN_VALUE, "fl", 1.1), crash.getCrashSegmentation());
}
Assert.assertEquals("Volvo\nScani\n", crash.getBreadcrumbsAsString());

crash.getCrashSegmentation().put("beforemath", "Mudrunner");
Expand All @@ -1197,9 +1225,15 @@ public void internalLimits_globalCrashFilter_sdkInternalLimits_withPreValues() t

Exception exception = new Exception("Some message");
countly.crashes().recordUnhandledException(exception, TestUtils.map("boolean", false, "star", "boom_boom", "integer", Integer.MIN_VALUE, "desire", "no"));
validateCrash(extractStackTrace(exception), "Scani\nMerce\n", true, false,
TestUtils.map("be", "Mudru", "do", Double.MIN_VALUE, "bo", false, "in", Integer.MIN_VALUE, "fl", 1.1),
12, new HashMap<>(), new ArrayList<>());

Map<String, Object> segm;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
segm = TestUtils.map("do", Double.MIN_VALUE, "de", "no", "fl", 1.1, "ar", new int[] { 1, 2 }, "in", Integer.MIN_VALUE);
} else {
segm = TestUtils.map("be", "Mudru", "do", Double.MIN_VALUE, "bo", false, "in", Integer.MIN_VALUE, "fl", 1.1);
}

validateCrash(extractStackTrace(exception), "Scani\nMerce\n", true, false, segm, 12, new HashMap<>(), new ArrayList<>());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ public void valuesClearedOnConsentRemoval() {
countly.consent().removeConsentAll();

Assert.assertEquals(2, countly.remoteConfig().getValues().size()); // values are cache cleared
countly.remoteConfig().getValues().forEach((k, v) -> Assert.assertTrue(v.isCurrentUsersData));
for (Map.Entry<String, RCData> kv : countly.remoteConfig().getValues().entrySet()) {
Assert.assertTrue(kv.getValue().isCurrentUsersData);
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void sessionBeginEndConsentChanges() throws InterruptedException {
}

protected static void validateSessionConsentRequest(int idx, boolean consentForSession, String deviceId) {
ModuleConsentTests.validateConsentRequest(deviceId, idx, new boolean[] { consentForSession, false, false, false, false, false, false, false, false, false, false, false, false, false, false });
ModuleConsentTests.validateConsentRequest(deviceId, idx, new boolean[] { consentForSession, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false });
}

protected static void validateSessionBeginRequest(int idx, String deviceId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ly.count.android.sdk;

import android.os.Build;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.util.Arrays;
Expand Down Expand Up @@ -616,7 +617,14 @@ public void internalLimit_setProperties_maxSegmentationValues() throws JSONExcep
Countly.sharedInstance().userProfile().setProperties(TestUtils.map("a", "b", "c", "d", "f", 5, "level", 45, "age", 101));
Countly.sharedInstance().userProfile().save();

validateUserProfileRequest(TestUtils.map(), TestUtils.map("f", 5, "age", 101));
Map<String, Object> custom;
if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 25) {
custom = TestUtils.map("c", "d", "level", 45);
} else {
custom = TestUtils.map("f", 5, "age", 101);
}

validateUserProfileRequest(TestUtils.map(), custom);
}

/**
Expand Down
Loading
Loading