Merge pull request #29 from ukutaht/process_koans
Koans about processes.
This commit is contained in:
123
lib/koans/10_processes.ex
Normal file
123
lib/koans/10_processes.ex
Normal file
@@ -0,0 +1,123 @@
|
||||
defmodule Processes do
|
||||
use Koans
|
||||
|
||||
koan "tests run in a process!" do
|
||||
assert Process.alive?(self)
|
||||
end
|
||||
|
||||
koan "can spew out information about a process" do
|
||||
information = Process.info(self)
|
||||
|
||||
assert information[:status] == :running
|
||||
end
|
||||
|
||||
koan "process can send messages to itself" do
|
||||
send self(), "hola!"
|
||||
assert_receive "hola!"
|
||||
end
|
||||
|
||||
koan "a common pattern is to include the sender in the message" do
|
||||
pid = spawn(fn -> receive do
|
||||
{:hello, sender} -> send sender, :how_are_you?
|
||||
_ -> assert false
|
||||
end
|
||||
end)
|
||||
|
||||
send pid, {:hello, self()}
|
||||
assert_receive :how_are_you?
|
||||
end
|
||||
|
||||
koan "you don't have to wait forever for messages" do
|
||||
parent = self()
|
||||
spawn(fn -> receive do
|
||||
_anything -> flunk "I really wasn't expecting messages"
|
||||
after
|
||||
10 -> send parent, {:waited_too_long, "I am inpatient"}
|
||||
end
|
||||
end)
|
||||
|
||||
assert_receive {:waited_too_long, "I am inpatient"}
|
||||
end
|
||||
|
||||
koan "killing a process will terminate it" do
|
||||
pid = spawn(fn -> Process.exit(self(), :kill) end)
|
||||
:timer.sleep(500)
|
||||
refute Process.alive?(pid)
|
||||
end
|
||||
|
||||
koan "killing a process kills it for good" do
|
||||
pid = spawn(fn -> receive do
|
||||
end
|
||||
end)
|
||||
assert Process.alive?(pid)
|
||||
Process.exit(pid, :kill)
|
||||
refute Process.alive?(pid)
|
||||
end
|
||||
|
||||
koan "can trap a signal in a child process" do
|
||||
parent = self()
|
||||
pid = spawn(fn ->
|
||||
Process.flag(:trap_exit, true)
|
||||
send parent, :ready
|
||||
receive do
|
||||
{:EXIT, _pid, reason} -> send parent, {:exited, reason}
|
||||
end
|
||||
end)
|
||||
wait()
|
||||
Process.exit(pid, :random_reason)
|
||||
|
||||
assert_receive {:exited, :random_reason}
|
||||
refute Process.alive?(pid)
|
||||
end
|
||||
|
||||
koan "quitting normally has no effect" do
|
||||
pid = spawn(fn -> receive do
|
||||
end
|
||||
end)
|
||||
Process.exit(pid, :normal)
|
||||
assert Process.alive?(pid)
|
||||
end
|
||||
|
||||
koan "quititing your own process normally does terminate it though" do
|
||||
pid = spawn(fn -> receive do
|
||||
:bye -> Process.exit(self(), :normal)
|
||||
end
|
||||
end)
|
||||
|
||||
assert Process.alive?(pid)
|
||||
send pid, :bye
|
||||
:timer.sleep(100)
|
||||
refute Process.alive?(pid)
|
||||
end
|
||||
|
||||
koan "linked processes are informed about exit signals of children when trapping those signals" do
|
||||
parent = self()
|
||||
spawn(fn ->
|
||||
Process.flag(:trap_exit, true)
|
||||
spawn_link(fn -> Process.exit(self(), :normal) end)
|
||||
receive do
|
||||
{:EXIT, _pid ,reason} -> send parent, {:exited, reason}
|
||||
end
|
||||
end)
|
||||
|
||||
assert_receive {:exited, :normal}
|
||||
end
|
||||
|
||||
koan "monitoring processes are informed via messages without having trapping" do
|
||||
parent = self()
|
||||
spawn(fn ->
|
||||
spawn_monitor(fn -> Process.exit(self(), :normal) end)
|
||||
receive do
|
||||
{:DOWN, _ref, :process, _pid, reason} -> send parent, {:exited, reason}
|
||||
end
|
||||
end)
|
||||
|
||||
assert_receive {:exited, :normal}
|
||||
end
|
||||
|
||||
def wait do
|
||||
receive do
|
||||
:ready -> true
|
||||
end
|
||||
end
|
||||
end
|
||||
49
lib/koans/11_task.ex
Normal file
49
lib/koans/11_task.ex
Normal file
@@ -0,0 +1,49 @@
|
||||
defmodule Tasks do
|
||||
use Koans
|
||||
|
||||
koan "Tasks can be used for asynchronous computations with results" do
|
||||
task = Task.async(fn -> 3 *3 end)
|
||||
do_other_stuff()
|
||||
assert Task.await(task) + 1 == 10
|
||||
end
|
||||
|
||||
koan "if you don't need a result, use start_link/1" do
|
||||
{:ok, pid} = Task.start_link(fn -> 1+1 end)
|
||||
end
|
||||
|
||||
koan "yield returns nil if the task isn't done yet" do
|
||||
handle = Task.async(fn ->
|
||||
:timer.sleep(100)
|
||||
3 * 3
|
||||
end)
|
||||
assert Task.yield(handle, 10) == nil
|
||||
assert Task.await(handle) == 9
|
||||
end
|
||||
|
||||
koan "tasks can be aborted with shutdown" do
|
||||
handle = Task.async(fn ->
|
||||
:timer.sleep(100)
|
||||
3 * 3
|
||||
end)
|
||||
refute Task.shutdown(handle)
|
||||
end
|
||||
|
||||
koan "shutdown will give you an answer if it has it" do
|
||||
handle = Task.async(fn -> 3 * 3 end)
|
||||
:timer.sleep(10)
|
||||
assert Task.shutdown(handle) == {:ok, 9}
|
||||
end
|
||||
|
||||
koan "you can yield to multiple tasks at once and extract the results" do
|
||||
squares = [1,2,3,4]
|
||||
|> Enum.map(fn(number) -> Task.async(fn -> number * number end) end)
|
||||
|> Task.yield_many(100)
|
||||
|> Enum.map(fn({_task,{:ok, result}}) -> result end)
|
||||
|
||||
assert squares == [1,4,9,16]
|
||||
end
|
||||
|
||||
def do_other_stuff do
|
||||
:timer.sleep(50)
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user