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

Do nothing if Action.StartDaemon being executed while already started #387

Merged
merged 5 commits into from
May 21, 2024
Merged
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
16 changes: 7 additions & 9 deletions library/runtime-core/api/runtime-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1170,10 +1170,10 @@ public class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply {
public synthetic fun <init> (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Ljava/lang/String;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public final fun equals (Ljava/lang/Object;)Z
public final fun hashCode ()I
public static final fun of (Ljava/lang/String;Ljava/lang/String;)Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply;
public fun toString ()Ljava/lang/String;
public final fun toString ()Ljava/lang/String;
}

public final class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Companion {
Expand All @@ -1182,14 +1182,15 @@ public final class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Companion {

public final class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error : java/lang/RuntimeException {
public static final field Companion Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error$Companion;
public final field jobName Ljava/lang/String;
public final field replies Ljava/util/List;
public synthetic fun <init> (Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public static final fun get (Ljava/util/List;)Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error;
public synthetic fun <init> (Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public static final fun get (Ljava/util/List;Ljava/lang/String;)Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error;
public fun getMessage ()Ljava/lang/String;
}

public final class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error$Companion {
public final fun get (Ljava/util/List;)Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error;
public final fun get (Ljava/util/List;Ljava/lang/String;)Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Error;
}

public class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Success : io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply {
Expand All @@ -1199,9 +1200,6 @@ public class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Success : io/matth

public final class io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Success$OK : io/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Success {
public static final field INSTANCE Lio/matthewnelson/kmp/tor/runtime/core/ctrl/Reply$Success$OK;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

public abstract class io/matthewnelson/kmp/tor/runtime/core/ctrl/TorCmd {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ import kotlin.jvm.JvmSynthetic
* @see [io.matthewnelson.kmp.tor.runtime.RuntimeEvent.ERROR]
* */
public class UncaughtException private constructor(
override val message: String,
override val cause: Throwable,
public override val message: String,
public override val cause: Throwable,
): Exception(message, cause) {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,42 +112,55 @@ public open class Reply private constructor(
*
* @see [toError]
* */
public class Error private constructor(replies: List<Reply>): RuntimeException() {
public class Error private constructor(
@JvmField
public val jobName: String,
replies: List<Reply>
): RuntimeException() {

@JvmField
public val replies: List<Reply> = replies.toImmutableList()

override val message: String by lazy { _message }
public override val message: String = buildString {
append("jobName: ")
append(jobName)
appendLine()

append("replies: [")
for (reply in [email protected]) {
appendLine()
append(" ")
append(reply)
}

@Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
private inline val _message: String get() = buildString {
replies.joinTo(this, separator = "\n")
appendLine()
append(']')
}

public companion object {

@JvmStatic
@JvmName("get")
@Throws(IllegalArgumentException::class)
public fun List<Reply>.toError(): Error {
public fun List<Reply>.toError(jobName: String): Error {
require(isNotEmpty()) { "replies cannot be empty" }
return Error(this)
return Error(jobName, this)
}
}
}

override fun equals(other: Any?): Boolean {
public final override fun equals(other: Any?): Boolean {
return other is Reply
&& other.status == status
&& other.message == message
}

override fun hashCode(): Int {
public final override fun hashCode(): Int {
var result = 17
result = result * 31 + status.hashCode()
result = result * 31 + message.hashCode()
return result
}

override fun toString(): String = "$status $message"
public final override fun toString(): String = "$status $message"
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ internal fun TorCmdJob<*>.respond(replies: ArrayList<Reply>) {
}

if (success == null) {
error(replies.toError())
error(replies.toError(name))
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,7 @@ class ProcessorUnitTest {
var threw: Throwable? = null
var invocationSuccess = 0
try {
val ctrl = try {
factory.connectAsync(address)
} catch (_: Throwable) {
withContext(Dispatchers.Default) { delay(350.milliseconds) }
factory.connectAsync(address)
}
val ctrl = factory.connectAsync(address)

val onFailure = OnFailure { threw = it }
val onSuccess = OnSuccess<Reply.Success.OK> { synchronized(lock) { invocationSuccess++ } }
Expand All @@ -78,6 +73,12 @@ class ProcessorUnitTest {
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)
ctrl.enqueue(TorCmd.Signal.Heartbeat, onFailure, onSuccess)

// Suspends test until non-suspending complete
ctrl.executeAsync(TorCmd.Signal.Dump)
Expand All @@ -97,22 +98,19 @@ class ProcessorUnitTest {
threw?.let { throw it }

// All commands for our test executed successfully
assertEquals(7, invocationSuccess)
assertEquals(3, invocationIntercept)
assertEquals(13, invocationSuccess)
assertEquals(9, invocationIntercept)

// Ensure that given our flurry of commands, a single processor
// coroutine was started to handle them all.
synchronized(lock) {
val processorStarts = debugLogs.mapNotNull {
// println(it)
if (it.contains("Processor Started")) it else null
}
val processorStarts = debugLogs.count { it.contains("Processor Started") }

// Simply need to know if the processor handled multiple
// commands when they were available, and other startProcessor
// calls were ignored (b/c was already looping). Cannot utilize
// a hard number because test will be flaky.
assertTrue(processorStarts.size < invocationSuccess)
assertTrue(processorStarts < invocationSuccess)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -508,9 +508,19 @@ internal class RealTorRuntime private constructor(
ensureActive()

val cmdQueue = _cmdQueue

// Should never be the case, but...
check(cmdQueue != null) { "cmdQueue cannot be null" }
cmdQueue.checkIsNotDestroyed()
check(cmdQueue.connection == null) { "cmdQueue already has a connection attach" }

cmdQueue.connection?.let { ctrl ->
// Should never be the case, but...
ctrl.checkIsNotDestroyed()

// Already started
NOTIFIER.d(this@ActionProcessor, "TorCtrl connection present. Already started.")
return
}

TorProcess.start(generator, NOTIFIER, scope, connect = {
val ctrl = connection.openWith(factory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,25 @@ class ServiceFactoryUnitTest {
lces.clear()
}

// Should already be started and do nothing
factory.startDaemonAsync()
withContext(Dispatchers.Default) { delay(50.milliseconds) }

synchronized(lock) { assertTrue(lces.isEmpty()) }

factory.restartDaemonAsync()
withContext(Dispatchers.Default) { delay(50.milliseconds) }

synchronized(lock) {
// Old process stopped
lces.assertContains("TorProcess", Lifecycle.Event.Name.OnDestroy, fid = factory)
lces.assertContains("RealTorCtrl", Lifecycle.Event.Name.OnDestroy, fid = factory)

// New process started
lces.assertContains("TorProcess", Lifecycle.Event.Name.OnCreate, fid = factory)
lces.assertContains("TorProcess", Lifecycle.Event.Name.OnStart, fid = factory)
lces.assertContains("RealTorCtrl", Lifecycle.Event.Name.OnCreate, fid = factory)

lces.assertDoesNotContain("RealTorRuntime", Lifecycle.Event.Name.OnDestroy, fid = factory)
lces.assertDoesNotContain("DestroyableTorRuntime", Lifecycle.Event.Name.OnDestroy, fid = factory)
lces.clear()
Expand Down
Loading