Skip to content

Commit bf78bb9

Browse files
Move network monitor initialization after connection is established, add tests
1 parent 4b54265 commit bf78bb9

File tree

8 files changed

+107
-91
lines changed

8 files changed

+107
-91
lines changed

stream-android-core/src/main/java/io/getstream/android/core/api/observers/network/StreamNetworkMonitorListener.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,20 @@ public interface StreamNetworkMonitorListener {
3030
*
3131
* @param snapshot A [StreamNetworkInfo.Snapshot] describing the newly connected network.
3232
*/
33-
public suspend fun onNetworkConnected(snapshot: StreamNetworkInfo.Snapshot?)
33+
public suspend fun onNetworkConnected(snapshot: StreamNetworkInfo.Snapshot?) {}
3434

3535
/**
3636
* Called when the network is lost.
3737
*
3838
* @param permanent True if the network is lost permanently (e.g., due to airplane mode).
3939
*/
40-
public suspend fun onNetworkLost(permanent: Boolean = false)
40+
public suspend fun onNetworkLost(permanent: Boolean = false) {}
4141

4242
/**
4343
* Called when the properties of the currently connected network change while the connection
4444
* remains active.
4545
*
4646
* @param snapshot A [StreamNetworkInfo.Snapshot] containing the updated properties.
4747
*/
48-
public suspend fun onNetworkPropertiesChanged(snapshot: StreamNetworkInfo.Snapshot)
48+
public suspend fun onNetworkPropertiesChanged(snapshot: StreamNetworkInfo.Snapshot) {}
4949
}

stream-android-core/src/main/java/io/getstream/android/core/internal/client/StreamClientImpl.kt

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -76,41 +76,6 @@ internal class StreamClientImpl<T>(
7676

7777
override suspend fun connect(): Result<StreamConnectedUser> =
7878
singleFlight.run(connectKey) {
79-
if (networkMonitorHandle == null) {
80-
logger.v { "[connect] Starting network monitor" }
81-
networkMonitorHandle =
82-
networkMonitor
83-
.subscribe(
84-
object : StreamNetworkMonitorListener {
85-
override suspend fun onNetworkConnected(
86-
snapshot: StreamNetworkInfo.Snapshot?
87-
) {
88-
logger.v { "[connect] Network connected: $snapshot" }
89-
internalNetworkInfo.update { snapshot }
90-
}
91-
92-
override suspend fun onNetworkLost(permanent: Boolean) {
93-
logger.v { "[connect] Network lost" }
94-
internalNetworkInfo.update { null }
95-
}
96-
97-
override suspend fun onNetworkPropertiesChanged(
98-
snapshot: StreamNetworkInfo.Snapshot
99-
) {
100-
logger.v { "[connect] Network changed: $snapshot" }
101-
internalNetworkInfo.update { snapshot }
102-
}
103-
},
104-
StreamSubscriptionManager.Options(
105-
retention =
106-
StreamSubscriptionManager.Options.Retention.KEEP_UNTIL_CANCELLED
107-
),
108-
)
109-
.getOrThrow()
110-
}
111-
112-
networkMonitor.start()
113-
11479
val currentState = connectionState.value
11580
if (currentState is StreamConnectionState.Connected) {
11681
logger.w { "[connect] Already connected!" }
@@ -124,7 +89,7 @@ internal class StreamClientImpl<T>(
12489
object : StreamClientListener {
12590
override fun onState(state: StreamConnectionState) {
12691
logger.v { "[client#onState]: $state" }
127-
mutableConnectionState.update(state)
92+
mutableConnectionState.update { state }
12893
subscriptionManager.forEach { it.onState(state) }
12994
}
13095

@@ -158,6 +123,42 @@ internal class StreamClientImpl<T>(
158123
.fold(
159124
onSuccess = { connected ->
160125
logger.d { "Connected to socket: $connected" }
126+
if (networkMonitorHandle == null) {
127+
logger.v { "[connect] Starting network monitor" }
128+
networkMonitorHandle =
129+
networkMonitor
130+
.subscribe(
131+
object : StreamNetworkMonitorListener {
132+
override suspend fun onNetworkConnected(
133+
snapshot: StreamNetworkInfo.Snapshot?
134+
) {
135+
logger.v {
136+
"[connect] Network connected: $snapshot"
137+
}
138+
internalNetworkInfo.update { snapshot }
139+
}
140+
141+
override suspend fun onNetworkLost(permanent: Boolean) {
142+
logger.v { "[connect] Network lost" }
143+
internalNetworkInfo.update { null }
144+
}
145+
146+
override suspend fun onNetworkPropertiesChanged(
147+
snapshot: StreamNetworkInfo.Snapshot
148+
) {
149+
logger.v { "[connect] Network changed: $snapshot" }
150+
internalNetworkInfo.update { snapshot }
151+
}
152+
},
153+
StreamSubscriptionManager.Options(
154+
retention =
155+
StreamSubscriptionManager.Options.Retention
156+
.KEEP_UNTIL_CANCELLED
157+
),
158+
)
159+
.getOrThrow()
160+
}
161+
networkMonitor.start()
161162
mutableConnectionState.update(connected)
162163
connectionIdHolder.setConnectionId(connected.connectionId).map {
163164
connected.connectedUser

stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkSnapshotBuilder.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,10 @@ internal class StreamNetworkSnapshotBuilder(
9393
} else {
9494
null
9595
}
96-
when (networkCapabilities.flag(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
97-
true -> false
98-
else -> null
99-
}
96+
when (networkCapabilities.flag(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
97+
true -> false
98+
else -> null
99+
}
100100
val bandwidthConstrained =
101101
when (
102102
networkCapabilities.flag(

stream-android-core/src/test/java/io/getstream/android/core/api/StreamClientFactoryTest.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
package io.getstream.android.core.api
1919

20-
import android.net.ConnectivityManager
2120
import io.getstream.android.core.annotations.StreamInternalApi
2221
import io.getstream.android.core.api.authentication.StreamTokenManager
2322
import io.getstream.android.core.api.authentication.StreamTokenProvider
@@ -52,7 +51,6 @@ import io.getstream.android.core.internal.socket.StreamSocketSession
5251
import io.getstream.android.core.internal.socket.StreamWebSocketImpl
5352
import io.getstream.android.core.testutil.assertFieldEquals
5453
import io.getstream.android.core.testutil.readPrivateField
55-
import io.mockk.every
5654
import io.mockk.mockk
5755
import kotlin.test.assertEquals
5856
import kotlin.test.assertNotSame

stream-android-core/src/test/java/io/getstream/android/core/internal/client/StreamClientIImplTest.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,12 @@ class StreamClientIImplTest {
9696
mutableConnectionState = connFlow,
9797
scope = scope,
9898
subscriptionManager = subscriptionManager,
99-
networkMonitor = mockk(relaxed = true),
99+
networkMonitor =
100+
mockk(relaxed = true) {
101+
every { start() } returns Result.success(Unit)
102+
every { stop() } returns Result.success(Unit)
103+
every { subscribe(any(), any()) } returns Result.success(mockk(relaxed = true))
104+
},
100105
)
101106

102107
@Test

stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorUtilsTest.kt

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ import io.mockk.MockKAnnotations
2424
import io.mockk.every
2525
import io.mockk.impl.annotations.MockK
2626
import io.mockk.mockk
27-
import org.junit.runner.RunWith
28-
import org.robolectric.RobolectricTestRunner
29-
import org.robolectric.annotation.Config
3027
import kotlin.test.BeforeTest
3128
import kotlin.test.Test
3229
import kotlin.test.assertEquals
3330
import kotlin.test.assertNull
3431
import kotlin.test.assertTrue
32+
import org.junit.runner.RunWith
33+
import org.robolectric.RobolectricTestRunner
34+
import org.robolectric.annotation.Config
3535

3636
@RunWith(RobolectricTestRunner::class)
3737
@Config(sdk = [Build.VERSION_CODES.P])
@@ -55,9 +55,7 @@ internal class StreamNetworkMonitorUtilsTest {
5555

5656
@Test
5757
fun `sanitizeSsid trims markers and ignores unknown`() {
58-
val info = mockk<WifiInfo> {
59-
every { ssid } returns "\"Stream\""
60-
}
58+
val info = mockk<WifiInfo> { every { ssid } returns "\"Stream\"" }
6159
assertEquals("Stream", sanitizeSsid(info))
6260

6361
every { info.ssid } returns "<unknown ssid>"
@@ -66,14 +64,11 @@ internal class StreamNetworkMonitorUtilsTest {
6664

6765
@Test
6866
fun `telephony helpers unwrap signal values`() {
69-
val manager = mockk<TelephonyManager> {
70-
every { signalStrength } returns mockk(relaxed = true)
71-
}
67+
val manager =
68+
mockk<TelephonyManager> { every { signalStrength } returns mockk(relaxed = true) }
7269
assertEquals(manager.signalStrength, telephonySignalStrength(manager))
7370

74-
val nrSignalStrength = mockk<SignalStrength>(relaxed = true) {
75-
every { level } returns 3
76-
}
71+
val nrSignalStrength = mockk<SignalStrength>(relaxed = true) { every { level } returns 3 }
7772
assertEquals(3, signalLevel(nrSignalStrength))
7873
}
7974
}

stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSignalProcessingTest.kt

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package io.getstream.android.core.internal.observers.network
1717

18-
import android.net.NetworkCapabilities
1918
import android.net.wifi.WifiInfo
2019
import android.net.wifi.WifiManager
2120
import android.os.Build
@@ -28,7 +27,6 @@ import io.mockk.MockKAnnotations
2827
import io.mockk.every
2928
import io.mockk.impl.annotations.MockK
3029
import io.mockk.mockk
31-
import io.mockk.mockkObject
3230
import io.mockk.mockkStatic
3331
import io.mockk.unmockkAll
3432
import kotlin.test.AfterTest
@@ -37,8 +35,6 @@ import kotlin.test.Test
3735
import kotlin.test.assertEquals
3836
import kotlin.test.assertIs
3937
import kotlin.test.assertNull
40-
import kotlinx.coroutines.ExperimentalCoroutinesApi
41-
import org.junit.Assert.assertTrue
4238
import org.junit.runner.RunWith
4339
import org.robolectric.RobolectricTestRunner
4440
import org.robolectric.annotation.Config
@@ -65,12 +61,13 @@ internal class StreamNetworkSignalProcessingTest {
6561

6662
@Test
6763
fun `bestEffortSignal returns wifi signal when wifi transport available`() {
68-
val wifiInfo = mockk<WifiInfo> {
69-
every { rssi } returns -45
70-
every { ssid } returns "\"Stream\""
71-
every { bssid } returns "00:11:22:33:44:55"
72-
every { frequency } returns 5200
73-
}
64+
val wifiInfo =
65+
mockk<WifiInfo> {
66+
every { rssi } returns -45
67+
every { ssid } returns "\"Stream\""
68+
every { bssid } returns "00:11:22:33:44:55"
69+
every { frequency } returns 5200
70+
}
7471
every { wifiManager.connectionInfo } returns wifiInfo
7572

7673
val signal =
@@ -91,11 +88,12 @@ internal class StreamNetworkSignalProcessingTest {
9188
@Test
9289
fun `cellularSignal returns NR details when available`() {
9390
val strength = mockk<SignalStrength>(relaxed = true)
94-
val nrStrength = mockk<CellSignalStrengthNr>(relaxed = true) {
95-
every { ssRsrp } returns -95
96-
every { ssRsrq } returns -10
97-
every { ssSinr } returns 18
98-
}
91+
val nrStrength =
92+
mockk<CellSignalStrengthNr>(relaxed = true) {
93+
every { ssRsrp } returns -95
94+
every { ssRsrq } returns -10
95+
every { ssSinr } returns 18
96+
}
9997

10098
mockkStatic(
10199
"io.getstream.android.core.internal.observers.network.StreamNetworkMonitorUtilsKt"

stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSnapshotBuilderTest.kt

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,16 @@ import io.mockk.MockKAnnotations
2828
import io.mockk.every
2929
import io.mockk.impl.annotations.MockK
3030
import io.mockk.mockk
31-
import org.junit.runner.RunWith
32-
import org.robolectric.RobolectricTestRunner
33-
import org.robolectric.annotation.Config
34-
import kotlin.intArrayOf
3531
import kotlin.test.BeforeTest
3632
import kotlin.test.Test
3733
import kotlin.test.assertEquals
3834
import kotlin.test.assertFalse
3935
import kotlin.test.assertNotNull
4036
import kotlin.test.assertTrue
4137
import kotlin.time.ExperimentalTime
42-
38+
import org.junit.runner.RunWith
39+
import org.robolectric.RobolectricTestRunner
40+
import org.robolectric.annotation.Config
4341

4442
@OptIn(ExperimentalTime::class)
4543
@RunWith(RobolectricTestRunner::class)
@@ -66,19 +64,40 @@ internal class StreamNetworkSnapshotBuilderTest {
6664

6765
every { capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) } returns true
6866
every { capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) } returns false
69-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns true
70-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) } returns true
71-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL) } returns false
72-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) } returns true
73-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) } returns true
74-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK) } returns false
75-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED) } returns true
76-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) } returns true
77-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) } returns true
78-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED) } returns true
79-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY) } returns true
80-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH) } returns false
81-
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) } returns true
67+
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) } returns
68+
true
69+
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) } returns
70+
true
71+
every {
72+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL)
73+
} returns false
74+
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) } returns
75+
true
76+
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) } returns
77+
true
78+
every {
79+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)
80+
} returns false
81+
every {
82+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)
83+
} returns true
84+
every {
85+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
86+
} returns true
87+
every {
88+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
89+
} returns true
90+
every {
91+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED)
92+
} returns true
93+
every {
94+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
95+
} returns true
96+
every {
97+
capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH)
98+
} returns false
99+
every { capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) } returns
100+
true
82101
every { capabilities.linkDownstreamBandwidthKbps } returns 50_000
83102
every { capabilities.linkUpstreamBandwidthKbps } returns 10_000
84103

0 commit comments

Comments
 (0)