Current section

Files

Jump to
beam_olympics src tasks bo_henchmen.erl
Raw

src/tasks/bo_henchmen.erl

-module(bo_henchmen).
-behaviour(bo_task).
-export([description/0, spec/0, score/0, timeout/0, tests/0]).
-spec description() -> binary().
description() ->
<<"Henchmen: Provide a function that spawns a process\n"
"The process should wait for messages\n"
"When it receives a pid, even if its own one, it should kill that process\n"
"but only if the victim lives in the same node as him"
>>.
-spec spec() -> bo_task:spec().
spec() -> #{input => [], output => <<"pid()">>}.
-spec score() -> 100.
score() -> 100.
-spec timeout() -> 5000.
timeout() -> 5000.
-spec tests() -> [bo_task:test()].
tests() ->
[ fun different_pids/1
, fun kills_siblings/1
, fun doesnt_kill_remotes/1
, fun commits_suicide/1
, fun doesnt_die_on_invalid_input/1
].
different_pids(Fun) ->
Henchmen = [Fun() || _ <- lists:seq(1, 1000)],
case length(lists:usort(Henchmen)) of
1000 -> ok;
_ -> {error, "Multiple executions of the function returned the same pid"}
end.
kills_siblings(Fun) ->
Bill = Fun(),
Boby = Fun(),
Dino = Fun(),
Henchmen = [Bill, Boby, Dino],
DeadProcs =
fun(Pids) ->
{dead_processes, [P || P <- Pids, not is_process_alive(P)]}
end,
try
{dead_processes, []} = DeadProcs(Henchmen),
Bill ! Boby,
timer:sleep(250),
{dead_processes, [Boby]} = DeadProcs(Henchmen),
Dino ! Boby,
timer:sleep(250),
{dead_processes, [Boby]} = DeadProcs(Henchmen),
Dino ! Bill,
timer:sleep(250),
{still_alive, [Dino]} =
{still_alive, [P || P <- Henchmen, is_process_alive(P)]},
ok
catch
_:Error -> {error, #{ test => ?FUNCTION_NAME
, error => Error
, stack => erlang:get_stacktrace()
}}
after
_ = exit(Bill, kill),
_ = exit(Boby, kill),
_ = exit(Dino, kill)
end.
doesnt_kill_remotes(Fun) ->
Harry = Fun(),
[Node | _] = nodes(),
Victim = spawn(Node, timer, sleep, [3000]),
try
true = is_process_alive(Harry),
true = rpc:pinfo(Victim) /= undefined,
Harry ! Victim,
timer:sleep(250),
true = is_process_alive(Harry),
true = rpc:pinfo(Victim) /= undefined,
exit(Victim, kill),
Harry ! Victim,
timer:sleep(250),
true = is_process_alive(Harry),
ok
catch
_:Error -> {error, #{ test => ?FUNCTION_NAME
, error => Error
, stack => erlang:get_stacktrace()
}}
after
_ = exit(Harry, kill),
_ = exit(Victim, kill)
end.
commits_suicide(Fun) ->
Kamikaze = Fun(),
try
true = is_process_alive(Kamikaze),
Kamikaze ! Kamikaze,
timer:sleep(250),
false = is_process_alive(Kamikaze),
ok
catch
_:Error -> {error, #{ test => ?FUNCTION_NAME
, error => Error
, stack => erlang:get_stacktrace()
}}
after
_ = exit(Kamikaze, kill)
end.
doesnt_die_on_invalid_input(Fun) ->
Larry = Fun(),
try
true = is_process_alive(Larry),
Larry ! hello,
timer:sleep(250),
true = is_process_alive(Larry),
Larry ! "is it me you're looking for?",
timer:sleep(250),
true = is_process_alive(Larry),
ok
catch
_:Error -> {error, #{ test => ?FUNCTION_NAME
, error => Error
, stack => erlang:get_stacktrace()
}}
after
_ = exit(Larry, kill)
end.