In previous versions, I could deploy Verticle in the following code.
#BeforeEach
fun deploy(vertx: Vertx, testContext: VertxTestContext) {
val web = vertx.deployVerticle(WebVerticle())
val database = vertx.deployVerticle(DatabaseVerticle())
CompositeFuture.all(web, database).handler = testContext.succeeding {
testContext.completeNow()
}
}
But in 4.0.0-SNAPSHOT, the handler is val, there's only a get method.
I have tried these methods.
CompositeFuture.all(web, database).onSuccess {
testContext.succeeding<Any> {
testContext.completeNow()
}
}
// Or
CompositeFuture.all(web, database).onSuccess {
testContext.completing<Any>()
}
// Or
CompositeFuture.all(web, database).onComplete {
testContext.succeeding<Any> {
testContext.completeNow()
}
}
Result: java.util.concurrent.TimeoutException. He has been waiting for this method to end and I don't know how to deal with it
How can I write code to get the same effect?
Thanks!
When you write your code in Kotlin, it would be even more simple to use the corresponding "...Await" functions, available in the modules:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-lang-kotlin</artifactId>
<version>4.0.0-milestone4</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-lang-kotlin-coroutines</artifactId>
<version>4.0.0-milestone4</version>
</dependency>
This way you are enabled to use the function deployVerticleAwait instead. But you must run this code wihtin a coroutine. A further, simple way is to use extension functions for test executing purposes, like:
fun Vertx.testAsync(testContext: VertxTestContext, block: suspend CoroutineScope.() -> Unit) {
CoroutineScope(this.dispatcher()).launch {
runCatching { block(this) }.onSuccess { testContext.completeNow() }.onFailure { testContext.failNow(it) }
}
}
An a final test function then can look like:
#Test
internal fun my_test(vertx: Vertx, testContext: VertxTestContext) =
vertx.testAsync(testContext) {
// Do some things within this coroutine
}
Since you cross-posted to the Vert.x users mailing list I am replying there instead.
Related
I using testcontainer and macbook m1. When i start testContainer it thow me error:
Could not pull image: no matching manifest for linux/arm64/v8 in the manifest list entries
I can't understand why because when i using postgres it ok.
Here is my config. Please help
open class MySqlResourceTest : QuarkusTestResourceLifecycleManager {
private val DATABASE: SpecifiedMySQLContainer = SpecifiedMySQLContainer("mysql:5.7.8").apply {
withDatabaseName("test")
withUsername("abc")
withPassword("123456")
withExposedPorts(3317)
}
override fun start(): MutableMap<String, String> {
DATABASE.start()
DATABASE.setCommand()
return Collections.singletonMap("quarkus.datasource.url", DATABASE.jdbcUrl)
}
override fun stop() {
DATABASE.stop()
}
}
Common testcontainer for MySql is org.testcontainers.containers.MySQLContainer. You're using a SpecifiedMySQLContainer in your code snippet, which may cause the issue.
I'm building an app for a friend and I use Firestore. What I want is to display a list of favorite places but for some reason, the list is always empty.
I cannot get the data from Firestore. This is my code:
fun getListOfPlaces() : List<String> {
val places = ArrayList<String>()
placesRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
for (document in task.result) {
val name = document.data["name"].toString()
places.add(name)
}
}
}
return list;
}
If I try to print, let's say the size of the list in onCreate function, the size is always 0.
Log.d("TAG", getListOfPlaces().size().toString()); // Is 0 !!!
I can confirm Firebase is successfully installed.
What am I missing?
This is a classic issue with asynchronous web APIs. You cannot return something now, that hasn't been loaded yet. With other words, you cannot simply return the places list as a result of a method because it will always be empty due the asynchronous behavior of the onComplete function. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.
But not only Cloud Firestore loads data asynchronously, almost all of modern other web APIs do, since it may take some time to get the data. But let's take an quick example, by placing a few log statements in the code, to see more clearly what I'm talking about.
fun getListOfPlaces() : List<String> {
Log.d("TAG", "Before attaching the listener!");
val places = ArrayList<String>()
placesRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
Log.d("TAG", "Inside onComplete function!");
for (document in task.result) {
val name = document.data["name"].toString()
places.add(name)
}
}
}
Log.d("TAG", "After attaching the listener!");
return list;
}
If we run this code will, the output in your logcat will be:
Before attaching the listener!
After attaching the listener!
Inside onComplete function!
This is probably not what you expected, but it explains precisely why your places list is empty when returning it.
The initial response for most developers is to try and "fix" this asynchronous behavior, which I personally recommend against it. Here is an excelent article written by Doug Stevenson that I'll highly recommend you to read.
A quick solve for this problem would be to use the places list only inside the onComplete function:
fun readData() {
placesRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val list = ArrayList<String>()
for (document in task.result) {
val name = document.data["name"].toString()
list.add(name)
}
//Do what you need to do with your list
}
}
}
If you want to use the list outside, there is another approach. You need to create your own callback to wait for Firestore to return you the data. To achieve this, first you need to create an interface like this:
interface MyCallback {
fun onCallback(value: List<String>)
}
Then you need to create a function that is actually getting the data from the database. This method should look like this:
fun readData(myCallback : MyCallback) {
placesRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val list = ArrayList<String>()
for (document in task.result) {
val name = document.data["name"].toString()
list.add(name)
}
myCallback.onCallback(list)
}
}
}
See, we don't have any return type anymore. In the end just simply call readData() function in your onCreate function and pass an instance of the MyCallback interface as an argument like this:
readData(object: MyCallback {
override fun onCallback(value: List<String>) {
Log.d("TAG", list.size.toString())
}
})
If you are using Kotlin, please check the other answer.
Nowadays, Kotlin provides a simpler way to achieve the same result as in the case of using a callback. This answer is going to explain how to use Kotlin Coroutines. In order to make it work, we need to add the following dependency in our build.gradle file:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.2.1"
This library that we use is called Module kotlinx-coroutines-play-services and is used for the exact same purpose. As we already know, there is no way we can return a list of objects as a result of a method because get() returns immediately, while the callback from the Task it returns will be called sometime later. That's the reason why we should wait until the data is available.
When calling "get()" on the Task object that is returned, we can attach a listener so we can get the result of our query. What we need to do now is to convert this into something that is working with Kotlin Coroutines. For that, we need to create a suspend function that looks like this:
private suspend fun getListOfPlaces(): List<DocumentSnapshot> {
val snapshot = placesRef.get().await()
return snapshot.documents
}
As you can see, we have now an extension function called await() that will interrupt the Coroutine until the data from the database is available and then return it. Now we can simply call it from another suspend method like in the following lines of code:
private suspend fun getDataFromFirestore() {
try {
val listOfPlaces = getListOfPlaces()
} catch (e: Exception) {
Log.d(TAG, e.getMessage()) //Don't ignore potential errors!
}
}
The reason for having a empty list got perfectly answered by Alex Mamo above.
I just like to present the same thing without needing to add an extra interface.
In Kotlin you could just implement it like so:
fun readData(myCallback: (List<String>) -> Unit) {
placesRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val list = ArrayList<String>()
for (document in task.result) {
val name = document.data["name"].toString()
list.add(name)
}
myCallback(list)
}
}
}
and then use it like so:
readData() {
Log.d("TAG", it.size.toString())
})
I've created a method, and the return is Result<R> in a class of MyClass<R>, but the error message is: 'kotlin.Result' cannot be used as a return type
I've also looked into the Result source code for some hints; why is this so?
Test code (using v. 1.3-RC).
class MyClass<R>(val r: R) {
fun f(): Result<R> { // error here
return Result.success(r)
}
}
fun main(args: Array<String>) {
val s = Result.success(1)
val m = MyClass(s)
}
From the Kotlin KEEP:
The rationale behind these limitations is that future versions of
Kotlin may expand and/or change semantics of functions that return
Result type and null-safety operators may change their semantics when
used on values of Result type. In order to avoid breaking existing
code in the future releases of Kotin and leave door open for those
changes, the corresponding uses produce an error now. Exceptions to
this rule are made for carefully-reviewed declarations in the standard
library that are part of the Result type API itself.
Note: if you just want to experiment with the Result type you can bypass this limitation by supplying a Kotlin compiler argument -Xallow-result-return-type.
When using Gradle on Java or Android project:
Define the compiler argument on Kotlin compilation task. It applies both for production code and tests.
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xallow-result-return-type"
}
}
When using Gradle on Multiplatform project:
Define the compiler argument for each target compilation. It applies both for production code and tests.
kotlin {
targets.all {
compilations.all {
kotlinOptions {
freeCompilerArgs = freeCompilerArgs + "-Xallow-result-return-type"
}
}
}
}
android {
kotlinOptions {
freeCompilerArgs = ["-Xallow-result-return-type"]
}
}
If you using android this solution for gradle
If using maven:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<jvmTarget>1.8</jvmTarget>
<args>
<arg>-Xallow-result-return-type</arg>
</args>
</configuration>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
If using gradle:
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.freeCompilerArgs = ["-Xallow-result-return-type"]
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.freeCompilerArgs = ["-Xallow-result-return-type"]
}
Source: http://rustyrazorblade.com/post/2018/2018-12-06-kotlin-result/
Update the kotlin version to 1.5 or above. See:
https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/result.md#limitations-legacy
In JUnit 4 you could use a Rule to wrap a test so that you could execute code both before and after a test had run. In most cases this could be accomplished with an #Before and #After method or an ExternalResource rule. However some control flow constructs (like try-with-resources) cannot be split into two methods. In most cases, there are alternatives to these constructs which allow you to split them into two methods. For example, with try-with-resources, you can manually acquire and close a resource instead of using a try block.
The specific problem that I have run into is that the database library I use, jOOQ, only has transaction methods that take a callback. (See https://www.jooq.org/doc/latest/manual/sql-execution/transaction-management/) You cannot call something like:
context.startTransaction()
doStuff()
context.commit() // Or rollback()
In JUnit4 this is ok because you can write a rule like so (in Kotlin, but the equivalent works in Java):
class TransactionRule(private val dbSessionManager: DBSessionManager) : TestRule {
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
dbSessionManager.transaction {
base.evaluate()
}
}
}
}
}
Is there anything similar in JUnit 5?
You can write an InvocationInterceptor in place of the JUnit4 rule:
public class TransactionInvocationInterceptor implements InvocationInterceptor {
#Override
public void interceptTestMethod(Invocation<Void> invocation,
ReflectiveInvocationContext<Method> invocationContext,
ExtensionContext extensionContext) throws Throwable {
runInTransaction(() -> {
try {
invocation.proceed();
} catch (Throwable t) {
throw new RuntimeException(t);
}
});
}
}
#ExtendWith(TransactionInvocationInterceptor.class)
class InvocationInterceptorTest {
#Test
void test() {
…
}
}
One difference is that interceptTestMethod only wraps the test method, not other lifecycle methods such as beforeEach. It's possible to intercept the other lifecycle methods individually with the other methods in InvocationInterceptor, but not multiple at a time (for example, if you want to call both beforeEach and the test method in one transaction).
From what I understand you can't use the JUnit 5 test lifecycle callbacks as they would require you to follow the doStuff route with context calls Before/After that you indicate won't work.
Would using JUnit 5 Dynamic Tests instead work?
This provides for test factories consisting of collections of dynamic test with a name and an executable (lambda). You could then do something like this:
import static org.junit.jupiter.api.DynamicTest.dynamicTest;
import org.junit.jupiter.api.function.Executable;
#TestFactory
Collection<DynamicTest> transactionTestCollection() {
return Arrays.asList(
dbTest("1st dynamic test", () -> assertTrue(true)),
dbTest("2nd dynamic test", () -> assertEquals(4, 2 * 2))
);
}
private DynamicTest dbTest(String name, Executable tst) {
return dynamicTest(name, () -> dbSessionManager.transaction(tst));
}
I'm trying to setup TeamCity, using config as code with Kotlin. I'm writing wrappers for buildsteps so I can hide the default exposed configuration and only expose parameters that matter. This would allow me to prevent users of the class from changing values that would cause build errors.
I want this:
steps {
step {
name = "Restore NuGet Packages"
type = "jb.nuget.installer"
param("nuget.path", "%teamcity.tool.NuGet.CommandLine.3.3.0%")
param("nuget.updatePackages.mode", "sln")
param("nuget.use.restore", "restore")
param("sln.path", "path_to_solution") //parameter here
param("toolPathSelector", "%teamcity.tool.NuGet.CommandLine.3.3.0%")
}
...to be this:
MyBuildSteps.buildstep1("path_to_solution")
Here's the function signature for step:
public final class BuildSteps {
public final fun step(base: BuildStep?, init: BuildStep.() -> Unit ): Unit { /* compiled code */ }
}
This is what I tried:
class MyBuildSteps {
fun restoreNugetPackages(slnPath: String): kotlin.Unit {
var step: BuildStep = BuildStep {
name = "Restore NuGet Packages"
type = "jb.nuget.installer"
}
var stepParams: List = Parametrized {
param("build-file-path", slnPath)
param("msbuild_version", "14.0")
param("octopus_octopack_package_version", "1.0.0.%build.number%")
param("octopus_run_octopack", "true")
param("run-platform", "x86")
param("toolsVersion", "14.0")
param("vs.version", "vs2015")
}
return {
step.name
step.type
stepParams
} //how do I return this?
}
}
Any advice would be much appreciated!
I assume you want to encapsulate step {...} into a function buildstep1 with a parameter slnPath.
Use this function signature and copy-paste the step {...} part right inside. Add any parameters you see fit:
fun BuildSteps.buildstep1(slnPath: String) {
step {
name = "Restore NuGet Packages"
type = "jb.nuget.installer"
param("nuget.path", "%teamcity.tool.NuGet.CommandLine.3.3.0%")
param("nuget.updatePackages.mode", "sln")
param("nuget.use.restore", "restore")
param("sln.path", slnPath) // your parameter here
param("toolPathSelector", "%teamcity.tool.NuGet.CommandLine.3.3.0%")
}
}
That's all! Use it instead of the step {...} construct:
steps {
buildstep1("path_to_solution")
}
This function may be declared anywhere in the configuration file (I usually place those at the bottom) or in a separate .kts file and imported (theoretically).