Skip to content

Commit

Permalink
feat: Native-image metadata for all modules (#32305)
Browse files Browse the repository at this point in the history
* feat: Native-image metadata for all modules

* Check in akka-actor metadata

* Some more manual ones

* Some more pluggable types

* Some more stuff

* akka-remote

* akka-cluster

* akka-cluster-metrics

* akka-cluster-sharding

* akka-cluster-sharding-typed

* akka-cluster-tools

* akka-cluster-typed

* akka-coordination

* akka-service-discovery

* akka-distributed-data

* akka-persistence

* akka-persistence-query

* akka-persistence-typed

* akka-pki

* akka-serialization-jackson

* akka-slf4j

* akka-stream

* akka-stream-typed

* Unsafe

* ClusterActorRefProvider

* LocalActorRefProvider

* RemoteActorRefProvider

* generic search for ClusterConfigChecker

* a bit more

* Trying out a CI test scheme inspired by akka-projection samples

* Most non-cluster features covered in native-image test and working
  • Loading branch information
johanandren committed Feb 13, 2024
1 parent 899e984 commit 0e6ac9c
Show file tree
Hide file tree
Showing 56 changed files with 3,062 additions and 4 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/native-image-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Native Image Tests

on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:

permissions:
contents: read

jobs:
native-image-tests:
name: Run Native Image Tests
runs-on: ubuntu-22.04
steps:
- name: Checkout
# https://github.com/actions/checkout/releases
# v4.1.1
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
with:
fetch-depth: 0

- name: Checkout GitHub merge
if: github.event.pull_request
run: |-
git fetch origin pull/${{ github.event.pull_request.number }}/merge:scratch
git checkout scratch
- name: Cache Coursier cache
# https://github.com/coursier/cache-action/releases
# v6.4.4
uses: coursier/cache-action@a0e7cd24be81bc84f0d7461e02bd1a96980553d7

- name: Set up JDK 11
# https://github.com/coursier/setup-action/releases
# v1.3.4
uses: coursier/setup-action@48280172a2c999022e42527711d6b28e4945e6f0
with:
jvm: temurin:1.11

- name: Gather version
run: |-
echo `git describe --tags | sed -e "s/v\(.*\)-\([0-9][0-9]*\).*/\\1-\\2-/"``git rev-parse HEAD | head -c8`-SNAPSHOT > ~/.version
cat ~/.version
- name: Publish artifacts locally
run: |-
sbt "publishLocal; publishM2"
- name: Local drone control sample Scala native image build
run: |-
cd native-image-tests/local-scala
sbt nativeImage -Dakka.version=`cat ~/.version`
# FIXME we need something more, actually running it as well to detect errors
205 changes: 205 additions & 0 deletions akka-actor-tests/src/test/scala/akka/NativeImageMetadataSpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
* Copyright (C) 2009-2023 Lightbend Inc. <https://www.lightbend.com>
*/

package akka

import akka.actor.ActorSystem
import akka.actor.DynamicAccess
import akka.actor.LocalActorRefProvider
import akka.actor.Props
import akka.event.EventStream
import akka.routing.RouterConfig
import akka.testkit.NativeImageUtils
import akka.testkit.NativeImageUtils.Constructor
import akka.testkit.NativeImageUtils.ReflectConfigEntry
import akka.testkit.NativeImageUtils.ReflectField
import akka.testkit.NativeImageUtils.ReflectMethod
import com.typesafe.config.ConfigFactory
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import akka.util.ccompat.JavaConverters._

object NativeImageMetadataSpec {

val metadataDir = NativeImageUtils.metadataDirFor("akka-actor")

val additionalEntries = Seq(
// dungeon or dungeon worthy unsafe trixery
// FIXME ugh, maybe we could reflect generate it instead of manually listing?
ReflectConfigEntry(
classOf[sun.misc.Unsafe].getName,
methods = Seq(
ReflectMethod("arrayBaseOff", parameterTypes = Seq("java.lang.Class")),
ReflectMethod("arrayIndexScale", parameterTypes = Seq("java.lang.Class")),
ReflectMethod("copyMemory", parameterTypes = Seq("long", "long", "long")),
ReflectMethod(
"copyMemory",
parameterTypes = Seq("java.lang.Object", "long", "java.lang.Object", "long", "long")),
ReflectMethod("getAndAddLong", parameterTypes = Seq("java.lang.Object", "long", "long")),
ReflectMethod("getAndSetObject", parameterTypes = Seq("java.lang.Object", "long", "java.lang.Object")),
ReflectMethod("getBoolean", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getByte", parameterTypes = Seq("long")),
ReflectMethod("getByte", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getDouble", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getFloat", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getInt", parameterTypes = Seq("long")),
ReflectMethod("getInt", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getLong", parameterTypes = Seq("long")),
ReflectMethod("getLong", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("getObject", parameterTypes = Seq("java.lang.Object", "long")),
ReflectMethod("invokeCleaner", parameterTypes = Seq("java.nio.ByteBuffer")),
ReflectMethod("objectFieldOffset", parameterTypes = Seq("java.lang.reflect.Field")),
ReflectMethod("putBoolean", parameterTypes = Seq("java.lang.Object", "long", "boolean")),
ReflectMethod("putByte", parameterTypes = Seq("long", "byte")),
ReflectMethod("putByte", parameterTypes = Seq("java.lang.Object", "long", "byte")),

Check failure on line 55 in akka-actor-tests/src/test/scala/akka/NativeImageMetadataSpec.scala

View workflow job for this annotation

GitHub Actions / Test Report

NativeImageMetadataSpec.Native-image metadata for akka-cluster should be up to date

org.scalatest.exceptions.TestFailedException: "[ { "name" : "akka.cluster.sbr.SplitBrainResolverProvider", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ActorSystem" ] } ] }, { "name" : "akka.cluster.ClusterActorRefProvider", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "java.lang.String", "akka.actor.ActorSystem$Settings", "akka.event.EventStream", "akka.actor.DynamicAccess" ] } ] }, { "name" : "akka.cluster.NoDowning", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ActorSystem" ] } ] }, { "name" : "akka.cluster.Cluster$", "fields" : [ { "name" : "MODULE$" } ] }, { "name" : "akka.cluster.protobuf.ClusterMessageSerializer", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ExtendedActorSystem" ] } ] }, { "name" : "akka.cluster.Cluster$$anon$1", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "com.typesafe.config.Config", "akka.event.LoggingAdapter", "java.util.concurrent.ThreadFactory" ] } ] }, { "name" : "akka.cluster.routing.ClusterRouterGroup" }, { "name" : "akka.cluster.routing.ClusterRouterPool" }, { "name" : "akka.cluster.JoinConfigCompatCheckCluster", "methods" : [ { "name" : "<init>" } ] }, { "name" : "akka.cluster.JoinConfigCompatChecker$$anon$1", "methods" : [ { "name" : "<init>" } ] } ]" did not equal "[ { "name" : "akka.cluster.sbr.SplitBrainResolverProvider", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ActorSystem" ] } ] }, { "name" : "akka.cluster.ClusterActorRefProvider", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "java.lang.String", "akka.actor.ActorSystem$Settings", "akka.event.EventStream", "akka.actor.DynamicAccess" ] } ] }, { "name" : "akka.cluster.NoDowning", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ActorSystem" ] } ] }, { "name" : "akka.cluster.Cluster$", "fields" : [ { "name" : "MODULE$" } ] }, { "name" : "akka.cluster.protobuf.ClusterMessageSerializer", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "akka.actor.ExtendedActorSystem" ] } ] }, { "name" : "akka.cluster.Cluster$$anon$1", "methods" : [ { "name" : "<init>", "parameterTypes" : [ "com.typesafe.config.Config", "akka.event.LoggingAdapter", "java.util.concurrent.ThreadFactory" ] } ] }, { "name" : "akka.cluster.routing.ClusterRouterGroup" }, { "name" : "akka.cluster.routing.ClusterRouterPool" }, { "name" : "akka.cluster.JoinConfigCompatCheckCluster", "methods" : [ { "name" : "<init>" } ] }, { "name" : "akka.cluster.JoinConfigCompatChecker$$anon$2", "methods" : [ { "name" : "<init>" } ] } ]"
Raw output
sbt.ForkMain$ForkError: org.scalatest.exceptions.TestFailedException: "[ {
  "name" : "akka.cluster.sbr.SplitBrainResolverProvider",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.ClusterActorRefProvider",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "java.lang.String", "akka.actor.ActorSystem$Settings", "akka.event.EventStream", "akka.actor.DynamicAccess" ]
  } ]
}, {
  "name" : "akka.cluster.NoDowning",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.Cluster$",
  "fields" : [ {
    "name" : "MODULE$"
  } ]
}, {
  "name" : "akka.cluster.protobuf.ClusterMessageSerializer",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ExtendedActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.Cluster$$anon$1",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "com.typesafe.config.Config", "akka.event.LoggingAdapter", "java.util.concurrent.ThreadFactory" ]
  } ]
}, {
  "name" : "akka.cluster.routing.ClusterRouterGroup"
}, {
  "name" : "akka.cluster.routing.ClusterRouterPool"
}, {
  "name" : "akka.cluster.JoinConfigCompatCheckCluster",
  "methods" : [ {
    "name" : "<init>"
  } ]
}, {
  "name" : "akka.cluster.JoinConfigCompatChecker$$anon$1",
  "methods" : [ {
    "name" : "<init>"
  } ]
} ]" did not equal "[ {
  "name" : "akka.cluster.sbr.SplitBrainResolverProvider",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.ClusterActorRefProvider",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "java.lang.String", "akka.actor.ActorSystem$Settings", "akka.event.EventStream", "akka.actor.DynamicAccess" ]
  } ]
}, {
  "name" : "akka.cluster.NoDowning",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.Cluster$",
  "fields" : [ {
    "name" : "MODULE$"
  } ]
}, {
  "name" : "akka.cluster.protobuf.ClusterMessageSerializer",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "akka.actor.ExtendedActorSystem" ]
  } ]
}, {
  "name" : "akka.cluster.Cluster$$anon$1",
  "methods" : [ {
    "name" : "<init>",
    "parameterTypes" : [ "com.typesafe.config.Config", "akka.event.LoggingAdapter", "java.util.concurrent.ThreadFactory" ]
  } ]
}, {
  "name" : "akka.cluster.routing.ClusterRouterGroup"
}, {
  "name" : "akka.cluster.routing.ClusterRouterPool"
}, {
  "name" : "akka.cluster.JoinConfigCompatCheckCluster",
  "methods" : [ {
    "name" : "<init>"
  } ]
}, {
  "name" : "akka.cluster.JoinConfigCompatChecker$$anon$2",
  "methods" : [ {
    "name" : "<init>"
  } ]
} ]"
	at org.scalatest.matchers.MatchersHelper$.indicateFailure(MatchersHelper.scala:392)
	at org.scalatest.matchers.should.Matchers.should(Matchers.scala:6956)
	at org.scalatest.matchers.should.Matchers.should$(Matchers.scala:1808)
	at akka.cluster.NativeImageMetadataSpec.should(NativeImageMetadataSpec.scala:50)
	at akka.cluster.NativeImageMetadataSpec.f$proxy1$1(NativeImageMetadataSpec.scala:57)
	at akka.cluster.NativeImageMetadataSpec.$init$$$anonfun$1$$anonfun$1(NativeImageMetadataSpec.scala:55)
	at org.scalatest.Transformer.apply$$anonfun$1(Transformer.scala:22)
	at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
	at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:31)
	at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
	at org.scalatest.Transformer.apply(Transformer.scala:22)
	at org.scalatest.Transformer.apply(Transformer.scala:21)
	at org.scalatest.wordspec.AnyWordSpecLike$$anon$3.apply(AnyWordSpecLike.scala:1118)
	at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
	at org.scalatest.TestSuite.withFixture$(TestSuite.scala:138)
	at org.scalatest.wordspec.AnyWordSpec.withFixture(AnyWordSpec.scala:1879)
	at org.scalatest.wordspec.AnyWordSpecLike.invokeWithFixture$1(AnyWordSpecLike.scala:1124)
	at org.scalatest.wordspec.AnyWordSpecLike.runTest$$anonfun$1(AnyWordSpecLike.scala:1128)
	at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
	at org.scalatest.wordspec.AnyWordSpecLike.runTest(AnyWordSpecLike.scala:1128)
	at org.scalatest.wordspec.AnyWordSpecLike.runTest$(AnyWordSpecLike.scala:44)
	at org.scalatest.wordspec.AnyWordSpec.runTest(AnyWordSpec.scala:1879)
	at org.scalatest.wordspec.AnyWordSpecLike.runTests$$anonfun$1(AnyWordSpecLike.scala:1187)
	at org.scalatest.SuperEngine.traverseSubNodes$1$$anonfun$1(Engine.scala:413)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:429)
	at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
	at org.scalatest.SuperEngine.traverseSubNodes$1$$anonfun$1(Engine.scala:427)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:15)
	at scala.runtime.function.JProcedure1.apply(JProcedure1.java:10)
	at scala.collection.immutable.List.foreach(List.scala:333)
	at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:429)
	at org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
	at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
	at org.scalatest.wordspec.AnyWordSpecLike.runTests(AnyWordSpecLike.scala:1187)
	at org.scalatest.wordspec.AnyWordSpecLike.runTests$(AnyWordSpecLike.scala:44)
	at org.scalatest.wordspec.AnyWordSpec.runTests(AnyWordSpec.scala:1879)
	at org.scalatest.Suite.run(Suite.scala:1114)
	at org.scalatest.Suite.run$(Suite.scala:564)
	at org.scalatest.wordspec.AnyWordSpec.org$scalatest$wordspec$AnyWordSpecLike$$super$run(AnyWordSpec.scala:1879)
	at org.scalatest.wordspec.AnyWordSpecLike.run$$anonfun$1(AnyWordSpecLike.scala:1232)
	at org.scalatest.SuperEngine.runImpl(Engine.scala:535)
	at org.scalatest.wordspec.AnyWordSpecLike.run(AnyWordSpecLike.scala:1232)
	at org.scalatest.wordspec.AnyWordSpecLike.run$(AnyWordSpecLike.scala:44)
	at org.scalatest.wordspec.AnyWordSpec.run(AnyWordSpec.scala:1879)
	at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:321)
	at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:517)
	at sbt.ForkMain$Run.lambda$runTest$1(ForkMain.java:414)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:840)
ReflectMethod("putDouble", parameterTypes = Seq("java.lang.Object", "long", "double")),
ReflectMethod("putFloat", parameterTypes = Seq("java.lang.Object", "long", "float")),
ReflectMethod("putInt", parameterTypes = Seq("long", "int")),
ReflectMethod("putInt", parameterTypes = Seq("java.lang.Object", "long", "int")),
ReflectMethod("putLong", parameterTypes = Seq("long", "long")),
ReflectMethod("putLong", parameterTypes = Seq("java.lang.Object", "long", "long")),
ReflectMethod("putObject", parameterTypes = Seq("java.lang.Object", "long", "java.lang.Object")),
ReflectMethod("storeFence", parameterTypes = Seq())),
allDeclaredFields = true),
// FIXME these are mostly "static" trixery, I wonder if graal can't figure them out itself without explicit listing
ReflectConfigEntry(
classOf[akka.actor.ActorCell].getName,
fields = Seq(
ReflectField("akka$actor$dungeon$Children$$_childrenRefsDoNotCallMeDirectly"),
ReflectField("akka$actor$dungeon$Children$$_functionRefsDoNotCallMeDirectly"),
ReflectField("akka$actor$dungeon$Children$$_nextNameDoNotCallMeDirectly"),
ReflectField("akka$actor$dungeon$Dispatch$$_mailboxDoNotCallMeDirectly"))),
ReflectConfigEntry(
classOf[akka.actor.RepointableRef].getName,
fields = Seq(ReflectField("_cellDoNotCallMeDirectly"), ReflectField("_lookupDoNotCallMeDirectly"))),
ReflectConfigEntry(
classOf[akka.pattern.CircuitBreaker].getName,
fields = Seq(
ReflectField("_currentResetTimeoutDoNotCallMeDirectly"),
ReflectField("_currentStateDoNotCallMeDirectly"))),
ReflectConfigEntry(
classOf[akka.pattern.PromiseActorRef].getName,
fields = Seq(ReflectField("_stateDoNotCallMeDirectly"), ReflectField("_watchedByDoNotCallMeDirectly"))),
ReflectConfigEntry("akka.actor.LightArrayRevolverScheduler$TaskHolder", fields = Seq(ReflectField("task"))),
// loaded via config
ReflectConfigEntry(
"akka.actor.LocalActorRefProvider$Guardian",
queryAllDeclaredConstructors = true,
methods = Seq(ReflectMethod(Constructor, Seq("akka.actor.SupervisorStrategy")))),
ReflectConfigEntry(
"akka.actor.LocalActorRefProvider$SystemGuardian",
queryAllDeclaredConstructors = true,
methods = Seq(ReflectMethod(Constructor, Seq("akka.actor.SupervisorStrategy", "akka.actor.ActorRef")))),
ReflectConfigEntry(
classOf[LocalActorRefProvider].getName,
methods = Seq(
ReflectMethod(
Constructor,
Seq(
classOf[java.lang.String].getName,
classOf[ActorSystem.Settings].getName,
classOf[EventStream].getName,
classOf[DynamicAccess].getName)))),
// left as reflection based to not break akka-remote remote deploy test
ReflectConfigEntry(classOf[Props.EmptyActor].getName, methods = Seq(ReflectMethod(Constructor))),
// affinity pool pluggable things
ReflectConfigEntry(
"akka.dispatch.affinity.ThrowOnOverflowRejectionHandler",
methods = Seq(ReflectMethod(Constructor, Seq.empty))),
ReflectConfigEntry(
"akka.dispatch.affinity.FairDistributionHashCache",
methods = Seq(ReflectMethod(Constructor, Seq("com.typesafe.config.Config")))),
// logging infra
ReflectConfigEntry(
classOf[akka.event.Logging.DefaultLogger].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor))),
ReflectConfigEntry(
classOf[akka.event.DefaultLoggingFilter].getName,
methods = Seq(
ReflectMethod(
NativeImageUtils.Constructor,
parameterTypes = Seq("akka.actor.ActorSystem$Settings", "akka.event.EventStream")))),
// akka io stuff
ReflectConfigEntry(
classOf[akka.io.InetAddressDnsProvider].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor))),
// FIXME remove these DNS related entries when removing the deprecated pluggable DNS setup and switch to non-reflective construction
// pluggable through deprecated InetAddressDnsProvider
ReflectConfigEntry(
classOf[akka.io.SimpleDnsManager].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor, parameterTypes = Seq("akka.io.DnsExt"))),
queryAllDeclaredConstructors = true),
ReflectConfigEntry(
classOf[akka.io.dns.internal.AsyncDnsProvider].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor, parameterTypes = Seq("akka.io.DnsExt"))),
queryAllDeclaredConstructors = true),
// pluggable through deprecated InetAddressDnsProvider.actorClass
ReflectConfigEntry(
classOf[akka.io.InetAddressDnsResolver].getName,
methods = Seq(
ReflectMethod(
NativeImageUtils.Constructor,
parameterTypes = Seq("akka.io.SimpleDnsCache", "com.typesafe.config.Config"))),
queryAllDeclaredConstructors = true),
ReflectConfigEntry(
"akka.io.dns.internal.AsyncDnsResolver",
methods = Seq(
ReflectMethod(
NativeImageUtils.Constructor,
parameterTypes = Seq(
"akka.io.SimpleDnsCache",
"com.typesafe.config.Config",
"scala.Function2<akka.actor.ActorRefFactory,scala.collection.immutable.List<java.net.InetSocketAddress>,scala.collection.immutable.List<akka.actor.ActorRef>>"))),
queryAllDeclaredConstructors = true),
// pluggable through deprecated InetAddressDnsProvider.managerClass
ReflectConfigEntry(
classOf[akka.io.SimpleDnsManager].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor, parameterTypes = Seq("akka.io.DnsExt"))),
queryAllDeclaredConstructors = true),
ReflectConfigEntry(
"akka.io.dns.internal.AsyncDnsManager",
methods = Seq(ReflectMethod(NativeImageUtils.Constructor, parameterTypes = Seq("akka.io.DnsExt"))),
queryAllDeclaredConstructors = true),
// Internal Routing infra
ReflectConfigEntry(
classOf[akka.routing.RoutedActorCell.RouterActorCreator].getName,
methods = Seq(ReflectMethod(NativeImageUtils.Constructor, parameterTypes = Seq(classOf[RouterConfig].getName))))) ++ serializationBindingTypeEntries

def serializationBindingTypeEntries = {
// we bind a bunch of stdlib and primitive types in akka-core (not what you'd normally do)
val config = ConfigFactory.load()
config.getConfig("akka.actor.serialization-bindings").root().unwrapped().keySet().asScala.map { typeName =>
ReflectConfigEntry(typeName)
}
}

val modulePackages = Seq(
"akka.actor",
"akka.dispatch",
"akka.event",
"akka.io",
"akka.japi",
"akka.pattern",
"akka.routing",
"akka.serialization",
"akka.util")

// run this to regenerate metadata 'akka-actor-tests/Test/runMain akka.NativeImageMetadataSpec'
def main(args: Array[String]): Unit = {
NativeImageUtils.writeMetadata(metadataDir, additionalEntries, modulePackages)
}
}

class NativeImageMetadataSpec extends AnyWordSpec with Matchers {
import NativeImageMetadataSpec._

"Native-image metadata for akka-actor" should {

"be up to date" in {
val (existing, current) = NativeImageUtils.verifyMetadata(metadataDir, additionalEntries, modulePackages)
existing should ===(current)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2009-2023 Lightbend Inc. <https://www.lightbend.com>
*/

package akka.actor.typed

import akka.testkit.NativeImageUtils
import akka.testkit.NativeImageUtils.ModuleField
import akka.testkit.NativeImageUtils.ReflectConfigEntry
import akka.testkit.NativeImageUtils.ReflectField
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec

object NativeImageMetadataSpec {

val metadataDir = NativeImageUtils.metadataDirFor("akka-actor-typed")

val additionalEntries = Seq(
ReflectConfigEntry(
"akka.actor.typed.internal.adapter.ActorSystemAdapter$LoadTypedExtensions$",
fields = Seq(ReflectField("MODULE$"))),
// trixery around auto-selecting local or cluster receptionist impl
ReflectConfigEntry(
classOf[akka.actor.typed.internal.receptionist.LocalReceptionist.type].getName,
fields = Seq(ModuleField))) ++ serializationBindingTypeEntries

val modulePackages = Seq("akka.actor.typed")

def serializationBindingTypeEntries = {
// Note: can't load from config because we'd get entries from all the other modules on classpath
Set(
"akka.actor.typed.ActorRef",
"akka.actor.typed.internal.adapter.ActorRefAdapter",
"akka.actor.typed.internal.receptionist.DefaultServiceKey").map { typeName =>
ReflectConfigEntry(typeName)
}
}

// run this to regenerate metadata 'akka-actor-typed-tests/Test/runMain akka.actor.typed.NativeImageMetadataSpec'
def main(args: Array[String]): Unit = {
NativeImageUtils.writeMetadata(metadataDir, additionalEntries, modulePackages)
}
}

class NativeImageMetadataSpec extends AnyWordSpec with Matchers {
import NativeImageMetadataSpec._

"Native-image metadata for akka-actor-typed" should {

"be up to date" in {
val (existing, current) = NativeImageUtils.verifyMetadata(metadataDir, additionalEntries, modulePackages)
existing should ===(current)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
[ {
"name" : "akka.actor.typed.internal.adapter.ActorSystemAdapter$LoadTypedExtensions$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.receptionist.LocalReceptionist$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.ActorRef"
}, {
"name" : "akka.actor.typed.internal.adapter.ActorRefAdapter"
}, {
"name" : "akka.actor.typed.internal.receptionist.DefaultServiceKey"
}, {
"name" : "akka.actor.typed.internal.adapter.ActorSystemAdapter$AdapterExtension$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.adapter.ActorSystemAdapter$LoadTypedExtensions$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.adapter.AdapterExtension$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.MiscMessageSerializer",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ "akka.actor.ExtendedActorSystem" ]
} ]
}, {
"name" : "akka.actor.typed.internal.receptionist.ServiceKeySerializer",
"methods" : [ {
"name" : "<init>",
"parameterTypes" : [ "akka.actor.ExtendedActorSystem" ]
} ]
}, {
"name" : "akka.actor.typed.ActorRefResolver$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.ActorFlightRecorder$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.internal.EventStreamExtension$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.pubsub.PubSub$",
"fields" : [ {
"name" : "MODULE$"
} ]
}, {
"name" : "akka.actor.typed.receptionist.Receptionist$",
"fields" : [ {
"name" : "MODULE$"
} ]
} ]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Args = --enable-monitoring=jfr
Loading

0 comments on commit 0e6ac9c

Please sign in to comment.