Skip to content

Commit f73ff15

Browse files
committed
Add more tests and docs
1 parent 0b8c9c9 commit f73ff15

File tree

7 files changed

+154
-9
lines changed

7 files changed

+154
-9
lines changed

sentry-android-core/src/main/java/io/sentry/android/core/internal/util/AndroidConnectionStatusProvider.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.jetbrains.annotations.ApiStatus;
1919
import org.jetbrains.annotations.NotNull;
2020
import org.jetbrains.annotations.Nullable;
21+
import org.jetbrains.annotations.TestOnly;
2122

2223
/**
2324
* Note: ConnectivityManager sometimes throws SecurityExceptions on Android 11. Hence all relevant
@@ -64,7 +65,7 @@ public AndroidConnectionStatusProvider(
6465

6566
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
6667
@Override
67-
public void addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
68+
public boolean addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
6869
final ConnectivityManager.NetworkCallback callback =
6970
new ConnectivityManager.NetworkCallback() {
7071
@Override
@@ -89,7 +90,7 @@ public void onUnavailable() {
8990
};
9091

9192
registeredCallbacks.put(observer, callback);
92-
registerNetworkCallback(context, logger, buildInfoProvider, callback);
93+
return registerNetworkCallback(context, logger, buildInfoProvider, callback);
9394
}
9495

9596
@Override
@@ -326,4 +327,11 @@ public static void unregisterNetworkCallback(
326327
logger.log(SentryLevel.ERROR, "unregisterNetworkCallback failed", t);
327328
}
328329
}
330+
331+
@TestOnly
332+
@NotNull
333+
public Map<IConnectionStatusObserver, ConnectivityManager.NetworkCallback>
334+
getRegisteredCallbacks() {
335+
return registeredCallbacks;
336+
}
329337
}

sentry-android-core/src/test/java/io/sentry/android/core/AndroidConnectionStatusProviderTest.kt

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import org.mockito.kotlin.any
2020
import org.mockito.kotlin.eq
2121
import org.mockito.kotlin.mock
2222
import org.mockito.kotlin.never
23+
import org.mockito.kotlin.times
2324
import org.mockito.kotlin.verify
2425
import org.mockito.kotlin.whenever
2526
import kotlin.test.BeforeTest
@@ -31,7 +32,7 @@ import kotlin.test.assertTrue
3132

3233
class AndroidConnectionStatusProviderTest {
3334

34-
private lateinit var connectionStatusProvider: IConnectionStatusProvider
35+
private lateinit var connectionStatusProvider: AndroidConnectionStatusProvider
3536
private lateinit var contextMock: Context
3637
private lateinit var connectivityManager: ConnectivityManager
3738
private lateinit var networkInfo: NetworkInfo
@@ -294,4 +295,52 @@ class AndroidConnectionStatusProviderTest {
294295
}
295296
assertFalse(failed)
296297
}
298+
299+
@Test
300+
fun `connectionStatus returns NO_PERMISSIONS when context does not hold the permission`() {
301+
whenever(contextMock.checkPermission(any(), any(), any())).thenReturn(PERMISSION_DENIED)
302+
assertEquals(IConnectionStatusProvider.ConnectionStatus.NO_PERMISSION, connectionStatusProvider.connectionStatus)
303+
}
304+
305+
@Test
306+
fun `connectionStatus returns ethernet when underlying mechanism provides ethernet`() {
307+
whenever(networkCapabilities.hasTransport(eq(TRANSPORT_ETHERNET))).thenReturn(true)
308+
assertEquals(
309+
"ethernet",
310+
connectionStatusProvider.connectionType
311+
)
312+
}
313+
314+
@Test
315+
fun `adding and removing an observer works correctly`() {
316+
whenever(buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.N)
317+
318+
val observer = IConnectionStatusProvider.IConnectionStatusObserver { }
319+
val addResult = connectionStatusProvider.addConnectionStatusObserver(observer)
320+
assertTrue(addResult)
321+
322+
connectionStatusProvider.removeConnectionStatusObserver(observer)
323+
assertTrue(connectionStatusProvider.registeredCallbacks.isEmpty())
324+
}
325+
326+
@Test
327+
fun `underlying callbacks correctly trigger update`() {
328+
whenever(buildInfo.sdkInfoVersion).thenReturn(Build.VERSION_CODES.N)
329+
330+
var callback: NetworkCallback? = null
331+
whenever(connectivityManager.registerDefaultNetworkCallback(any())).then { invocation ->
332+
callback = invocation.getArgument(0, NetworkCallback::class.java)
333+
Unit
334+
}
335+
val observer = mock<IConnectionStatusProvider.IConnectionStatusObserver>()
336+
connectionStatusProvider.addConnectionStatusObserver(observer)
337+
callback!!.onAvailable(mock<Network>())
338+
callback!!.onUnavailable()
339+
callback!!.onLosing(mock<Network>(), 0)
340+
callback!!.onLost(mock<Network>())
341+
callback!!.onUnavailable()
342+
connectionStatusProvider.removeConnectionStatusObserver(observer)
343+
344+
verify(observer, times(5)).onConnectionStatusChanged(any())
345+
}
297346
}

sentry/api/sentry.api

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ public abstract interface class io/sentry/ICollector {
441441
}
442442

443443
public abstract interface class io/sentry/IConnectionStatusProvider {
444-
public abstract fun addConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)V
444+
public abstract fun addConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)Z
445445
public abstract fun getConnectionStatus ()Lio/sentry/IConnectionStatusProvider$ConnectionStatus;
446446
public abstract fun getConnectionType ()Ljava/lang/String;
447447
public abstract fun removeConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)V
@@ -863,7 +863,7 @@ public final class io/sentry/MemoryCollectionData {
863863

864864
public final class io/sentry/NoOpConnectionStatusProvider : io/sentry/IConnectionStatusProvider {
865865
public fun <init> ()V
866-
public fun addConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)V
866+
public fun addConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)Z
867867
public fun getConnectionStatus ()Lio/sentry/IConnectionStatusProvider$ConnectionStatus;
868868
public fun getConnectionType ()Ljava/lang/String;
869869
public fun removeConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)V

sentry/src/main/java/io/sentry/IConnectionStatusProvider.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,43 @@ enum ConnectionStatus {
1515
}
1616

1717
interface IConnectionStatusObserver {
18+
/**
19+
* Invoked whenever the connection status changed.
20+
*
21+
* @param status the new connection status
22+
*/
1823
void onConnectionStatusChanged(ConnectionStatus status);
1924
}
2025

26+
/**
27+
* Gets the connection status.
28+
*
29+
* @return the current connection status
30+
*/
2131
@NotNull
2232
ConnectionStatus getConnectionStatus();
2333

34+
/**
35+
* Gets the connection type.
36+
*
37+
* @return the current connection type. E.g. "ethernet", "wifi" or "cellular"
38+
*/
2439
@Nullable
2540
String getConnectionType();
2641

27-
void addConnectionStatusObserver(@NotNull final IConnectionStatusObserver observer);
28-
42+
/**
43+
* Adds an observer for listening to connection status changes.
44+
*
45+
* @param observer the observer to register
46+
* @return true if the observer was sucessfully registered
47+
*/
48+
boolean addConnectionStatusObserver(@NotNull final IConnectionStatusObserver observer);
49+
50+
/**
51+
* Removes an observer.
52+
*
53+
* @param observer a previously added observer via {@link
54+
* #addConnectionStatusObserver(IConnectionStatusObserver)}
55+
*/
2956
void removeConnectionStatusObserver(@NotNull final IConnectionStatusObserver observer);
3057
}

sentry/src/main/java/io/sentry/NoOpConnectionStatusProvider.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ public final class NoOpConnectionStatusProvider implements IConnectionStatusProv
1717
}
1818

1919
@Override
20-
public void addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
21-
// no-op
20+
public boolean addConnectionStatusObserver(@NotNull IConnectionStatusObserver observer) {
21+
return false;
2222
}
2323

2424
@Override
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.sentry
2+
3+
import org.mockito.kotlin.mock
4+
import kotlin.test.Test
5+
import kotlin.test.assertEquals
6+
import kotlin.test.assertFalse
7+
import kotlin.test.assertNull
8+
9+
class NoOpConnectionStatusProviderTest {
10+
11+
private val provider = NoOpConnectionStatusProvider()
12+
13+
@Test
14+
fun `provider returns unknown status`() {
15+
assertEquals(IConnectionStatusProvider.ConnectionStatus.UNKNOWN, provider.connectionStatus)
16+
}
17+
18+
@Test
19+
fun `connection type returns null`() {
20+
assertNull(provider.connectionType)
21+
}
22+
23+
@Test
24+
fun `adding a listener is a no-op and returns false`() {
25+
val result = provider.addConnectionStatusObserver(mock<IConnectionStatusProvider.IConnectionStatusObserver>())
26+
assertFalse(result)
27+
}
28+
29+
@Test
30+
fun `removing a listener is a no-op`() {
31+
provider.addConnectionStatusObserver(mock<IConnectionStatusProvider.IConnectionStatusObserver>())
32+
}
33+
}

sentry/src/test/java/io/sentry/SentryOptionsTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,4 +478,32 @@ class SentryOptionsTest {
478478
fun `when options are initialized, FullyDrawnReporter is set`() {
479479
assertEquals(FullyDisplayedReporter.getInstance(), SentryOptions().fullyDisplayedReporter)
480480
}
481+
482+
@Test
483+
fun `when options is initialized, connectionStatusProvider is not null and default to noop`() {
484+
assertNotNull(SentryOptions().connectionStatusProvider)
485+
assertTrue(SentryOptions().connectionStatusProvider is NoOpConnectionStatusProvider)
486+
}
487+
488+
@Test
489+
fun `when connectionStatusProvider is set, its returned as well`() {
490+
val options = SentryOptions()
491+
val customProvider = object : IConnectionStatusProvider {
492+
override fun getConnectionStatus(): IConnectionStatusProvider.ConnectionStatus {
493+
return IConnectionStatusProvider.ConnectionStatus.UNKNOWN
494+
}
495+
496+
override fun getConnectionType(): String? = null
497+
498+
override fun addConnectionStatusObserver(observer: IConnectionStatusProvider.IConnectionStatusObserver) {
499+
// no-op
500+
}
501+
502+
override fun removeConnectionStatusObserver(observer: IConnectionStatusProvider.IConnectionStatusObserver) {
503+
// no-op
504+
}
505+
}
506+
options.connectionStatusProvider = customProvider
507+
assertEquals(customProvider, options.connectionStatusProvider)
508+
}
481509
}

0 commit comments

Comments
 (0)