Skip to content

Commit

Permalink
Add config for sending force ping request (#71)
Browse files Browse the repository at this point in the history
* Add config for sending force ping request

* Fix unit tests
  • Loading branch information
deepanshu42 authored Jul 18, 2023
1 parent e3fe343 commit 7ae7f5b
Show file tree
Hide file tree
Showing 17 changed files with 152 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ public MqttToken sendForcePingRequest() throws MqttException
// Wake sender thread since it may be in wait state (in ClientState.get())
notifyQueueLock();
}
else if ((time - lastPing >= keepAlive + delta) && (time - lastInboundActivity >= keepAlive + delta) && (time - lastOutboundActivity >= keepAlive + delta))
else if ((time - lastPing >= keepAlive + delta) && (time - lastInboundActivity >= keepAlive + delta))
{
// any of the conditions is true means the client is active
// lastInboundActivity will be updated once receiving is done.
Expand Down
10 changes: 6 additions & 4 deletions pingsender/alarm-pingsender/api/alarm-pingsender.api
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
public final class com/gojek/alarm/pingsender/AlarmPingSenderConfig {
public fun <init> ()V
public fun <init> (ZZIZ)V
public synthetic fun <init> (ZZIZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (ZZIZZ)V
public synthetic fun <init> (ZZIZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component2 ()Z
public final fun component3 ()I
public final fun component4 ()Z
public final fun copy (ZZIZ)Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;ZZIZILjava/lang/Object;)Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;
public final fun component5 ()Z
public final fun copy (ZZIZZ)Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;ZZIZZILjava/lang/Object;)Lcom/gojek/alarm/pingsender/AlarmPingSenderConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getPingWakeLockTimeout ()I
public final fun getSendForcePing ()Z
public final fun getUseElapsedRealTimeAlarm ()Z
public fun hashCode ()I
public final fun isMqttAllowWhileIdle ()Z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,11 @@ internal class AlarmPingSender(
serverUri = comms.client.serverURI
}
pingSenderEvents.mqttPingInitiated(serverUri, comms.keepAlive.fromMillisToSeconds())
val token: IMqttToken? = comms.checkForActivity()
val token = if (alarmPingSenderConfig.sendForcePing) {
comms.sendPingRequest()
} else {
comms.checkForActivity()
}

// No ping has been sent.
if (token == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ data class AlarmPingSenderConfig(
val isMqttPingWakeUp: Boolean = true,
val isMqttAllowWhileIdle: Boolean = true,
val pingWakeLockTimeout: Int = DEFAULT_PING_WAKELOCK_TIMEOUT_IN_SECONDS,
val useElapsedRealTimeAlarm: Boolean = false
val useElapsedRealTimeAlarm: Boolean = false,
val sendForcePing: Boolean = false
)

private const val DEFAULT_PING_WAKELOCK_TIMEOUT_IN_SECONDS = 0 // 0 seconds
15 changes: 14 additions & 1 deletion pingsender/timer-pingsender/api/timer-pingsender.api
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
public final class com/gojek/timer/pingsender/TimerPingSenderConfig {
public fun <init> ()V
public fun <init> (Z)V
public synthetic fun <init> (ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun copy (Z)Lcom/gojek/timer/pingsender/TimerPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/timer/pingsender/TimerPingSenderConfig;ZILjava/lang/Object;)Lcom/gojek/timer/pingsender/TimerPingSenderConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getSendForcePing ()Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public final class com/gojek/timer/pingsender/TimerPingSenderFactory {
public static final field Companion Lcom/gojek/timer/pingsender/TimerPingSenderFactory$Companion;
}

public final class com/gojek/timer/pingsender/TimerPingSenderFactory$Companion {
public final fun create ()Lcom/gojek/mqtt/pingsender/MqttPingSender;
public final fun create (Lcom/gojek/timer/pingsender/TimerPingSenderConfig;)Lcom/gojek/mqtt/pingsender/MqttPingSender;
}

Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.eclipse.paho.client.mqttv3.internal.ClientComms
* @see MqttPingSender
*/
internal class TimerPingSender(
private val pingSenderConfig: TimerPingSenderConfig,
private val clock: Clock = Clock(),
private val timerFactory: TimerFactory = TimerFactory()
) : MqttPingSender {
Expand Down Expand Up @@ -71,7 +72,11 @@ internal class TimerPingSender(
val serverUri = comms.client?.serverURI ?: ""
val keepAliveMillis = comms.keepAlive
pingSenderEvents.mqttPingInitiated(comms.client.serverURI, keepAliveMillis.fromMillisToSeconds())
val token = comms.checkForActivity()
val token = if (pingSenderConfig.sendForcePing) {
comms.sendPingRequest()
} else {
comms.checkForActivity()
}
if (token == null) {
logger.d(TAG, "Mqtt Ping Token null")
pingSenderEvents.pingMqttTokenNull(serverUri, keepAliveMillis.fromMillisToSeconds())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.gojek.timer.pingsender

data class TimerPingSenderConfig(
val sendForcePing: Boolean = false
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import com.gojek.mqtt.pingsender.MqttPingSender

class TimerPingSenderFactory private constructor() {
companion object {
fun create(): MqttPingSender {
return TimerPingSender()
fun create(timerPingSenderConfig: TimerPingSenderConfig): MqttPingSender {
return TimerPingSender(timerPingSenderConfig)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ class TimerPingSenderTest {
private val comms = mock<ClientComms>()
private val logger = mock<ILogger>()
private val pingSenderEvents = mock<IPingSenderEvents>()
private val pingSenderConfig = mock<TimerPingSenderConfig>()

private val pingSender = TimerPingSender(clock, timerFactory)
private val pingSender = TimerPingSender(pingSenderConfig, clock, timerFactory)

@Before
fun setup() {
Expand Down Expand Up @@ -107,6 +108,31 @@ class TimerPingSenderTest {
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping can be sent successfully with sendForcePing=true`() {
val mqttClient = mock<IMqttAsyncClient>()
val mqttToken = mock<MqttToken>()
val testUri = "test-uri"
val keepaliveMillis = 30000L
val startTime = TimeUnit.MILLISECONDS.toNanos(100)
val endTime = TimeUnit.MILLISECONDS.toNanos(110)
whenever(pingSenderConfig.sendForcePing).thenReturn(true)
whenever(comms.client).thenReturn(mqttClient)
whenever(mqttClient.serverURI).thenReturn(testUri)
whenever(comms.keepAlive).thenReturn(keepaliveMillis)
whenever(comms.sendPingRequest()).thenReturn(mqttToken)
whenever(clock.nanoTime()).thenReturn(startTime, endTime)

pingSender.PingTask().run()

verify(pingSenderEvents).mqttPingInitiated(testUri, keepaliveMillis / 1000)

val argumentCaptor = argumentCaptor<IMqttActionListener>()
verify(mqttToken).actionCallback = argumentCaptor.capture()
argumentCaptor.lastValue.onSuccess(mqttToken)
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping cannot be sent successfully`() {
val mqttClient = mock<IMqttAsyncClient>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
public final class com/gojek/workmanager/pingsender/WorkManagerPingSenderConfig {
public fun <init> ()V
public fun <init> (J)V
public synthetic fun <init> (JILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (JZ)V
public synthetic fun <init> (JZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()J
public final fun copy (J)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;JILjava/lang/Object;)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public final fun component2 ()Z
public final fun copy (JZ)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;JZILjava/lang/Object;)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getSendForcePing ()Z
public final fun getTimeoutSeconds ()J
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ internal class WorkManagerPingSender(
val keepAliveMillis = comms.keepAlive
pingSenderEvents.mqttPingInitiated(serverUri, keepAliveMillis.fromMillisToSeconds())

val token = comms.checkForActivity()
val token = if (pingSenderConfig.sendForcePing) {
comms.sendPingRequest()
} else {
comms.checkForActivity()
}
if (token == null) {
logger.d(TAG, "Mqtt Ping Token null")
pingSenderEvents.pingMqttTokenNull(serverUri, keepAliveMillis.fromMillisToSeconds())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.gojek.workmanager.pingsender

data class WorkManagerPingSenderConfig(
val timeoutSeconds: Long = DEFAULT_PING_TIMEOUT_SECS
val timeoutSeconds: Long = DEFAULT_PING_TIMEOUT_SECS,
val sendForcePing: Boolean = false
)

internal const val DEFAULT_PING_TIMEOUT_SECS = 30L
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,35 @@ class WorkManagerPingSenderTest {
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping can be sent successfully with sendForcePing=true`() {
val mqttClient = mock<IMqttAsyncClient>()
val mqttToken = mock<MqttToken>()
val testUri = "test-uri"
val keepaliveMillis = 30000L
val startTime = TimeUnit.MILLISECONDS.toNanos(100)
val endTime = TimeUnit.MILLISECONDS.toNanos(110)
whenever(pingSenderConfig.sendForcePing).thenReturn(true)
whenever(comms.client).thenReturn(mqttClient)
whenever(mqttClient.serverURI).thenReturn(testUri)
whenever(comms.keepAlive).thenReturn(keepaliveMillis)
whenever(comms.sendPingRequest()).thenReturn(mqttToken)
whenever(clock.nanoTime()).thenReturn(startTime, endTime)

var success: Boolean? = null
pingSender.sendPing {
success = it
}

verify(pingSenderEvents).mqttPingInitiated(testUri, keepaliveMillis / 1000)

val argumentCaptor = argumentCaptor<IMqttActionListener>()
verify(mqttToken).actionCallback = argumentCaptor.capture()
argumentCaptor.lastValue.onSuccess(mqttToken)
assertTrue(success!!)
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping cannot be sent successfully`() {
val mqttClient = mock<IMqttAsyncClient>()
Expand Down
10 changes: 6 additions & 4 deletions pingsender/workmanager-pingsender/api/workmanager-pingsender.api
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
public final class com/gojek/workmanager/pingsender/WorkManagerPingSenderConfig {
public fun <init> ()V
public fun <init> (J)V
public synthetic fun <init> (JILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (JZ)V
public synthetic fun <init> (JZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()J
public final fun copy (J)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;JILjava/lang/Object;)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public final fun component2 ()Z
public final fun copy (JZ)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public static synthetic fun copy$default (Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;JZILjava/lang/Object;)Lcom/gojek/workmanager/pingsender/WorkManagerPingSenderConfig;
public fun equals (Ljava/lang/Object;)Z
public final fun getSendForcePing ()Z
public final fun getTimeoutSeconds ()J
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,11 @@ internal class WorkManagerPingSender(
val keepAliveMillis = comms.keepAlive
pingSenderEvents.mqttPingInitiated(serverUri, keepAliveMillis.fromMillisToSeconds())

val token = comms.checkForActivity()
val token = if (pingSenderConfig.sendForcePing) {
comms.sendPingRequest()
} else {
comms.checkForActivity()
}
if (token == null) {
logger.d(TAG, "Mqtt Ping Token null")
pingSenderEvents.pingMqttTokenNull(serverUri, keepAliveMillis.fromMillisToSeconds())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.gojek.workmanager.pingsender

data class WorkManagerPingSenderConfig(
val timeoutSeconds: Long = DEFAULT_PING_TIMEOUT_SECS
val timeoutSeconds: Long = DEFAULT_PING_TIMEOUT_SECS,
val sendForcePing: Boolean = false
)

internal const val DEFAULT_PING_TIMEOUT_SECS = 30L
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,35 @@ class WorkManagerPingSenderTest {
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping can be sent successfully with sendForcePing=true`() {
val mqttClient = mock<IMqttAsyncClient>()
val mqttToken = mock<MqttToken>()
val testUri = "test-uri"
val keepaliveMillis = 30000L
val startTime = TimeUnit.MILLISECONDS.toNanos(100)
val endTime = TimeUnit.MILLISECONDS.toNanos(110)
whenever(pingSenderConfig.sendForcePing).thenReturn(true)
whenever(comms.client).thenReturn(mqttClient)
whenever(mqttClient.serverURI).thenReturn(testUri)
whenever(comms.keepAlive).thenReturn(keepaliveMillis)
whenever(comms.sendPingRequest()).thenReturn(mqttToken)
whenever(clock.nanoTime()).thenReturn(startTime, endTime)

var success: Boolean? = null
pingSender.sendPing {
success = it
}

verify(pingSenderEvents).mqttPingInitiated(testUri, keepaliveMillis / 1000)

val argumentCaptor = argumentCaptor<IMqttActionListener>()
verify(mqttToken).actionCallback = argumentCaptor.capture()
argumentCaptor.lastValue.onSuccess(mqttToken)
assertTrue(success!!)
verify(pingSenderEvents).pingEventSuccess(testUri, 10, keepaliveMillis / 1000)
}

@Test
fun `test sendPing when ping cannot be sent successfully`() {
val mqttClient = mock<IMqttAsyncClient>()
Expand Down

0 comments on commit 7ae7f5b

Please sign in to comment.