I have a GenServer which performs a periodic action like so:
defmodule Hello
use GenServer
def init(_) do
Process.send_after(self(), :timer, 1000)
{:ok, %{}}
end
def handle_info(:timer, state) do
# do stuff
Process.send_after(self(), :timer, 1000)
{:noreply, state}
end
end
I'm trying to figure out the best way to unit test it. My initial idea was to use mox to stub the Process.send_after call. This works fine, but then in my unit test, I tried something like this:
test "the timer callback does the right thing" do
MyMock |> expect(:timer, fn -> :ok end)
{:ok, pid} = start_supervised(Hello, [])
Process.send(pid, :timer)
# assert the right thing happens
end
However, this doesn't work because Process.send is async and doesn't return me anything. How else can I test the handle_info callback?
There are many options, like one might spawn an Agent from setup_all callback and use it in both mock and assertion:
expect(MyMock, :timer, fn -> Agent.update(MyAgent, & &1 + 1))
...
Process.sleep(1_100) # ensure all sent
assert Agent.get(MyAgent, & &1) == 1 # number of calls
The probably easiest approach would be to capture IO:
import ExUnit.CaptureLog
...
test "the timer callback does the right thing" do
MyMock |> expect(:timer, fn -> IO.inspect(:ok) end)
{:ok, pid} = start_supervised(Hello, [])
assert capture_log(fn ->
Process.send(pid, :timer)
Process.sleep(1_100)
end) =~ "ok"
end
Related
I am attempting to implement a basic 'stress testing' program in MLton and its Concurrent ML implementation, specifically the Monte Carlo Pi test described here. While I think I have most of what I need figured out, I have a problem in that my program always terminates before the CML threads have finished their work. I know that they are doing something, since I sometimes see them print text to the console that I have directed should be printed, but there seems to be a race condition between them getting started and running, and the program as a whole exiting.
The code where I start CML is:
local
val iterations : int = 10
val num_threads : int = 1
val still_going : bool ref = ref true
in
val _ = (RunCML.doit ((experiment iterations num_threads still_going), NONE);
(* while !still_going do (); (* Spin-wait for the CML stuff to finish. This doesn't work... *) *)
print "All done!\n")
end
the contents of the experiment function are:
fun experiment (iterations : int) (num_threads : int) (still_going : bool ref) () : unit = let
val iters_per_thread : int = iterations div num_threads
val return_ivars = Vector.tabulate (num_threads, (fn _ => SyncVar.iVar()))
val _ = Vector.map (fn return_ivar => CML.spawn (montecarlopi iters_per_thread return_ivar)) return_ivars
val return_val = Vector.foldl (fn (elem, acc) => acc + (SyncVar.iGet elem)) 0.0 return_ivars
in
(TextIO.print ("Result is: " ^ (Real.toString return_val) ^ "\n");
still_going := false)
end
and finally, the montecarlopi function is:
fun montecarlopi (iterations : int) (return_ivar : real SyncVar.ivar) () = let
val _ = MLton.Random.srand (valOf (MLton.Random.useed ()))
fun helper accumulator 0 = accumulator
| helper accumulator iteration = let
val x : real = wordToBoundedReal (MLton.Random.rand ())
val y : real = wordToBoundedReal (MLton.Random.rand ())
val in_target = (x * x) + (y * y)
val next_iter = iteration - 1
val _ = TextIO.print ("next_iter is: " ^ (Int.toString next_iter) ^ ", in_target is: " ^ (Real.toString in_target) ^ ",x is: " ^ (Real.toString x) ^ ",y is: " ^ (Real.toString y) ^ "\n")
in
if in_target < 1.0 then
helper (accumulator + 1) next_iter
else
helper accumulator next_iter
end
in
SyncVar.iPut (return_ivar, (4.0 * ((real (helper 0 iterations)) / (real iterations))))
end
(The full (small) program and accompanying .mlb file can be viewed here). I'm reasonably sure that the bits inside the RunCML.doit function call do what they're supposed to, which leads me to think that the issue is probably to do with the outermost part of the program.
As you can see, I tried to spin wait, using a ref cell on a boolean to determine when to stop, but that doesn't seem to work. Nor does trying to spin wait using RunCML.isRunning - although both of those sound like terrible ideas to begin with, really, anyway. Of course, I can't use something like a CML channel or syncvar, since those need to be inside the RunCML.doit segment to be used. Changing the number of threads doesn't make any difference to this problem. Nor was I able to find any other functions that would make the main part go into a non-blocking wait.
How do I get the outer part of my program to wait until the bulk of it, inside the RunCML.doit function call, completes? Or, am I doing something wrong inside that part, which is causing the problem?
If we look at the the function RunCML.doit, It has type OS.Process.status which can either be success or failure, from which your call to doit is returning failure. There is a CML function shutdown: OS.Process.status -> 'a.
Which could be an explaination for why it's failing, except you don't call shutdown, and parts of your output results never print.
Here is a small example exercising various mechanisms for CML's shutdown, where CML seems to be doing something such as 'graceful' internally. Catching exceptions raised and turning those into failure.
structure Main = struct
open CML
structure RunCML = RunCML;
exception ohno
fun raises() = raise ohno
fun succeed() = RunCML.shutdown(OS.Process.success)
fun fail() = RunCML.shutdown(OS.Process.failure)
fun graceful f () =
let val () = f() handle _ => RunCML.shutdown(OS.Process.failure);
in RunCML.shutdown(OS.Process.success)
end
fun print_status status =
if OS.Process.isSuccess status
then TextIO.print("success\n")
else TextIO.print("failure\n")
fun main() = let
val _ = TextIO.print(banner ^ "\n");
val _ = print_status(RunCML.doit(succeed, NONE))
val _ = print_status(RunCML.doit(fail, NONE))
val _ = print_status(RunCML.doit(raises, NONE))
val _ = print_status(RunCML.doit(graceful(raises), NONE))
val _ = print_status(RunCML.doit(graceful(succeed), NONE))
in OS.Process.success end
end
So, if CML is exiting strangely, and you aren't calling shutdown yourself, its a good chance there is an exception being raised somewhere, which turned out to be the case.
One way to avoid this silent handling of exceptions might in the future might be adding something like:
fun noisy f () =
let val () = f()
handle e =>
let val () = TextIO.print ("Exception: " ^ (exnName e)
^ " Message: " ^ (exnMessage e) ^ "\n")
in RunCML.shutdown(OS.Process.failure) end
in RunCML.shutdown(OS.Process.success)
end
then calling RunCML.doit(noisy(f), NONE)
P.S. Thank you for including a link to your code, it would have been much harder to understand the problem otherwise.
I want to make a function which can make a pause less then 1 sec.
So I have made this function :
let pause(n:float)=
Unix.select [] [] [] n
;;
And I use it like this :
ignore(pause(0.1));
And the top level return me this error :
Exception: Unix.Unix_error (Unix.EINTR, "select", "").
What should I do ?
P.S. I have also tried with Thread.delay but I have same error.
This means a signal was sent to your program during the call to select.
Assuming you are using OCaml 4.03 or higher, you can use the Unix.sleepf function which does exactly what you expect:
# Unix.sleepf;;
- : float -> unit = <fun>
On older versions of OCaml, you can use the setitimer function, which will require some signal handling:
exception Alarm
let () = Sys.set_signal Sys.sigalrm ( Sys.Signal_handle (fun _ -> raise Alarm) )
let pause f =
let _ = Unix.setitimer Unix.ITIMER_REAL
{ Unix.it_interval = 0.; Unix.it_value = f; } in
try Unix.sleep (int_of_float (ceil f)) with
| Alarm -> ()
Note that this is not really thread safe and would conflict with other uses of SIGALRM. I strongly suggest you switch to the most recent version of OCaml.
I'm trying to test a small function (or rather, IO Action) that takes a command line argument and outputs it to the screen. My original (untestable) function is:
-- In Library.hs
module Library where
import System.Environment (getArgs)
run :: IO ()
run = do
args <- getArgs
putStrLn $ head args
After looking at this answer about mocking, I have come up with a way to mock getArgs and putStrLn by using a type class constrained type. So the above function becomes:
-- In Library.hs
module Library where
class Monad m => SystemMonad m where
getArgs :: m [String]
putStrLn :: String -> m ()
instance SystemMonad IO where
getArgs = System.Environment.getArgs
putStrLn = Prelude.putStrLn
run :: SystemMonad m => m ()
run = do
args <- Library.getArgs
Library.putStrLn $ head args
This Library., Prelude. and System.Environment. are to avoid compiler complaints of Ambigious Occurence. My test file looks like the following.
-- In LibrarySpec.hs
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
import Library
import Test.Hspec
import Control.Monad.State
data MockArgsAndResult = MockArgsAndResult [String] String
deriving(Eq, Show)
instance SystemMonad (State MockArgsAndResult) where
getArgs = do
MockArgsAndResult args _ <- get
return args
putStrLn string = do
MockArgsAndResult args _ <- get
put $ MockArgsAndResult args string
return ()
main :: IO ()
main = hspec $ do
describe "run" $ do
it "passes the first command line argument to putStrLn" $ do
(execState run (MockArgsAndResult ["first", "second"] "")) `shouldBe` (MockArgsAndResult ["first", "second"] "first")
I'm using a State monad that effectively contains 2 fields.
A list for the command line arguments where the mock getArgs reads from
A string that the mock putStrLn puts what was passed to it.
The above code works and seems to test what I want it to test. However, I'm wondering if there is some better / cleaner / more idiomatic way of testing this. For one thing, I'm using the same state to both put stuff into the test (my fake command line arguments), and then get stuff out of it (what was passed to putStrLn.
Is there a better way of doing what I'm doing? I'm more familiar with mocking in a Javascript environment, and my knowledge of Haskell is pretty basic (I arrived at the above solution by a fair bit of trial and error, rather than actual understanding)
The better way is to avoid needing to provide mock versions of getArgs and putStrLn by separating out the heart of the computation into a pure function.
Consider this example:
main = do
args <- getArgs
let n = length $ filter (\w -> length w < 5) args
putStrLn $ "Number of small words: " ++ show n
One could say that the heart of the computation is counting the number of small words which is a pure function of type [String] -> Int. This suggest that we should refactor the program like this:
main = do
args <- getArgs
let n = countSmallWords args
putStrLn $ "Number of small words: " ++ show n
countSmallWords :: [String] -> Int
countSmallWords ws = ...
Now we just test countSmallWords, and this is easy because it is pure function.
I am writing an introduction to Haskell for my local functional programming group.
As a base I am using the Tasty-testing framework and I want to test the indexing function (!!).
MinimalExample.hs
module MinimalExample where
myIndex :: Int -> [a] -> a
myIndex _ [] = error "index too large"
myIndex 0 (x:_) = x
myIndex n (_:xs) = myIndex (n-1) xs
MinimalTests.hs
module MinimalTests where
import Test.Tasty
import Test.Tasty.SmallCheck as SC
import Test.SmallCheck.Series
import MinimalExample
main :: IO ()
main = defaultMain tests
tests :: TestTree
tests = testGroup "Tests" [scProps]
scProps :: TestTree
scProps = testGroup "(checked by SmallCheck)"
[ SC.testProperty "(!!) == myIndex" $ \lst n ->
lst !! n == myIndex (n::Int) (lst::[Int])
]
The tests should not fail on "too large indices" as the Errors/Exceptions are the same.
The tests should fail with negative input - which could be resolved by adding NonNegative as a constraint on the input, or adding the respective clause in the myIndex-function.
Can I test for exceptions in property based tests?
Or do I have to use (H)Unit-tests like in How do I test for an error in Haskell? or Haskell exceptions and unit testing , in this case how do I choose the Index in the range of 0 to length of the generated testing list.
You could use the spoon package, or write a similar function that would return the exception if you want to test that the exceptions are the same.
I'm following the scala course in coursera and I was asked to implement set operations in the last exercise. One of the test I failed was called
exists should be implemented in terms of forall
Both exists and forall signatures are :
type Set = Int => Boolean
def forall(s: Set, p: Int => Boolean): Boolean = {}
def exists(s: Set, p: Int => Boolean): Boolean = {
/*should eventually call forall */
}
I am not asking for the implementation, but how to perform such a unit test in scala
There are three methods that I can think of to start with:
1) Mock forall to throw a particular exception, and then call exists, and see if it throws that exception.
2) Instrument the code and call exists, and test afterwards to see if forall was called
3) Use a scala macro, which analyses the AST for exists and checks recursively to see if it calls forall.
This is fairly easy done with mock objects. I'm using Mockito in my Java projects, and it is pretty usable from Scala too, especially together with Scalatest.
Put this code to project_dir/build.sbt:
scalaVersion := "2.10.2"
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "2.0.M8",
"org.mockito" % "mockito-core" % "1.9.5"
)
Then put this code to project_dir/src/main/test/test.scala:
import org.scalatest.{FlatSpec,ShouldMatchers}
import org.scalatest.mock.MockitoSugar
package object test {
type Set = Int => Boolean
}
package test {
class Foraller {
def forall(s: Set, p: Int => Boolean): Boolean = ???
}
class Exister(foraller: Foraller) {
def exists(s: Set, p: Int => Boolean): Boolean = ??? // Fails
// def exists(s: Set, p: Int => Boolean): Boolean = foraller.forall(s, p) // Passes
}
class Test extends FlatSpec with ShouldMatchers with MockitoSugar {
"Exister" should "use Foraller in its exists method" in {
val foraller = mock[Foraller]
val exister = new Exister(foraller)
val set: Set = _ == 1
val pred: Int => Boolean = _ > 0
exister.exists(set, pred)
import org.mockito.Mockito._
verify(foraller).forall(set, pred)
}
}
}
Then invoke sbt test command in project_dir. You should see that the test has failed. Switch comments on lines in Exister class and try again.
Here we create mock object for the class which provides forall method and we use this object inside a class which provides exists method. Mockito allows verifying whether some method on some mock object is called, and this is what is working here.