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

Add tests for the Android and iOS plugin #1587

Merged
merged 50 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8cb2613
add first test to android
denrase Aug 7, 2023
57a189e
update remaining options for android
denrase Aug 7, 2023
557867b
test update of options in ios/macos plugin
denrase Aug 7, 2023
0e644ed
change provisioning profile
denrase Aug 7, 2023
286e8f3
run native tests un integration test workflow
denrase Aug 7, 2023
ddc9041
new detekt baseline
denrase Aug 8, 2023
7d2c460
fix some lint issues
denrase Aug 8, 2023
d905ab7
fix klint issue
denrase Aug 8, 2023
686e7d6
remove trailing commas
denrase Aug 8, 2023
787dfac
update baseline
denrase Aug 8, 2023
a590378
set junit version directly
denrase Aug 8, 2023
c357792
fix swiftlint issues
denrase Aug 8, 2023
a2f07a3
fix klint issues
denrase Aug 8, 2023
3cc4682
remove trailing commas
denrase Aug 8, 2023
337e279
comment out in action
denrase Aug 8, 2023
2b774a1
remove comments
denrase Aug 8, 2023
a3cdb7a
Merge branch 'main' into denrase/test-native-plugin-init
denrase Aug 21, 2023
dbb1454
run ios native test
denrase Aug 21, 2023
cd604d4
try native test only
denrase Aug 21, 2023
fb9c99d
update wd to start from root dir
denrase Aug 21, 2023
c858af8
run on created device
denrase Aug 21, 2023
7fcb9e9
run on sim
denrase Aug 21, 2023
6dc9e6c
use id to start test
denrase Aug 21, 2023
a44bfcc
run on 16.4 target
denrase Aug 21, 2023
424a77b
lower deployment target of tests
denrase Aug 21, 2023
d2434bf
build ios app
denrase Aug 21, 2023
edf9110
handle provision profile issue
denrase Aug 21, 2023
8d4afdb
run build before launching sim
denrase Aug 21, 2023
1bff064
just run pod install
denrase Aug 22, 2023
179656e
run native test on android device
denrase Aug 22, 2023
e8856a1
check why gradlew is not present (wrong folder?)
denrase Aug 22, 2023
83231b6
init gradle wrapper
denrase Aug 22, 2023
2c1495a
run gradle wrapper init in sep. step
denrase Aug 22, 2023
acdd4a4
build apk
denrase Aug 22, 2023
a505327
rename action
denrase Aug 22, 2023
b2cdeeb
Merge branch 'main' into denrase/test-native-plugin-init
denrase Aug 28, 2023
6e5aba2
provide auth token as env
denrase Aug 28, 2023
ef5516a
uncomment other tests to test integration test
denrase Aug 28, 2023
0fd5be0
disable e2e test
denrase Aug 28, 2023
89b82fb
disable e2e test & enable native tests
denrase Aug 28, 2023
170763a
add alias in macos folder
denrase Aug 28, 2023
c2d8736
add detekt rule
denrase Aug 28, 2023
671d550
fix macos example target
denrase Aug 28, 2023
fcecded
provide device id
denrase Aug 28, 2023
4905b17
run integration tests before native tests
denrase Aug 28, 2023
1a84ab4
remove lines
denrase Aug 28, 2023
62aa008
disable integration test
denrase Aug 28, 2023
430038b
Merge branch 'main' into denrase/test-native-plugin-init
denrase Aug 28, 2023
da19bc2
comment in e2e test
denrase Aug 29, 2023
2c11a95
diable e2e test
denrase Aug 29, 2023
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
20 changes: 18 additions & 2 deletions .github/workflows/flutter_integration_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,18 @@ jobs:
profile: Nexus 6
script: flutter test integration_test/integration_test.dart --verbose

- name: launch android emulator & run android native test
uses: reactivecircus/android-emulator-runner@d94c3fbe4fe6a29e4a5ba47c12fb47677c73656b #[email protected]
with:
working-directory: ./flutter/example/android
api-level: 21
force-avd-creation: false
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
disable-animations: true
arch: x86_64
profile: Nexus 6
script: ./gradlew testDebugUnitTest

test-ios:
runs-on: macos-13
timeout-minutes: 30
Expand Down Expand Up @@ -113,5 +125,9 @@ jobs:
simulator_id=$(xcrun simctl create sentryPhone com.apple.CoreSimulator.SimDeviceType.iPhone-14 com.apple.CoreSimulator.SimRuntime.iOS-16-2)
xcrun simctl boot ${simulator_id}

- name: run ios integration test
run: flutter test integration_test/integration_test.dart --verbose
# - name: run ios integration test
# run: flutter test integration_test/integration_test.dart --verbose

- name: run native test
working-directory: ./flutter/example/ios
run: xcodebuild test -workspace Runner.xcworkspace -scheme Runner -configuration Debug -destination 'platform=iOS Simulator,name=iPhone 14'
3 changes: 3 additions & 0 deletions flutter/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,7 @@ android {
dependencies {
api 'io.sentry:sentry-android:6.25.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

// Required -- JUnit 4 framework
testImplementation "junit:junit:$junit_version"
}
129 changes: 129 additions & 0 deletions flutter/android/src/main/kotlin/io/sentry/flutter/SentryFlutter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package io.sentry.flutter

import io.sentry.SentryLevel
import io.sentry.android.core.BuildConfig
import io.sentry.android.core.SentryAndroidOptions
import io.sentry.protocol.SdkVersion
import java.util.Locale

class SentryFlutter(
private val androidSdk: String,
private val nativeSdk: String
) {

var autoPerformanceTracingEnabled = false

fun updateOptions(options: SentryAndroidOptions, data: Map<String, Any>) {
data.getIfNotNull<String>("dsn") {
options.dsn = it
}
data.getIfNotNull<Boolean>("debug") {
options.isDebug = it
}
data.getIfNotNull<String>("environment") {
options.environment = it
}
data.getIfNotNull<String>("release") {
options.release = it
}
data.getIfNotNull<String>("dist") {
options.dist = it
}
data.getIfNotNull<Boolean>("enableAutoSessionTracking") {
options.isEnableAutoSessionTracking = it
}
data.getIfNotNull<Long>("autoSessionTrackingIntervalMillis") {
options.sessionTrackingIntervalMillis = it
}
data.getIfNotNull<Long>("anrTimeoutIntervalMillis") {
options.anrTimeoutIntervalMillis = it
}
data.getIfNotNull<Boolean>("attachThreads") {
options.isAttachThreads = it
}
data.getIfNotNull<Boolean>("attachStacktrace") {
options.isAttachStacktrace = it
}
data.getIfNotNull<Boolean>("enableAutoNativeBreadcrumbs") {
options.isEnableActivityLifecycleBreadcrumbs = it
options.isEnableAppLifecycleBreadcrumbs = it
options.isEnableSystemEventBreadcrumbs = it
options.isEnableAppComponentBreadcrumbs = it
options.isEnableUserInteractionBreadcrumbs = it
}
data.getIfNotNull<Int>("maxBreadcrumbs") {
options.maxBreadcrumbs = it
}
data.getIfNotNull<Int>("maxCacheItems") {
options.maxCacheItems = it
}
data.getIfNotNull<String>("diagnosticLevel") {
if (options.isDebug) {
val sentryLevel = SentryLevel.valueOf(it.toUpperCase(Locale.ROOT))
options.setDiagnosticLevel(sentryLevel)
}
}
data.getIfNotNull<Boolean>("anrEnabled") {
options.isAnrEnabled = it
}
data.getIfNotNull<Boolean>("sendDefaultPii") {
options.isSendDefaultPii = it
}
data.getIfNotNull<Boolean>("enableNdkScopeSync") {
options.isEnableScopeSync = it
}
data.getIfNotNull<String>("proguardUuid") {
options.proguardUuid = it
}

val nativeCrashHandling = (data["enableNativeCrashHandling"] as? Boolean) ?: true
// nativeCrashHandling has priority over anrEnabled
if (!nativeCrashHandling) {
options.isEnableUncaughtExceptionHandler = false
options.isAnrEnabled = false
// if split symbols are enabled, we need Ndk integration so we can't really offer the option
// to turn it off
// options.isEnableNdk = false
}

data.getIfNotNull<Boolean>("enableAutoPerformanceTracing") { enableAutoPerformanceTracing ->
if (enableAutoPerformanceTracing) {
autoPerformanceTracingEnabled = true
}
}

data.getIfNotNull<Boolean>("sendClientReports") {
options.isSendClientReports = it
}

data.getIfNotNull<Long>("maxAttachmentSize") {
options.maxAttachmentSize = it
}

var sdkVersion = options.sdkVersion
if (sdkVersion == null) {
sdkVersion = SdkVersion(androidSdk, BuildConfig.VERSION_NAME)
} else {
sdkVersion.name = androidSdk
}

options.sdkVersion = sdkVersion
options.sentryClientName = "$androidSdk/${BuildConfig.VERSION_NAME}"
options.nativeSdkName = nativeSdk

data.getIfNotNull<Int>("connectionTimeoutMillis") {
options.connectionTimeoutMillis = it
}
data.getIfNotNull<Int>("readTimeoutMillis") {
options.readTimeoutMillis = it
}
}
}

// Call the `completion` closure if cast to map value with `key` and type `T` is successful.
@Suppress("UNCHECKED_CAST")
private fun <T> Map<String, Any>.getIfNotNull(key: String, callback: (T) -> Unit) {
(get(key) as? T)?.let {
callback(it)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import java.util.UUID
class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel: MethodChannel
private lateinit var context: Context
private lateinit var sentryFlutter: SentryFlutter

private var activity: WeakReference<Activity>? = null
private var framesTracker: ActivityFramesTracker? = null
Expand All @@ -48,6 +49,11 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
context = flutterPluginBinding.applicationContext
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "sentry_flutter")
channel.setMethodCallHandler(this)

sentryFlutter = SentryFlutter(
androidSdk = androidSdk,
nativeSdk = nativeSdk,
denrase marked this conversation as resolved.
Show resolved Hide resolved
)
}

override fun onMethodCall(call: MethodCall, result: Result) {
Expand Down Expand Up @@ -122,78 +128,17 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

SentryAndroid.init(context) { options ->
args.getIfNotNull<String>("dsn") { options.dsn = it }
args.getIfNotNull<Boolean>("debug") { options.isDebug = it }
args.getIfNotNull<String>("environment") { options.environment = it }
args.getIfNotNull<String>("release") { options.release = it }
args.getIfNotNull<String>("dist") { options.dist = it }
args.getIfNotNull<Boolean>("enableAutoSessionTracking") { options.isEnableAutoSessionTracking = it }
args.getIfNotNull<Long>("autoSessionTrackingIntervalMillis") { options.sessionTrackingIntervalMillis = it }
args.getIfNotNull<Long>("anrTimeoutIntervalMillis") { options.anrTimeoutIntervalMillis = it }
args.getIfNotNull<Boolean>("attachThreads") { options.isAttachThreads = it }
args.getIfNotNull<Boolean>("attachStacktrace") { options.isAttachStacktrace = it }
args.getIfNotNull<Boolean>("enableAutoNativeBreadcrumbs") {
options.isEnableActivityLifecycleBreadcrumbs = it
options.isEnableAppLifecycleBreadcrumbs = it
options.isEnableSystemEventBreadcrumbs = it
options.isEnableAppComponentBreadcrumbs = it
options.isEnableUserInteractionBreadcrumbs = it
}
args.getIfNotNull<Int>("maxBreadcrumbs") { options.maxBreadcrumbs = it }
args.getIfNotNull<Int>("maxCacheItems") { options.maxCacheItems = it }
args.getIfNotNull<String>("diagnosticLevel") {
if (options.isDebug) {
val sentryLevel = SentryLevel.valueOf(it.toUpperCase(Locale.ROOT))
options.setDiagnosticLevel(sentryLevel)
}
}
args.getIfNotNull<Boolean>("anrEnabled") { options.isAnrEnabled = it }
args.getIfNotNull<Boolean>("sendDefaultPii") { options.isSendDefaultPii = it }
args.getIfNotNull<Boolean>("enableNdkScopeSync") { options.isEnableScopeSync = it }
args.getIfNotNull<String>("proguardUuid") { options.proguardUuid = it }

val nativeCrashHandling = (args["enableNativeCrashHandling"] as? Boolean) ?: true
// nativeCrashHandling has priority over anrEnabled
if (!nativeCrashHandling) {
options.isEnableUncaughtExceptionHandler = false
options.isAnrEnabled = false
// if split symbols are enabled, we need Ndk integration so we can't really offer the option
// to turn it off
// options.isEnableNdk = false
}

args.getIfNotNull<Boolean>("enableAutoPerformanceTracing") { enableAutoPerformanceTracing ->
if (enableAutoPerformanceTracing) {
autoPerformanceTracingEnabled = true
framesTracker = ActivityFramesTracker(LoadClass(), options)
}
}
sentryFlutter.updateOptions(options, args)

args.getIfNotNull<Boolean>("sendClientReports") { options.isSendClientReports = it }

args.getIfNotNull<Long>("maxAttachmentSize") { options.maxAttachmentSize = it }

var sdkVersion = options.sdkVersion
if (sdkVersion == null) {
sdkVersion = SdkVersion(androidSdk, VERSION_NAME)
} else {
sdkVersion.name = androidSdk
if (sentryFlutter.autoPerformanceTracingEnabled) {
framesTracker = ActivityFramesTracker(LoadClass(), options)
}

options.sdkVersion = sdkVersion
options.sentryClientName = "$androidSdk/$VERSION_NAME"
options.nativeSdkName = nativeSdk

options.setBeforeSend { event, _ ->
setEventOriginTag(event)
addPackages(event, options.sdkVersion)
event
}

args.getIfNotNull<Int>("connectionTimeoutMillis") { options.connectionTimeoutMillis = it }
args.getIfNotNull<Int>("readTimeoutMillis") { options.readTimeoutMillis = it }

// missing proxy
}
result.success("")
}
Expand Down Expand Up @@ -437,10 +382,3 @@ class SentryFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}
}
}

// Call the `completion` closure if cast to map value with `key` and type `T` is successful.
private fun <T> Map<String, Any>.getIfNotNull(key: String, callback: (T) -> Unit) {
(get(key) as? T)?.let {
callback(it)
}
}
Loading
Loading