okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

Aly Raffauffix(daemon): remove stopped session running marks8d97901

main
3.4 KiB88 linesraw
1%% E2E cannot hold an old owner's cleanup behind a replacement publication.
2%% Control owner publications and suspend the real progress monitor to verify
3%% reads remain safe even before queued death cleanup runs.
4-module(albedo_running_test).
5-include_lib("eunit/include/eunit.hrl").
6
7old_owner_cleanup_preserves_replacement_test() ->
8    Session = make_ref(),
9    {Previous, PreviousWatcher} = owner(Session),
10    {Replacement, ReplacementWatcher} = owner(Session),
11    try
12        Previous ! {idle, self()},
13        receive {idle, Previous} -> ok after 5000 -> error(idle_stalled) end,
14        ?assertEqual([{Session, Replacement}], ets:lookup(albedo_running, Session)),
15        nil = albedo_bus:forget(Session, Previous),
16        ?assert(albedo_bus:running(Session)),
17        stop(Previous),
18        wait_for_exit(PreviousWatcher),
19        ?assertEqual([{Session, Replacement}], ets:lookup(albedo_running, Session)),
20        ?assertMatch({ok, {Replacement, _}},
21            albedo_registry:lookup(albedo_session_progress, Session))
22    after
23        stop(Previous),
24        stop(Replacement),
25        wait_for_exit(PreviousWatcher),
26        wait_for_exit(ReplacementWatcher)
27    end,
28    ?assertEqual([], ets:lookup(albedo_running, Session)).
29
30dead_owner_reads_idle_before_monitor_removes_record_test() ->
31    Session = make_ref(),
32    {Owner, Watcher} = owner(Session),
33    true = erlang:suspend_process(Watcher),
34    try
35        ?assert(albedo_bus:running(Session)),
36        stop(Owner),
37        ?assertEqual([{Session, Owner}], ets:lookup(albedo_running, Session)),
38        ?assertNot(albedo_bus:running(Session))
39    after
40        erlang:resume_process(Watcher),
41        stop(Owner),
42        wait_for_exit(Watcher)
43    end,
44    ?assertEqual([], ets:lookup(albedo_running, Session)),
45    ?assertEqual(undefined, albedo_registry:lookup(albedo_session_progress, Session)).
46
47owner(Session) ->
48    %% Initialise detached tables before tracing, leaving only the progress
49    %% monitor as a spawned child of the registering owner.
50    nil = albedo_registry:register(albedo_running, warmup, self()),
51    nil = albedo_registry:forget(albedo_running, warmup),
52    nil = albedo_registry:register(albedo_session_progress, warmup, self()),
53    nil = albedo_registry:forget(albedo_session_progress, warmup),
54    Parent = self(),
55    Owner = spawn(fun() ->
56        receive start -> ok end,
57        nil = albedo_bus:register_progress(Session, self(), fun(_) -> nil end),
58        nil = albedo_bus:mark_running(Session, true),
59        Parent ! {ready, self()},
60        owner_loop(Session)
61    end),
62    erlang:trace(Owner, true, [procs, {tracer, Parent}]),
63    Owner ! start,
64    Watcher = receive {trace, Owner, spawn, Child, _} -> Child
65        after 5000 -> error(progress_monitor_missing) end,
66    receive {ready, Owner} -> ok after 5000 -> error(owner_start_stalled) end,
67    erlang:trace(Owner, false, [procs]),
68    {Owner, Watcher}.
69
70owner_loop(Session) ->
71    receive
72        {idle, Parent} ->
73            nil = albedo_bus:mark_running(Session, false),
74            Parent ! {idle, self()},
75            owner_loop(Session);
76        stop -> ok
77    end.
78
79stop(Pid) ->
80    Monitor = monitor(process, Pid),
81    Pid ! stop,
82    receive {'DOWN', Monitor, process, Pid, _} -> ok
83    after 5000 -> error({owner_stop_stalled, Pid}) end.
84
85wait_for_exit(Pid) ->
86    Monitor = monitor(process, Pid),
87    receive {'DOWN', Monitor, process, Pid, _} -> ok
88    after 5000 -> error({monitor_cleanup_stalled, Pid}) end.