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

[pekko-testkit-typed] Support for Junit5 #445

Closed
wants to merge 72 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
9e68f05
junit5 extension and tests
Jun 21, 2023
2e6ae54
cleanup merge residuals in Dependencies.scala
Jun 21, 2023
d895234
added config value for test
Jun 21, 2023
7e6a230
changed junit5 version to 5.9.3
Jun 21, 2023
07ae196
added results of scalafmt run
Jun 21, 2023
b7e06ee
removed unnecessary license header
Jun 21, 2023
3a96f71
added class copy notice
Jun 21, 2023
367ec78
deleted unnecessary import
Jun 22, 2023
9f0a81a
scalafmt reformat
Jun 22, 2023
b8c83b6
scalafmt reformat
Jun 22, 2023
b1c7d1a
Merge branch 'apache:main' into junit5-extension
thmue Jun 22, 2023
449b041
scalafmt reformat
Jun 24, 2023
fb1a88a
scalafmt reformat
Jun 26, 2023
f07bd69
recreate headers
Jun 26, 2023
a07a0e1
replaced headers
Jun 26, 2023
ef1ec63
replaced 2.13 list handling with ccoompat to support 2.12/2.13
Jun 26, 2023
cccc892
added error handling if annotated field is missing
Jun 26, 2023
3046170
moved annotation to java package
Jun 28, 2023
d9b3142
simplified code
Jul 2, 2023
d9a2ca0
updated headers
Jul 3, 2023
85c0df1
updated headers to full ASF header lic
Jul 3, 2023
761bdae
Merge branch 'apache:main' into junit5-extension
thmue Oct 14, 2023
2ae605d
updated deps, changed case class to class, aligned imports
Oct 14, 2023
b882379
reverted change
Oct 14, 2023
57d6421
formating javafmtCheck
Oct 14, 2023
0b3dc44
Update sbt-scalafix to 0.11.1 (#709)
scala-steward-asf[bot] Oct 15, 2023
3101167
Update sbt-dynver to 5.0.1 (#711)
scala-steward-asf[bot] Oct 15, 2023
fa0a509
Update sbt-license-report to 1.6.1 (#716)
scala-steward-asf[bot] Oct 15, 2023
3d47f05
Update gson to 2.10.1 (#717)
scala-steward-asf[bot] Oct 15, 2023
77ff42d
Update logback-classic to 1.2.12 (#710)
scala-steward-asf[bot] Oct 15, 2023
e72dfa5
Update lmdbjava to 0.8.3 (#731)
scala-steward-asf[bot] Oct 15, 2023
567c4b6
Update sbt-jmh to 0.4.6 (#734)
scala-steward-asf[bot] Oct 15, 2023
6d25bb0
Update jctools-core to 4.0.1 (#730)
scala-steward-asf[bot] Oct 15, 2023
a8d8ece
Update commons-compress to 1.24.0 (#728)
scala-steward-asf[bot] Oct 15, 2023
279ec93
Update bcpkix-jdk15on to 1.70 (#729)
scala-steward-asf[bot] Oct 15, 2023
21bb4dd
Update metrics-core, metrics-jvm to 4.2.21 (#726)
scala-steward-asf[bot] Oct 15, 2023
69e192b
Update commons-io to 2.14.0 (#725)
scala-steward-asf[bot] Oct 15, 2023
45d6b7d
Update asn-one to 0.6.0 (#719)
scala-steward-asf[bot] Oct 15, 2023
2615e35
Update jimfs to 1.3.0 (#718)
scala-steward-asf[bot] Oct 15, 2023
49f2f07
Update commons-codec to 1.16.0 (#724)
scala-steward-asf[bot] Oct 15, 2023
ddb4909
Sidestep reproducibility issue (#708)
raboof Oct 15, 2023
955b622
scalatest 3.2.17 (#735)
pjfanning Oct 15, 2023
5314dcf
use bcpkix-jdk18on (jdk15on no longer published)
pjfanning Oct 15, 2023
a603d47
Update sigar-loader to 1.6.6 (#727)
scala-steward-asf[bot] Oct 16, 2023
a99dbda
=sbt Update sbt-welcome to 0.3.2
He-Pin Oct 16, 2023
2e19bf1
Add more ignored dependencies to .scala-steward.conf
mdedetrich Oct 16, 2023
a5899c7
on each PR, do a full local publish (#691)
pjfanning Oct 16, 2023
a0811b2
junit5 extension and tests
Jun 21, 2023
e656dd3
cleanup merge residuals in Dependencies.scala
Jun 21, 2023
51d1fb5
added config value for test
Jun 21, 2023
478ff7d
changed junit5 version to 5.9.3
Jun 21, 2023
92e8cc3
added results of scalafmt run
Jun 21, 2023
7478787
removed unnecessary license header
Jun 21, 2023
3e94070
added class copy notice
Jun 21, 2023
0ac3496
deleted unnecessary import
Jun 22, 2023
691706a
scalafmt reformat
Jun 22, 2023
e756455
scalafmt reformat
Jun 22, 2023
9d91038
scalafmt reformat
Jun 24, 2023
c71034c
scalafmt reformat
Jun 26, 2023
46a1f74
recreate headers
Jun 26, 2023
448c927
replaced headers
Jun 26, 2023
656feb5
replaced 2.13 list handling with ccoompat to support 2.12/2.13
Jun 26, 2023
3786acb
added error handling if annotated field is missing
Jun 26, 2023
aa9ae7a
moved annotation to java package
Jun 28, 2023
fb9c333
simplified code
Jul 2, 2023
cd923da
updated headers
Jul 3, 2023
dace911
updated headers to full ASF header lic
Jul 3, 2023
9eed963
updated deps, changed case class to class, aligned imports
Oct 14, 2023
e421ef4
reverted change
Oct 14, 2023
b05b40f
formating javafmtCheck
Oct 14, 2023
e717dec
rebased
Oct 16, 2023
58ae5da
Merge remote-tracking branch 'origin/junit5-extension' into junit5-ex…
Oct 16, 2023
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package org.apache.pekko.actor.testkit.typed.javadsl;


thmue marked this conversation as resolved.
Show resolved Hide resolved
import java.lang.annotation.*;

@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Junit5TestKit {
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package org.apache.pekko.actor.testkit.typed.javadsl

import com.typesafe.config.Config
import org.apache.pekko.actor.testkit.typed.internal.TestKitUtils
import org.apache.pekko.actor.testkit.typed.scaladsl.ActorTestKit.ApplicationTestConfig
import org.apache.pekko.actor.typed.ActorSystem

case class Junit5TestKitBuilder() {
thmue marked this conversation as resolved.
Show resolved Hide resolved

var system: Option[ActorSystem[_]] = None

var customConfig: Config = ApplicationTestConfig

var name: String = TestKitUtils.testNameFromCallStack(classOf[Junit5TestKitBuilder])

def withSystem(system: ActorSystem[_]): Junit5TestKitBuilder = {
this.system = Some(system)
this
}

def withCustomConfig(customConfig: Config): Junit5TestKitBuilder = {
this.customConfig = customConfig
this
}

def withName(name: String): Junit5TestKitBuilder = {
this.name = name
this
}

def build(): ActorTestKit = {
if (system.isDefined) {
return ActorTestKit.create(system.get)
}
ActorTestKit.create(name, customConfig)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package org.apache.pekko.actor.testkit.typed.javadsl

import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation
import org.junit.jupiter.api.extension.{ ExtensionContext, InvocationInterceptor, ReflectiveInvocationContext }
import org.slf4j.LoggerFactory
import org.apache.pekko.actor.testkit.typed.internal.CapturingAppender

import java.lang.reflect.Method
import scala.util.control.NonFatal

final class LogCapturingExtension extends InvocationInterceptor {

private val capturingAppender = CapturingAppender.get("")

private val myLogger = LoggerFactory.getLogger(classOf[LogCapturing])

@throws[Throwable]
override def interceptTestMethod(invocation: Invocation[Void], invocationContext: ReflectiveInvocationContext[Method],
extensionContext: ExtensionContext): Unit = {

val testClassName = invocationContext.getTargetClass.getSimpleName
val testMethodName = invocationContext.getExecutable.getName

try {
myLogger.info(s"Logging started for test [${testClassName}: ${testMethodName}]")
invocation.proceed
myLogger.info(
s"Logging finished for test [${testClassName}: ${testMethodName}] that was successful")
} catch {
case NonFatal(e) =>
println(
s"--> [${Console.BLUE}${testClassName}: ${testMethodName}${Console.RESET}] " +
s"Start of log messages of test that failed with ${e.getMessage}")
capturingAppender.flush()
println(
s"<-- [${Console.BLUE}${testClassName}: ${testMethodName}${Console.RESET}] " +
s"End of log messages of test that failed with ${e.getMessage}")
throw e
} finally {

capturingAppender.clear()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package org.apache.pekko.actor.testkit.typed.javadsl

import org.junit.jupiter.api.extension.{ AfterAllCallback, BeforeTestExecutionCallback, ExtensionContext }
import org.junit.platform.commons.support.AnnotationSupport
import org.apache.pekko
import pekko.util.ccompat.JavaConverters.CollectionHasAsScala

final class TestKitJunit5Extension() extends AfterAllCallback with BeforeTestExecutionCallback {

var testKit: Option[ActorTestKit] = None

/**
* Get a reference to the field annotated with @Junit5Testkit [[pekko.actor.testkit.typed.javadsl.Junit5TestKit]]
*/
override def beforeTestExecution(context: ExtensionContext): Unit = {

context.getTestInstance.ifPresent((instance: AnyRef) => {
val annotations = AnnotationSupport.findAnnotatedFieldValues(instance, classOf[Junit5TestKit])
if (annotations.isEmpty) {
throw new IllegalArgumentException("Could not find field annotated with @Junit5TestKit")
} else {
val fieldValue = annotations.asScala.toList.head
testKit = Some(fieldValue.asInstanceOf[ActorTestKit])
}
})
}

/**
* Shutdown testKit
*/
override def afterAll(context: ExtensionContext): Unit = {
testKit.get.shutdownTestKit()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package jdocs.org.apache.pekko.actor.testkit.typed.javadsl

import org.apache.pekko.actor.typed.{ ActorRef, Behavior }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this following import style

import org.apache.pekko
import pekko.actor.typed.{ ActorRef, Behavior }
import pekko.actor.typed.scaladsl.Behaviors

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it to a normal class

import org.apache.pekko.actor.typed.scaladsl.Behaviors

object Greeter {
final case class Greet(whom: String, replyTo: ActorRef[Greeted])
final case class Greeted(whom: String, from: ActorRef[Greet])

def apply(): Behavior[Greet] = Behaviors.receive { (context, message) =>
context.log.info("Hello {}!", message.whom)
// #greeter-send-messages
message.replyTo ! Greeted(message.whom, context.self)
// #greeter-send-messages
Behaviors.same
}
}

object GreeterBot {

def apply(max: Int): Behavior[Greeter.Greeted] = {
bot(0, max)
}

private def bot(greetingCounter: Int, max: Int): Behavior[Greeter.Greeted] =
Behaviors.receive { (context, message) =>
val n = greetingCounter + 1
context.log.info("Greeting {} for {}", n, message.whom)
if (n == max) {
Behaviors.stopped
} else {
message.from ! Greeter.Greet(message.whom, context.self)
bot(n, max)
}
}
}

object GreeterMain {

final case class SayHello(name: String)

def apply(): Behavior[SayHello] =
Behaviors.setup { context =>
val greeter = context.spawn(Greeter(), "greeter")

Behaviors.receiveMessage { message =>
val replyTo = context.spawn(GreeterBot(max = 3), message.name)
greeter ! Greeter.Greet(message.name, replyTo)
Behaviors.same
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

// test code copied from JunitIntegrationTest.java

package jdocs.org.apache.pekko.actor.testkit.typed.javadsl;

import org.apache.pekko.actor.Address;
import org.apache.pekko.actor.testkit.typed.javadsl.*;
import org.apache.pekko.actor.testkit.typed.javadsl.Junit5TestKitBuilder;
import org.apache.pekko.actor.typed.ActorRef;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

// #junit5-integration
@DisplayName("Junit5")
@ExtendWith(TestKitJunit5Extension.class)
class Junit5IntegrationExampleTest {

@Junit5TestKit public ActorTestKit testKit = new Junit5TestKitBuilder().build();

@Test
void junit5Test() {
Address address = testKit.system().address();
assertNotNull(address);
}

@Test
void testSomething() {

ActorRef<AsyncTestingExampleTest.Echo.Ping> pinger =
testKit.spawn(AsyncTestingExampleTest.Echo.create(), "ping");
TestProbe<AsyncTestingExampleTest.Echo.Pong> probe = testKit.createTestProbe();
pinger.tell(new AsyncTestingExampleTest.Echo.Ping("hello", probe.ref()));
AsyncTestingExampleTest.Echo.Pong pong =
probe.expectMessage(new AsyncTestingExampleTest.Echo.Pong("hello"));
assertEquals("hello", pong.message);
}

@Test
void testSomething2() {
ActorRef<AsyncTestingExampleTest.Echo.Ping> pinger2 =
testKit.spawn(AsyncTestingExampleTest.Echo.create(), "ping2");
TestProbe<AsyncTestingExampleTest.Echo.Pong> probe2 = testKit.createTestProbe();
pinger2.tell(new AsyncTestingExampleTest.Echo.Ping("hello", probe2.ref()));
AsyncTestingExampleTest.Echo.Pong pong =
probe2.expectMessage(new AsyncTestingExampleTest.Echo.Pong("hello"));
assertEquals("hello", pong.message);
}
}
// #junit5-integration
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* license agreements; and to You under the Apache License, version 2.0:
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* This file is part of the Apache Pekko project, which was derived from Akka.
*/

package jdocs.org.apache.pekko.actor.testkit.typed.javadsl;

// #log-capturing-junit5

import org.apache.pekko.actor.testkit.typed.javadsl.*;
import org.apache.pekko.actor.testkit.typed.javadsl.Junit5TestKitBuilder;
import org.apache.pekko.actor.typed.ActorRef;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import static jdocs.org.apache.pekko.actor.testkit.typed.javadsl.AsyncTestingExampleTest.Echo;

// test code copied from LogCapturingExampleTest.java

@DisplayName("Junit5 log capturing")
@ExtendWith(TestKitJunit5Extension.class)
@ExtendWith(LogCapturingExtension.class)
class LogCapturingExtensionExampleTest {

@Junit5TestKit public ActorTestKit testKit = new Junit5TestKitBuilder().build();

@Test
void testSomething() {
ActorRef<Echo.Ping> pinger = testKit.spawn(Echo.create(), "ping");
TestProbe<Echo.Pong> probe = testKit.createTestProbe();
pinger.tell(new Echo.Ping("hello", probe.ref()));
probe.expectMessage(new Echo.Pong("hello"));
}

@Test
void testSomething2() {
ActorRef<Echo.Ping> pinger = testKit.spawn(Echo.create(), "ping");
TestProbe<Echo.Pong> probe = testKit.createTestProbe();
pinger.tell(new Echo.Ping("hello", probe.ref()));
probe.expectMessage(new Echo.Pong("hello"));
}
}
// #log-capturing-junit5
Loading