akka.testkit.TestKitUtils.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2020-2021 Lightbend Inc.
*/
package akka.testkit
import java.lang.reflect.Modifier
import scala.util.matching.Regex
import akka.annotation.InternalApi
/**
* INTERNAL API
*/
@InternalApi
private[akka] object TestKitUtils {
def testNameFromCallStack(classToStartFrom: Class[_], testKitRegex: Regex): String = {
def isAbstractClass(className: String): Boolean = {
try {
Modifier.isAbstract(Class.forName(className).getModifiers)
} catch {
case _: Throwable => false // yes catch everything, best effort check
}
}
val startFrom = classToStartFrom.getName
val filteredStack = Thread.currentThread.getStackTrace.iterator
.map(_.getClassName)
// drop until we find the first occurrence of classToStartFrom
.dropWhile(!_.startsWith(startFrom))
// then continue to the next entry after classToStartFrom that makes sense
.dropWhile {
case `startFrom` => true
case str if str.startsWith(startFrom + "$") => true // lambdas inside startFrom etc
case testKitRegex() => true // testkit internals
case str if isAbstractClass(str) => true
case _ => false
}
if (filteredStack.isEmpty)
throw new IllegalArgumentException(s"Couldn't find [${classToStartFrom.getName}] in call stack")
// sanitize for actor system name
scrubActorSystemName(filteredStack.next())
}
/**
* Sanitize the `name` to be used as valid actor system name by
* replacing invalid characters. `name` may for example be a fully qualified
* class name and then the short class name will be used.
*/
def scrubActorSystemName(name: String): String = {
name
.replaceFirst("""^.*\.""", "") // drop package name
.replaceAll("""\$\$?\w+""", "") // drop scala anonymous functions/classes
.replaceAll("[^a-zA-Z_0-9-]", "_")
.replaceAll("""MultiJvmNode\d+""", "") // drop MultiJvm suffix
}
}