1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%%-------------------------------------------------------------------
22%%% File        : conn_SUITE
23%%% Description : Check that the generic connection handling in CT
24%%%               works as expected.
25%%%-------------------------------------------------------------------
26-module(conn_SUITE).
27
28%% Note: This directive should only be used in test suites.
29-compile(export_all).
30
31-include_lib("common_test/include/ct.hrl").
32
33%%--------------------------------------------------------------------
34%% COMMON TEST CALLBACK FUNCTIONS
35%%--------------------------------------------------------------------
36
37suite() ->
38    [{timetrap,{seconds,5}}].
39
40init_per_suite(Config) ->
41    Config.
42
43end_per_suite(_Config) ->
44    ok.
45
46init_per_testcase(_TestCase, Config) ->
47    Config.
48
49end_per_testcase(_TestCase, _Config) ->
50    ok.
51
52all() ->
53    [handles_to_multi_conn_pids, handles_to_single_conn_pids,
54     names_to_multi_conn_pids, names_to_single_conn_pids].
55
56%%--------------------------------------------------------------------
57%% TEST CASES
58%%--------------------------------------------------------------------
59
60handles_to_multi_conn_pids() ->
61    [{require,multi_conn_pid}].
62
63handles_to_multi_conn_pids(_Config) ->
64    application:set_env(ct_test, reconnect, true),
65
66    Handle1 = proto:open(multi_conn_pid),
67    ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
68    {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
69    Handle2 = proto:open(multi_conn_pid),
70    ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
71    {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
72    Handle3 = proto:open(multi_conn_pid),
73    ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
74    {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
75
76    monitor_procs([Handle1,ConnPid1,Handle2,ConnPid2,Handle3,ConnPid3]),
77
78    ok = proto:close(Handle1),
79    ok = wait_procs_down([Handle1,ConnPid1]),
80    {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
81    {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
82
83    ok = proto:kill_conn_proc(Handle2),
84    ok = wait_procs_down([ConnPid2]),
85    {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
86    ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
87    true = is_process_alive(ConnPid2x),
88
89    monitor_procs([ConnPid2x]),
90
91    ok = proto:close(Handle2),
92    ok = wait_procs_down([Handle2,ConnPid2x]),
93    {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
94
95    application:set_env(ct_test, reconnect, false),
96    ok = proto:kill_conn_proc(Handle3),
97    ok = wait_procs_down([Handle3,ConnPid3]),
98    {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
99
100    ok.
101
102handles_to_single_conn_pids() ->
103    [{require,single_conn_pid}].
104
105handles_to_single_conn_pids(_Config) ->
106    application:set_env(ct_test, reconnect, true),
107
108    Handle1 = proto:open(single_conn_pid),
109    ConnPid = ct_gen_conn:get_conn_pid(Handle1),
110    {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
111    Handle2 = proto:open(single_conn_pid),
112    ConnPid = ct_gen_conn:get_conn_pid(Handle2),
113    {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
114    Handle3 = proto:open(single_conn_pid),
115    ConnPid = ct_gen_conn:get_conn_pid(Handle3),
116    {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
117
118    Conns = [{undefined,Handle1,_,_},
119	     {undefined,Handle2,_,_},
120	     {undefined,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
121    ct:pal("CONNS = ~n~p", [Conns]),
122
123    monitor_procs([Handle1,Handle2,Handle3,ConnPid]),
124    ok = proto:close(Handle1),
125    ok = wait_procs_down([Handle1]),
126    {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
127
128    ok = proto:kill_conn_proc(Handle2),
129    ok = wait_procs_down([ConnPid]),
130    NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
131    NewConnPid = ct_gen_conn:get_conn_pid(Handle3),
132    true = is_process_alive(Handle2),
133    true = is_process_alive(Handle3),
134    false = is_process_alive(ConnPid),
135
136    monitor_procs([NewConnPid]),
137
138    ok = proto:close(Handle2),
139    ok = wait_procs_down([Handle2]),
140    {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
141
142    application:set_env(ct_test, reconnect, false),
143    ok = proto:kill_conn_proc(Handle3),
144    ok = wait_procs_down([Handle3,NewConnPid]),
145    {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
146
147    ok.
148
149names_to_multi_conn_pids() ->
150    [{require,mconn1,multi_conn_pid},
151     {require,mconn2,multi_conn_pid},
152     {require,mconn3,multi_conn_pid}].
153
154names_to_multi_conn_pids(_Config) ->
155    application:set_env(ct_test, reconnect, true),
156
157    Handle1 = proto:open(mconn1),
158    ConnPid1 = ct_gen_conn:get_conn_pid(Handle1),
159    {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
160    Handle2 = proto:open(mconn2),
161    ConnPid2 = ct_gen_conn:get_conn_pid(Handle2),
162    {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
163    Handle3 = proto:open(mconn3),
164    ConnPid3 = ct_gen_conn:get_conn_pid(Handle3),
165    {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
166
167    Handle1 = proto:open(mconn1),
168
169    monitor_procs([Handle1,ConnPid1,Handle2,ConnPid2,Handle3,ConnPid3]),
170
171    ok = proto:close(mconn1),
172    ok = wait_procs_down([Handle1,ConnPid1]),
173    {false,false} = {is_process_alive(Handle1),is_process_alive(ConnPid1)},
174
175    ok = proto:kill_conn_proc(Handle2),
176    ok = wait_procs_down([ConnPid2]),
177    Handle2 = proto:open(mconn2),  % should've been reconnected already
178    {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2)},
179    ConnPid2x = ct_gen_conn:get_conn_pid(Handle2),
180    true = is_process_alive(ConnPid2x),
181
182    monitor_procs([ConnPid2x]),
183
184    ok = proto:close(mconn2),
185    ok = wait_procs_down([Handle2,ConnPid2x]),
186    {false,false} = {is_process_alive(Handle2),is_process_alive(ConnPid2x)},
187    Handle2y = proto:open(mconn2),
188    ConnPid2y = ct_gen_conn:get_conn_pid(Handle2y),
189    {true,true} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
190
191    monitor_procs([Handle2y,ConnPid2y]),
192
193    ok = proto:close(mconn2),
194    ok = wait_procs_down([Handle2y,ConnPid2y]),
195    {false,false} = {is_process_alive(Handle2y),is_process_alive(ConnPid2y)},
196
197    application:set_env(ct_test, reconnect, false),
198    ok = proto:kill_conn_proc(Handle3),
199    ok = wait_procs_down([Handle3,ConnPid3]),
200    {false,false} = {is_process_alive(Handle3),is_process_alive(ConnPid3)},
201
202    ok.
203
204names_to_single_conn_pids() ->
205    [{require,sconn1,single_conn_pid},
206     {require,sconn2,single_conn_pid},
207     {require,sconn3,single_conn_pid}].
208
209names_to_single_conn_pids(_Config) ->
210    application:set_env(ct_test, reconnect, true),
211
212    Handle1 = proto:open(sconn1),
213    ConnPid = ct_gen_conn:get_conn_pid(Handle1),
214    {true,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
215    Handle2 = proto:open(sconn2),
216    ConnPid = ct_gen_conn:get_conn_pid(Handle2),
217    {true,true} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
218    Handle3 = proto:open(sconn3),
219    ConnPid = ct_gen_conn:get_conn_pid(Handle3),
220    {true,true} = {is_process_alive(Handle3),is_process_alive(ConnPid)},
221
222    Handle1 = proto:open(sconn1),
223
224    Conns = [{sconn1,Handle1,_,_},
225	     {sconn2,Handle2,_,_},
226	     {sconn3,Handle3,_,_}] = lists:sort(ct_util:get_connections(ConnPid)),
227    ct:pal("CONNS on ~p = ~n~p", [ConnPid,Conns]),
228
229    monitor_procs([Handle1,Handle2,Handle3,ConnPid]),
230
231    ok = proto:close(sconn1),
232    ok = wait_procs_down([Handle1]),
233    {false,true} = {is_process_alive(Handle1),is_process_alive(ConnPid)},
234
235    ok = proto:kill_conn_proc(Handle2),
236    ok = wait_procs_down([ConnPid]),
237    {true,false} = {is_process_alive(Handle2),is_process_alive(ConnPid)},
238    Handle2 = proto:open(sconn2),  % should've been reconnected already
239    NewConnPid = ct_gen_conn:get_conn_pid(Handle2),
240    true = is_process_alive(NewConnPid),
241
242    monitor_procs([NewConnPid]),
243
244    Conns1 = [{sconn2,Handle2,_,_},
245	      {sconn3,Handle3,_,_}] =
246	lists:sort(ct_util:get_connections(NewConnPid)),
247    ct:pal("CONNS on ~p = ~n~p", [NewConnPid,Conns1]),
248
249    ok = proto:close(sconn2),
250    ok = wait_procs_down([Handle2]),
251    {false,true} = {is_process_alive(Handle2),is_process_alive(NewConnPid)},
252
253    application:set_env(ct_test, reconnect, false),
254    ok = proto:kill_conn_proc(Handle3),
255    ok = wait_procs_down([Handle3,NewConnPid]),
256    {false,false} = {is_process_alive(Handle3),is_process_alive(NewConnPid)},
257
258    ok.
259
260
261%%%-----------------------------------------------------------------
262monitor_procs(Pids) ->
263    [erlang:monitor(process,Pid) || Pid <- Pids],
264    ok.
265
266wait_procs_down([]) ->
267    ok;
268wait_procs_down(Pids) ->
269    receive
270	{'DOWN',_,process,Pid,_} ->
271	    wait_procs_down(lists:delete(Pid,Pids))
272    after 2000 ->
273	    timeout
274    end.
275
276