Unit Testing failures from Futures in Scala - scala

I'm trying to test the error handling in a script I'm writing. If the async function fetchBar fails I pattern match the failure case and then return a successful future containing the failed result.
val fetchedBar = Try(fooClient.fetchBar(params))
fetchedBar match {
case Success(bar) => foobar(bar)
case Failure(e) => Future.successful(FooResult(success = false))
}
However when I unit test this flow I'm having trouble testing the failure case. I have stubbed fetchBar to return a failed future as shown below.
val fetchedBar = Try(Future.failed(new Exception()))
But I noticed that fetchedBar returns a Success rather than a Failure. Why is that and how can I stub the fetchBar function to create a failed Try?

I think you're slightly mixing concepts - but that's not 100% your fault.
The thing is, Future in Scala is a bit non-orthogonal concept - that it is, it represents not only the notion of delayed execution, but also a notion of failure.
Because of this, in most cases it doesn't make much sense to wrap the Future into the Try, or vice versa - unless one wants to explicitly separate the notion of failure from the notion of asynchrony.
In other words, the following combinations are sort of weird, but still has their use:
Try[Future[_]] - future already captures failures. However, makes sense if you have a (bad-behaving) library method that normally returns a Future, but may throw on a "synchronous" path:
def futureReciprocal(i: Int): Float = {
val reciprocal = 1 / i // Division by zero is intentional
Future.successful(reciprocal)
}
futureReciprocal(0) // throws
Try(futureReciprocal(0)) // Failure(DivisionByZero(...))
... but this is basically a workaround to fix poorly implemented function
Future[Try[_]] - sometimes useful to separate the "business" error (represented by Future.success(Failure(...))) from "infrastructure" failure (represented by Future.failed(...)). On a side - this is especially useful with akka-streams, which tend to treat failed futures as "fatal" to the stream.
In your case, what you want to do is to assert on the result of the future. To do so, you have at least two options, actually.
Block till the future is completed and check the outcome - this is usually done with scala.concurrent.Await:
// writing this without the compiler, might mix up namespaces a bit
import scala.concurrent.Await
import scala.concurrent.duration.DurationInt
val future = fooClient.fetchBar(...)
val futureResult: Try[_] = Await.result(future, 1.second)
futureResult match { case Success(_) => ??? ; case Failure(exc) => ???; }
Use some test framework that supports working with futures - e.g. scalatest:
class YourTest extends FlatSpec with ScalaFutures {
"fetchBar should return failed future" in {
val future: Future[XYZ] = fooClient.fetchBar(...)
// whenReady comes from the ScalaFutures trait
whenReady(future) { result => result shouldBe XYZ } // asserting on the successful future result
whenReady(future.failed) { exc => exc shoulBe a[RuntimeException] } // asserting on an exception in the failed future
}
}

Related

Why does Finatra use flatMap and not just map?

This might be a really dumb question but I am trying to understand the logic behind using #flatMap and not just #map in this method definition in Finatra's HttpClient definition:
def executeJson[T: Manifest](request: Request, expectedStatus: Status = Status.Ok): Future[T] = {
execute(request) flatMap { httpResponse =>
if (httpResponse.status != expectedStatus) {
Future.exception(new HttpClientException(httpResponse.status, httpResponse.contentString))
} else {
Future(parseMessageBody[T](httpResponse, mapper.reader[T]))
.transformException { e =>
new HttpClientException(httpResponse.status, s"${e.getClass.getName} - ${e.getMessage}")
}
}
}
}
Why create a new Future when I can just use #map and instead have something like:
execute(request) map { httpResponse =>
if (httpResponse.status != expectedStatus) {
throw new HttpClientException(httpResponse.status, httpResponse.contentString)
} else {
try {
FinatraObjectMapper.parseResponseBody[T](httpResponse, mapper.reader[T])
} catch {
case e => throw new HttpClientException(httpResponse.status, s"${e.getClass.getName} - ${e.getMessage}")
}
}
}
Would this be purely a stylistic difference and using Future.exception is just better style in this case, whereas throwing almost looks like a side-effect (in reality it's not, as it doesn't exit the context of a Future) or is there something more behind it, such as order of execution and such?
Tl;dr:
What's the difference between throwing within a Future vs returning a Future.exception?
From a theoretical point of view, if we take away the exceptions part (they cannot be reasoned about using category theory anyway), then those two operations are completely identical as long as your construct of choice (in your case Twitter Future) forms a valid monad.
I don't want to go into length over these concepts, so I'm just going to present the laws directly (using Scala Future):
import scala.concurrent.ExecutionContext.Implicits.global
// Functor identity law
Future(42).map(x => x) == Future(42)
// Monad left-identity law
val f = (x: Int) => Future(x)
Future(42).flatMap(f) == f(42)
// combining those two, since every Monad is also a Functor, we get:
Future(42).map(x => x) == Future(42).flatMap(x => Future(x))
// and if we now generalise identity into any function:
Future(42).map(x => x + 20) == Future(42).flatMap(x => Future(x + 20))
So yes, as you already hinted, those two approaches are identical.
However, there are three comments that I have on this, given that we are including exceptions into the mix:
Be careful - when it comes to throwing exceptions, Scala Future (probably Twitter too) violates the left-identity law on purpose, in order to trade it off for some extra safety.
Example:
import scala.concurrent.ExecutionContext.Implicits.global
def sneakyFuture = {
throw new Exception("boom!")
Future(42)
}
val f1 = Future(42).flatMap(_ => sneakyFuture)
// Future(Failure(java.lang.Exception: boom!))
val f2 = sneakyFuture
// Exception in thread "main" java.lang.Exception: boom!
As #randbw mentioned, throwing exceptions is not idiomatic to FP and it violates principles such as purity of functions and referential transparency of values.
Scala and Twitter Future make it easy for you to just throw an exception - as long as it happens in a Future context, exception will not bubble up, but instead cause that Future to fail. However, that doesn't mean that literally throwing them around in your code should be permitted, because it ruins the structure of your programs (similarly to how GOTO statements do it, or break statements in loops, etc.).
Preferred practice is to always evaluate every code path into a value instead of throwing bombs around, which is why it's better to flatMap into a (failed) Future than to map into some code that throws a bomb.
Keep in mind referential transparency.
If you use map instead of flatMap and someone takes the code from the map and extracts it out into a function, then you're safer if this function returns a Future, otherwise someone might run it outside of Future context.
Example:
import scala.concurrent.ExecutionContext.Implicits.global
Future(42).map(x => {
// this should be done inside a Future
x + 1
})
This is fine. But after completely valid refactoring (which utilizes the rule of referential transparency), your codfe becomes this:
def f(x: Int) = {
// this should be done inside a Future
x + 1
}
Future(42).map(x => f(x))
And you will run into problems if someone calls f directly. It's much safer to wrap the code into a Future and flatMap on it.
Of course, you could argue that even when using flatMap someone could rip out the f from .flatMap(x => Future(f(x)), but it's not that likely. On the other hand, simply extracting the response processing logic into a separate function fits perfectly with the functional programming's idea of composing small functions into bigger ones, and it's likely to happen.
From my understanding of FP, exceptions are not thrown. This would be, as you said, a side-effect. Exceptions are instead values that are handled at some point in the execution of the program.
Cats (and i'm sure other libraries, too) employs this technique too (https://github.com/typelevel/cats/blob/master/core/src/main/scala/cats/ApplicativeError.scala).
Therefore, the flatMap call allows the exception to be contained within a satisfied Future here and handled at a later point in the program's execution where other exception value handling may also occur.

Await.result on HttpService

I've a scala project with http4s 0.15.16a and slick 3.2.1 with these steps:
Receive a ID by rest call
passing ID to MySlickDAO that responds with a Future
Call Await.result(res, Duration.Inf) on Future returned by MySlickDAO
Create the json
The problem is that I use a Await.result and this is bad practices
is there a better solution ?
Here the code:
val service = HttpService {
//http://localhost:8080/rest/id/9008E75A-F112-396B-E050-A8C08D26075F
case GET -> Root / "rest" / "id" / id =>
val res = MySlickDAO.load(id)
Await.result(res, Duration.Inf)
val ll = res.value.get.get
ll match {
case Failure(x) =>
InternalServerError(x)
case Success(record) =>
val r = record.map(x => MyEntity(x._1, x._2, x._3))
jsonOK(r.asJson)
}
case ....
}
Instead of awaiting, you can chain the result of one Future into another:
val resFut = MySlickDAO.load(id)
resFut.map { record =>
val r = record.map(x => MyEntity(x._1, x._2, x._3))
jsonOK(r.asJson)
} recover { x =>
InternalServerError(x)
}
The result of this will be a Future of a common supertype of jsonOK and InternalServerError (not familiar with the libraries you're using; so I may have the type of load wrong: it's not a Future[Try[_]] is it?).
BTW: your original code has a very problematic line:
val ll = res.value.get.get
res.value is an Option[Try[T]]. Calling get on an Option or a Try is generally a bad idea (even though in this case because of the Await, the Option should never be None, so the get is technically safe) because it can throw an exception. You're much better off using map, flatMap, and friends.
The issue is that http4s 0.15 uses the Scalaz concurrency constructs, while Slick uses the native Scala ones, and the two aren't designed to work with each other. My understanding is that http4s 0.17+ has switched from Scalaz to Cats, which might entail using native Scala Futures, so if you can upgrade that might be worth a shot. If not, you can handle the conversion by manually creating a Task that wraps your future:
def scalaFutureRes = MySlickDAO.load(id)
val scalazTaskRes = Task.async { register =>
scalaFutureRes.onComplete {
case Success(success) => register(success.right)
case Failure(ex) => register(ex.left)
}
}
At this point you've got a Task[ResultType] from the Future[ResultType] which you can map/flatMap with the rest of your logic like in Levi's answer.
You can also use the delorean library for this which has this logic and the opposite direction defined on the classes in question via implicit conversions, so that you can just call .toTask on a Future to get it in a compatible form. Their readme also has a lot of useful information on the conversion and what pitfalls there are.

Dealing with errors using idiomatic Scala

I'm writing an HTTPS service for a chat bot and find myself dealing with a lot of Futures and Options. Usually if an Option returns None or a Future fails I want to log the exception and reset the user back to the start. Here's a toy example of how I accomplish this:
(for {
user <- userService.retrieve(userId)
userPet <- Future(user.userPet.get)
_ <- sendTextAsJson(s"You're holding a $userPet!")
} yield {}).recover {
case ex: Exception =>
log.error(ex.toString)
fail
}
This works fine but it feels a little weird to wrap things in Future just so their exceptions are swallowed and dealt with in the recover block. It also feels weird to include an empty yield block. Is there a better way?
What you basically do is using onSuccess or onFailure to retrieve the futures result. What you also might try is Try.
There is an example of the underlying functionality.
http://www.scala-lang.org/api/2.9.3/scala/util/Try.html
I might suggest you this article: http://docs.scala-lang.org/overviews/core/futures.html I can't summarize whats stated there in a few sentences. But if you look to the table of contents on the right side, the point Futures explains what happens and how to handle it is stated under Excepetions. Thats the idiomatic way.
I don't think it's too bad tbh, assuming userService.retrieve() returns a Future in the first place. I'd personnally rather use map in this case to make things a bit more explicit :
val futureMsg = userService.retrieve(userId)
.map(user => sendTextAsJson(s"You're holding a ${user.userPet.get}!")
.recover {
case NonFatal(ex) => //Look it up ;)
log.error(ex.toString)
fail
}
You now have Future[Unit] to do whatever you want with.
I agree with you that that's an awkward use of a for-comprehension. This is how I would write this:
import scala.util.control.NonFatal
userService.retrieve(userId)
.map(_.userPet.get)
.map(userPet => s"You're holding a $userPet!")
.flatMap(sendTextAsJson)
.recover {
case NonFatal(ex) =>
log.error(ex.toString)
fail
}
Looking at your sendTextAsJson and fail functions you seem to want to side-effect when the future completes. I would not use map after you perform the Option.get and instead look at Futures onComplete method to either handle the success of the future or handle the exception throw. I am not sure how this way and recover are different though so double check that. I did like #sascha10000 link to the scala doc futures. Its been a long time since I read that but its a good resource from what I remember
Example implementation of your code with onComplete:
import scala.concurrent.Future
import scala.util.{Failure, Success}
import scala.concurrent.ExecutionContext.Implicits.global
object UserFuture extends App {
def fail = println("failed")
def sendTextAsJson(message: String): Unit = println(message)
case class User(userPet: Option[String])
object userService {
def userPet = Some("dog")
val someUser = User(userPet)
def retrieve(userId: Int): Future[User] = Future {
someUser
}
}
def getPet(userId: Int): Unit = {
userService.retrieve(userId)
.map(user => user.userPet.get)
.onComplete {
case Success(userPet) => sendTextAsJson(s"You're holding a $userPet!")
case Failure(ex) => println(ex.toString); fail
}
}
getPet(1)
Thread.sleep(10000) // I forgot how to use Await. This is just here to be able to make sure we see some printouts in the console.
}

Do Futures always end up not returning anything?

Given that we must avoid...
1) Modifying state
2) Blocking
...what is a correct end-to-end usage for a Future?
The general practice in using Futures seems to be transforming them into other Futures by using map, flatMap etc. but it's no good creating Futures forever.
Will there always be a call to onComplete somewhere, with methods writing the result of the Future to somewhere external to the application (e.g. web socket; the console; a message broker) or is there a non-blocking way of accessing the result?
All of the information on Futures in the Scaladocs - http://docs.scala-lang.org/overviews/core/futures.html seem to end up writing to the console. onComplete doesn't return anything, so presumably we have to end up doing some "fire-and-forget" IO.
e.g. a call to println
f onComplete {
case Success(number) => println(number)
case Failure(err) => println("An error has occured: " + err.getMessage)
}
But what about in more complex cases where we want to do more with the result of the Future?
As an example, in the Play framework Action.async can return a Future[Result] and the framework handles the rest. Will it eventually have to expect never to get a result from the Future?
We know the user needs to be returned a Result, so how can a framework do this using only a Unit method?
Is there a non-blocking way to retrieve the value of a future and use it elsewhere within the application, or is a call to Await inevitable?
Best practice is to use callbacks such as onComplete, onSuccess, onFailure for side effecting operations, e.g. logging, monitoring, I/O.
If you need the continue with the result of of your Future computation as opposed to do a side-effecting operation, you should use map to get access to the result of your computation and compose over it.
Future returns a unit, yes. That's because it's an asynchronous trigger. You need to register a callback in order to gather the result.
From your referenced scaladoc (with my comments):
// first assign the future with expected return type to a variable.
val f: Future[List[String]] = Future {
session.getRecentPosts
}
// immediately register the callbacks
f onFailure {
case t => println("An error has occurred: " + t.getMessage)
}
f onSuccess {
case posts => for (post <- posts) println(post)
}
Or instead of println-ing you could do something with the result:
f onSuccess {
case posts: List[String] => someFunction(posts)
}
Try this out:
import scala.concurrent.duration._
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
val f: Future[Int] = Future { 43 }
val result: Int = Await.result(f, 0 nanos)
So what is going on here?
You're defining a computation to be executed on a different thread.
So you Future { 43 } returns immediately.
Then you can wait for it and gather the result (via Await.result) or define computation on it without waiting for it to be completed (via map etc...)
Actually, the kind of Future you are talking about are used for side-effects. The result returned by a Future depends its type :
val f = Future[Int] { 42 }
For example, I could send the result of Future[Int] to another Future :
val f2 = f.flatMap(integer => Future{ println(integer) }) // may print 42
As you know, a future is a process that happens concurrently. So you can get its result in the future (that is, using methods such as onComplete) OR by explicitly blocking the current thread until it gets a value :
import scala.concurrent.Await
import akka.util.Timeout
import scala.concurrent.duration._
implicit val timeout = Timeout(5 seconds)
val integer = Await.result(Future { 42 }, timeout.duration)
Usually when you start dealing with asynchronous processes, you have to think in terms of reactions which may never occur. Using chained Futures is like declaring a possible chain of events which could be broken at any moment. Therefore, waiting for a Future's value is definitely not a good practice as you may never get it :
val integer = Await.result(Future { throw new RuntimeException() }, timeout.duration) // will throw an uncaught exception
Try to think more in terms of events, than in procedures.

Scala: Throw Error vs Return Try?

Should a Scala API ideally throw exceptions or return a Try value? Is there an official guideline regarding this?
def doSomethingMayThrow(): A = ???
def doSomethingWontThrow(): Try[A] = ???
Never throw exceptions for recoverable errors.
Returning appropriate data structure representing a possible failure (a Future, a Try, an Either and so on) is always preferable than throwing exceptions in the wild. It will inform the caller about the possibility of a failure, and it will force them to manage it.
Exceptions should only be thrown for unrecoverable errors, such as hardware failures and similar.
Let's make an example:
def throwOnOdds(x: Int): Int =
if (x % 2 == 0) x / 2 else throw new Exception("foo")
val x = throwOnOdds(41) + 2 // compiles and explodes at runtime
now, let's make it better
def throwOnOdds(x: Int): Try[Int] =
if (x % 2 == 0) Success(x / 2) else Failure(new Exception("foo"))
val x = throwOnOdds(41) + 2 // doesn't compile
Not handling the failure leads to a compile-time error, which is way better than a runtime one. Here's how to handle it
throwOnOdds(41) match {
case Success(n) => // do something with n
case Failure(e) => // handle exception
}
See monadic datatypes. Using monadic datatypes is much more expressive and clear than throwing exceptions and would be the preferred way of declaratively handling all cases without unclear side effects.
http://en.wikipedia.org/wiki/Monad_(functional_programming)
The advantage of using a failure vs success and using map and flatMap to express the 'happy path' is that exceptions/failures become explicit in the chain.
Where you can tell if you call to doSomethingMayThrow might have a side effect (eg throwing an exception) it is very clear when you use a monadic datatype as a result.
It would help to look at a real world case. I'll use this as it is something i have worked on recently:
Consider a monadic future in a caching scenario - if the cache returns a result, you can process the result. If the cache does not return a result, then we can go to the actual service that we are trying to cache results from and we can express it very explicitly without any unclear implied side effects such as exception :
Here recoverWith is like flatMap on the error case (return a Future[Model] instead of the failure). recover is like map on the error case (return a model on the future instead of the failure). Then map takes whatever the resulting model is and processes it - all cases are clearly defined in the code so there is clarity of all cases and conditions in a single expression.
(userCacheActor ? GetUserModel(id="abc"))
.recoverWith(userServiceActor ? GetUserModel(id="abc"))
.recover(new ErrorModel(errorCode=100, body="service error")
.map(x: Response => createHttpResponseFromModel(x))
def createHttpResponseFromModel(x: Model) =>
x match {
case model: ErrorModel => ???
case model: UserModel => ???
}
Again, everything is expressively notated - what to do with the failure of the cache hit, what to do if the service can't respond in that scenario, what to do with the result model at the end of all of the processing in any case.
Often flatMap is talked about as the 'plumber' of the monad or 'plumber' of the happy path. flatMap allows you to take another Monad and return it. So you can 'try' multiple scenarios and write the happy path code collecting any errors at the end.
scala> Option("Something").flatMap(x => Option( x + " SomethingElse"))
.flatMap(x => None).getOrElse("encountered None somewhere")
res1: String = encountered None somewhere
scala> scala.util.Try("tried")
.flatMap(x => scala.util.Try( x + " triedSomethingElse"))
.flatMap(x => scala.util.Try{throw new Exception("Oops")})
.getOrElse("encountered exception")
res2: String = encountered exception