PureScript FFI & Aff Monad: Why does the effect never run? - monads

I'm a total PureScript newbie and need a bit of help figuring out why a FFI function modeled with the Aff monad doesn't seem to be working for me.
The expected behavior is to log a message "keyMessage" to the console after 1000ms.
Instead, the program just hangs indefinitely after the following output:
Compiling Main
* Build successful.
Waiting for message...
Main.purs:
module Main where
import Prelude
import Control.Monad.Aff (Aff, Fiber, launchAff)
import Control.Monad.Aff.Console (log)
import Control.Monad.Eff (Eff, kind Effect)
import Control.Monad.Eff.Console (CONSOLE)
main :: forall e. Eff (console :: CONSOLE, to :: TIMEOUT | e) (Fiber (console :: CONSOLE, to :: TIMEOUT | e) Unit)
main = launchAff do
log "Waiting for message..."
m <- message "key"
log m
foreign import data TIMEOUT :: Effect
foreign import message :: forall e. String -> Aff (to :: TIMEOUT | e) String
Main.js:
'use strict';
exports.message = function(key) {
return function(errback, callback) {
var timeout = setTimeout(function() {
callback(key + 'Message');
}, 1000);
return function() {
return function (cancelErrback, cancelCallback) {
clearTimeout(timeout);
return cancelCallback();
};
};
};
};
Thanks in advance for your insights!

If you're using the latest major version of purescript-aff (v4 or later) then the runtime representation of Aff has changed, and you can't create it directly using the errback/callback function style anymore.
Take a look at the https://pursuit.purescript.org/packages/purescript-aff/4.0.2/docs/Control.Monad.Aff.Compat module, in particular the EffFnAff type / fromEffFnAff functions for an explanation of how the equivalent thing works now.
Alternatively you can also construct Affs with makeAff, but that would require reformulating your FFI code a bit.

Related

KotlinTest with Koin: InvocationTargetException

I'm unable to use Koin 2.0.1 with Kotlin-test 3.4.2. I get an InvocationTargetException like this:
Running koinexample.KoinSampleTests
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.009 sec <<< FAILURE! - in koinexample.KoinSampleTests
koinexample.KoinSampleTests Time elapsed: 0.009 sec <<< ERROR!
java.lang.reflect.InvocationTargetException
at koinexample.KoinSampleTests.getKoin(KoinSampleTests.kt:26)
at koinexample.KoinSampleTests.<init>(KoinSampleTests.kt:61)
I've created a small example on GitHub that reproduces this error:
https://github.com/elifarley/kotlin-tests-with-koin-examples
Just execute these commands to clone the repo and run tests:
git clone https://github.com/elifarley/kotlin-tests-with-koin-examples.git
cd kotlin-tests-with-koin-examples
mvn
Here's the main Kotlin file:
package koinexample
import io.kotlintest.koin.KoinListener
import io.kotlintest.shouldBe
import io.kotlintest.specs.FreeSpec
import org.koin.core.inject
import org.koin.dsl.module
import org.koin.test.KoinTest
data class Stats(var ok: Long = 0, var error: Long = 0)
interface StatsServer {
fun newError(): Long
}
class StatsServerSimple(private val stats: Stats) : StatsServer {
override fun newError() = stats.error++
}
val appModule = module {
single { Stats() }
single { StatsServerSimple(get()) as StatsServer }
}
class KoinSampleTests : FreeSpec(), KoinTest {
private val modules = listOf(
appModule
)
override fun listeners() = listOf(KoinListener(modules))
val statsServer: StatsServer by inject()
init {
"Happy path" {
statsServer.newError() shouldBe 1
}
}
}
Your issue seems to be a simple import confusion.
Note that you're using import org.koin.core.inject, which is this function:
inline fun <reified T> KoinComponent.inject(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): Lazy<T> =
getKoin().inject(qualifier, parameters)
It needs getKoin to work, and therefore you cannot initialize your test (The test class is initialized before Koin had a chance to start with the listener).
The correct import is import org.koin.test.inject, which translates to:
inline fun <reified T> KoinTest.inject(
qualifier: Qualifier? = null,
noinline parameters: ParametersDefinition? = null
): Lazy<T> = lazy { get<T>(qualifier, parameters) }
Take note that this is indeed lazy, so Kotest will have a chance to initialize Koin before your tests start.
Fixing that import should resolve this issue
Seems like you're never starting the Koin app. You need to have
startKoin {
modules(appModule)
}
in your test method or in the beforeSpec/beforeTest function call of the spec.
Or use something like here:
override fun listeners() = listOf(KoinListener(appModule))
which is described in the documentation for kotlintest/kotest: https://github.com/Kotest/Kotest/blob/master/doc/extensions.md#koin

Is it possible to build an OLTP/CRUD HTTP server using AkkaHttp, AkkaStreams, Alpakka and a database?

It is clear to me that using Actors of course it is possible: for instance https://github.com/chbatey/akka-http-typed.git is using AkkaHttp and typed actors.
But it is unclear to me if just using AkkaStreams and its Alpakka connectors library (which includes databases), if is it possible to do regular CRUD / OLTP services, or just data replication from one database to another, or other OLAP / batch / stream processing scenarios.
If you know how it can be done please indicate a few details and if you can provide an example on github for instance that would be great.
The way I am thinking it may be possible is that the server is involved in two conversations / stateful stream transformation: one with the outside world over HTTP, and one with the database. I am not sure if this is possible to be modelled like that.
https://doc.akka.io/docs/alpakka/current/slick.html seems to offer both UPDATE/INSERTS as a Sink as well as pointed SELECT to a certain id as a Source. Do you know if an example app is there or can you broadly mention how the wiring would happen with Akka Http?
I put a demo here, hope it can help you.
Creating table, database is mysql.
CREATE TABLE test(id VARCHAR(32))
sbt:
"com.lightbend.akka" %% "akka-stream-alpakka-slick" % "1.1.0",
"mysql" % "mysql-connector-java" % "5.1.40"
Code:
package tech.parasol.scala.crud
import java.sql.SQLException
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives.{complete, get, path, _}
import akka.stream.alpakka.slick.scaladsl.{Slick, SlickSession}
import akka.stream.scaladsl.Sink
import akka.stream.{ActorAttributes, ActorMaterializer, Supervision}
import com.typesafe.config.ConfigFactory
import scala.concurrent.Future
import scala.io.StdIn
import scala.util.{Failure, Success}
object CrudTest1 {
def main(args: Array[String]): Unit = {
implicit val system = ActorSystem("CrudTest1")
implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
val hostName = "120.0.0.1"
val rocketDbConfig =
s"""
|db-config {
| profile = "slick.jdbc.MySQLProfile$$"
| db {
| dataSourceClass = "slick.jdbc.DriverDataSource"
| properties = {
| driver = "com.mysql.jdbc.Driver"
| url = "jdbc:mysql://${hostName}:3306/rocket?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false"
| user = "root"
| password = "passw0rd"
| }
| }
|}
|
""".stripMargin
implicit val session = SlickSession.forConfig("db-config", ConfigFactory.parseString(rocketDbConfig))
import session.profile.api._
def persistence(message: String) = {
def insert(message: String): DBIO[Int] = {
sqlu"""INSERT INTO test(id) VALUES (${message})"""
}
session.db.run(insert(message)).map {
case _ => message
}.recover {
case e : SQLException => {
throw new Exception("Database error ===>")}
case e : Exception => {
throw new Exception("Database error.")}
}
}
val route = path("hello" / Segment ) { name =>
get {
val res = persistence(name)
onComplete(res) {
case Success(value) => {
complete(s"<h1>Say hello to ${name}</h1>")
}
case Failure(e) => {
complete(s"<h1>Failed to say hello to ${name}</h1>")
}
}
}
}
val bindingFuture = Http().bindAndHandle(route, "localhost", 8088)
println(s"Server online at http://localhost:8088/\nPress RETURN to stop...")
StdIn.readLine() // let it run until user presses return
bindingFuture
.flatMap(_.unbind()) // trigger unbinding from the port
.onComplete(_ => system.terminate()) // and shutdown when done
}
}
Yes, basically at every request receive in AkkaHttp, we create an AkkaStreams Graph (just a pipeline typically), basically just the Slick Alpakka Source from the database, maybe prefixed by some operators, and then returned in AkkaHttp, which of course supports Source. More details at [https://www.quora.com/Is-it-possible-to-build-an-OLTP-CRUD-HTTP-server-using-Akka-HTTP-Akka-Streams-Alpakka-and-a-database-Do-you-know-any-examples-of-code-on-GitHub-or-elsewhere/answer/Nicolae-Marasoiu]

How to send Akka broadcast message

I'm trying to send a single message to several actors. Investigation led me to the code below, but it doesn't work. The message that's "wrapped" in the Broadcast object disappears, and the plain string ends up in the dead letter box.
Can someone tell me what I'm missing? (Edit: I've added the correction below)
import akka.actor.{Actor, ActorSystem, Props}
import akka.routing.{Broadcast, BroadcastRoutingLogic, Router}
object RouterAndBroadcast {
class MyRoutee extends Actor {
override def receive: Receive = {
case x => println(s"MyRoutee $this got message $x")
}
}
def main(args: Array[String]): Unit = {
val system = ActorSystem.create("system")
val mr0 = system.actorOf(Props[MyRoutee])
val mr1 = system.actorOf(Props[MyRoutee])
val mr2 = system.actorOf(Props[MyRoutee])
/* This was the error:
val router = new Router(BroadcastRoutingLogic())
router.addRoutee(mr1)
router.addRoutee(mr2) */
// This is the corrected version:
val router = new Router(BroadcastRoutingLogic())
.addRoutee(mr1)
.addRoutee(mr2)
mr1 ! "Hello number one!"
mr2 ! "Ahoy two, me old mate!"
router.route(new Broadcast("Listen up!"), mr0) // vanishes??
router.route("Listen up!", mr0) // ends up in dead letters
mr1 ! "Number one, are you still there?"
mr2 ! "Two, where's the grog?"
router.route(new Broadcast("Still shouting!"), mr0) // also vanishes
Thread.sleep(5000)
system.terminate()
}
}
Router.addRoutee returns a copy with the routee added, it doesn't modify ther Router in place, see:
https://github.com/akka/akka/blob/b94e064a34a7f6a9d1fea55317d5676731ac0778/akka-actor/src/main/scala/akka/routing/Router.scala#L140
/**
* Create a new instance with one more routee and the same [[RoutingLogic]].
*/
def addRoutee(routee: Routee): Router = copy(routees = routees :+ routee)
so instead try
router = router.addRoutee(mr1).addRoutee(mr2)

How do I write an async unit test method in F#

How do I write an async test method in F#?
I'm referencing the following code:
[TestMethod]
public async Task CorrectlyFailingTest()
{
  await SystemUnderTest.FailAsync();
}
This is my failed attempt:
[<Test>]
let ``Correctly failing test``() = async {
SystemUnderTest.FailAsync() | Async.RunSynchronously
}
So after a bit of research, it turns out that this is more difficult than it ought to be. https://github.com/nunit/nunit/issues/34
That being said a workaround was mentioned. This seems kinda lame but, it looks like declaring a task delegate outside as a member and leveraging it is a viable work around.
The examples mentioned in the thread:
open System.Threading.Tasks
open System.Runtime.CompilerServices
let toTask computation : Task = Async.StartAsTask computation :> _
[<Test>]
[<AsyncStateMachine(typeof<Task>)>]
member x.``Test``() = toTask <| async {
do! asyncStuff()
}
And
open System.Threading.Tasks
open NUnit.Framework
let toAsyncTestDelegate computation =
new AsyncTestDelegate(fun () -> Async.StartAsTask computation :> Task)
[<Test>]
member x.``TestWithNUnit``() =
Assert.ThrowsAsync<InvalidOperationException>(asyncStuff 123 |> toAsyncTestDelegate)
|> ignore
[<Test>]
member x.``TestWithFsUnit``() =
asyncStuff 123
|> toAsyncTestDelegate
|> should throw typeof<InvalidOperationException>
XUnit had a similar problem and did come up with a solution:
https://github.com/xunit/xunit/issues/955
So you should be able to do this in xunit
[<Fact>]
let ``my async test``() =
async {
let! x = someAsyncCall()
AssertOnX
}
Sorry if this is not the most satisfying answer.
open Xunit
[<Fact>]
let ``my async test``() =
async {
do! Async.AwaitTask(someAsyncCall())|> Async.Ignore
AssertOnX
}
I asked https://github.com/fsprojects/FsUnit/issues/153 because I think that it is a responsibility of the F# unit testing framework to provide a right binding.
Meanwhile, this looks the best for me.
open System.Threading.Tasks
let runAsyncTest async = async |> Async.StartImmediateAsTask :> Task
[<Test>]
let ``Some test`` () = runAsyncTest <| async {
}
This is an old question but now can use the task builder from the Ply package for testing C# async methods in Xunit like so:
open FSharp.Control.Tasks
open System.Threading
open Xunit
let ``Test some Task returning async method`` () =
task {
let! actual = MyType.GetSomethingAsync()
Assert.Equal(expected, actual)
return ()
}

Can't run OpenGL on Haskell [duplicate]

Here is my source code I'm trying to get to work:
In Main.hs:
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
import Bindings
import Data.IORef
main = do
(progname,_) <- getArgsAndInitialize
createWindow "Hello World"
reshapeCallback $= Just reshape
keyboardMouseCallback $= Just keyboardMouse
angle <- newIORef 0.0
displayCallback $= display
idleCallback $= Just idle
mouseWheelCallback $= Just mouseWheel
mainLoop
In Bindings.hs:
module Bindings where
import Graphics.Rendering.OpenGL
import Graphics.UI.GLUT
display :: IO ()
display = return ()
overlayDisplay :: IO ()
overlayDisplay = return ()
visibility :: Visibility -> IO ()
visibility v = return ()
reshape :: Size -> IO ()
reshape s#(Size w h) = do
viewport $= (Position 0 0, s)
close :: IO ()
close = return ()
keyboardMouse :: Key -> KeyState -> Modifiers -> Position -> IO ()
keyboardMouse key state modifiers position = return ()
mouseWheel :: WheelNumber -> WheelDirection -> Position -> IO ()
mouseWheel wn wd p = return ()
idle :: IO ()
idle = return ()
It works if I use normal glut32.dll and none of the freeglut extensions in my code, but I want to use the freeglut extensions.
When I use freeglut.dll, rename it to glut32.dll, and put it in the same folder as my .exe, it gives me the error:
main: user error (unknown GLUT entry glutInit)
When I use the normal glut32.dll in the same way I get the error:
main: user error (unknown GLUT entry glutMouseWheelFunc)
download glut from http://www.transmissionzero.co.uk/software/freeglut-devel/. Be sure to download the MinGW version.
copy the file freeglut-MinGW-3.0.0-1.mp.zip\freeglut\bin\x64\freeglut.dll to C:\Windows\System32. Make sure you get the 64 bit version from the x64 folder.
rename it as glut32.dll
I just solved this problem and hope this could help others.
You have to use freeglut .lib/.dll from Mingw or compile it yourself.