1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
Code.require_file "test_helper.exs", __DIR__
defmodule GenServerTest do
use ExUnit.Case, async: true
defmodule Stack do
use GenServer
def handle_call(:pop, _from, [h | t]) do
{:reply, h, t}
end
def handle_call(:noreply, _from, h) do
{:noreply, h}
end
def handle_call(request, from, state) do
super(request, from, state)
end
def handle_cast({:push, item}, state) do
{:noreply, [item | state]}
end
def handle_cast(request, state) do
super(request, state)
end
def terminate(_reason, _state) do
# There is a race condition if the agent is
# restarted too fast and it is registered.
try do
self() |> Process.info(:registered_name) |> elem(1) |> Process.unregister
rescue
_ -> :ok
end
:ok
end
end
test "start_link/3" do
assert_raise ArgumentError, ~r"expected :name option to be one of:", fn ->
GenServer.start_link(Stack, [:hello], name: "my_gen_server_name")
end
assert_raise ArgumentError, ~r"expected :name option to be one of:", fn ->
GenServer.start_link(Stack, [:hello], name: {:invalid_tuple, "my_gen_server_name"})
end
assert_raise ArgumentError, ~r"expected :name option to be one of:", fn ->
GenServer.start_link(Stack, [:hello], name: {:via, "Via", "my_gen_server_name"})
end
end
test "start_link/3 with via" do
GenServer.start_link(Stack, [:hello], name: {:via, :global, :stack})
assert GenServer.call({:via, :global, :stack}, :pop) == :hello
end
test "start_link/3 with global" do
GenServer.start_link(Stack, [:hello], name: {:global, :stack})
assert GenServer.call({:global, :stack}, :pop) == :hello
end
test "start_link/3 with local" do
GenServer.start_link(Stack, [:hello], name: :stack)
assert GenServer.call(:stack, :pop) == :hello
end
test "start_link/2, call/2 and cast/2" do
{:ok, pid} = GenServer.start_link(Stack, [:hello])
{:links, links} = Process.info(self(), :links)
assert pid in links
assert GenServer.call(pid, :pop) == :hello
assert GenServer.cast(pid, {:push, :world}) == :ok
assert GenServer.call(pid, :pop) == :world
assert GenServer.stop(pid) == :ok
assert GenServer.cast({:global, :foo}, {:push, :world}) == :ok
assert GenServer.cast({:via, :foo, :bar}, {:push, :world}) == :ok
assert GenServer.cast(:foo, {:push, :world}) == :ok
end
@tag capture_log: true
test "call/3 exit messages" do
name = :self
Process.register self(), name
:global.register_name name, self()
{:ok, pid} = GenServer.start_link(Stack, [:hello])
{:ok, stopped_pid} = GenServer.start(Stack, [:hello])
GenServer.stop(stopped_pid)
assert catch_exit(GenServer.call(name, :pop, 5000)) == {:calling_self, {GenServer, :call, [name, :pop, 5000]}}
assert catch_exit(GenServer.call({:global, name}, :pop, 5000)) == {:calling_self, {GenServer, :call, [{:global, name}, :pop, 5000]}}
assert catch_exit(GenServer.call({:via, :global, name}, :pop, 5000)) == {:calling_self, {GenServer, :call, [{:via, :global, name}, :pop, 5000]}}
assert catch_exit(GenServer.call(self(), :pop, 5000)) == {:calling_self, {GenServer, :call, [self(), :pop, 5000]}}
assert catch_exit(GenServer.call(pid, :noreply, 1)) == {:timeout, {GenServer, :call, [pid, :noreply, 1]}}
assert catch_exit(GenServer.call(nil, :pop, 5000)) == {:noproc, {GenServer, :call, [nil, :pop, 5000]}}
assert catch_exit(GenServer.call(stopped_pid, :pop, 5000)) == {:noproc, {GenServer, :call, [stopped_pid, :pop, 5000]}}
assert catch_exit(GenServer.call({:stack, :bogus_node}, :pop, 5000)) == {{:nodedown, :bogus_node}, {GenServer, :call, [{:stack, :bogus_node}, :pop, 5000]}}
end
test "nil name" do
{:ok, pid} = GenServer.start_link(Stack, [:hello], name: nil)
assert Process.info(pid, :registered_name) == {:registered_name, []}
end
test "start/2" do
{:ok, pid} = GenServer.start(Stack, [:hello])
{:links, links} = Process.info(self(), :links)
refute pid in links
GenServer.stop(pid)
end
test "abcast/3" do
{:ok, _} = GenServer.start_link(Stack, [], name: :stack)
assert GenServer.abcast(:stack, {:push, :hello}) == :abcast
assert GenServer.call({:stack, node()}, :pop) == :hello
assert GenServer.abcast([node(), :foo@bar], :stack, {:push, :world}) == :abcast
assert GenServer.call(:stack, :pop) == :world
GenServer.stop(:stack)
end
test "multi_call/4" do
{:ok, _} = GenServer.start_link(Stack, [:hello, :world], name: :stack)
assert GenServer.multi_call(:stack, :pop) ==
{[{node(), :hello}], []}
assert GenServer.multi_call([node(), :foo@bar], :stack, :pop) ==
{[{node(), :world}], [:foo@bar]}
GenServer.stop(:stack)
end
test "whereis/1" do
name = :whereis_server
{:ok, pid} = GenServer.start_link(Stack, [], name: name)
assert GenServer.whereis(name) == pid
assert GenServer.whereis({name, node()}) == pid
assert GenServer.whereis({name, :another_node}) == {name, :another_node}
assert GenServer.whereis(pid) == pid
assert GenServer.whereis(:whereis_bad_server) == nil
{:ok, pid} = GenServer.start_link(Stack, [], name: {:global, name})
assert GenServer.whereis({:global, name}) == pid
assert GenServer.whereis({:global, :whereis_bad_server}) == nil
assert GenServer.whereis({:via, :global, name}) == pid
assert GenServer.whereis({:via, :global, :whereis_bad_server}) == nil
end
test "stop/3" do
{:ok, pid} = GenServer.start(Stack, [])
assert GenServer.stop(pid, :normal) == :ok
{:ok, _} = GenServer.start(Stack, [], name: :stack)
assert GenServer.stop(:stack, :normal) == :ok
end
end
|