aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/snmp')
-rw-r--r--lib/snmp/src/agent/snmpa_set.erl13
-rw-r--r--lib/snmp/test/Makefile2
-rw-r--r--lib/snmp/test/modules.mk2
-rw-r--r--lib/snmp/test/snmp_agent_test.erl61
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl326
-rw-r--r--lib/snmp/test/snmp_manager_test.erl141
-rw-r--r--lib/snmp/test/snmp_test_global_sys_monitor.erl214
-rw-r--r--lib/snmp/test/snmp_test_lib.erl152
-rw-r--r--lib/snmp/test/snmp_test_lib.hrl11
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl17
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl3
-rw-r--r--lib/snmp/test/snmp_test_server.erl4
-rw-r--r--lib/snmp/test/snmp_test_sys_monitor.erl86
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl143
14 files changed, 917 insertions, 258 deletions
diff --git a/lib/snmp/src/agent/snmpa_set.erl b/lib/snmp/src/agent/snmpa_set.erl
index 9833d6fdcc..b3a3bf0ab0 100644
--- a/lib/snmp/src/agent/snmpa_set.erl
+++ b/lib/snmp/src/agent/snmpa_set.erl
@@ -163,10 +163,14 @@ set_phase_two(MyVarbinds, SubagentVarbinds) ->
[MyVarbinds, SubagentVarbinds]),
case snmpa_set_lib:try_set(MyVarbinds) of
{noError, 0} ->
+ ?vtrace("set phase two: (local) varbinds set ok", []),
set_phase_two_subagents(SubagentVarbinds);
- {ErrorStatus, Index} ->
+ {ErrorStatus, ErrorIndex} ->
+ ?vlog("set phase two: (local) varbinds set failed"
+ "~n ErrorStatus: ~p"
+ "~n ErrorIndex: ~p", [ErrorStatus, ErrorIndex]),
set_phase_two_undo_subagents(SubagentVarbinds),
- {ErrorStatus, Index}
+ {ErrorStatus, ErrorIndex}
end.
%%-----------------------------------------------------------------
@@ -188,6 +192,7 @@ set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
{_SAOids, Vbs} = sa_split(SAVbs),
case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of
{noError, 0} ->
+ ?vtrace("set phase two: subagent ~p varbinds set ok", [SubAgentPid]),
set_phase_two_subagents(SubagentVarbinds);
{'EXIT', Reason} ->
user_err("Lost contact with subagent (set)~n~w. Using genErr",
@@ -195,10 +200,14 @@ set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
set_phase_two_undo_subagents(SubagentVarbinds),
{genErr, 0};
{ErrorStatus, ErrorIndex} ->
+ ?vlog("set phase two: subagent ~p varbinds set failed"
+ "~n ErrorStatus: ~p"
+ "~n ErrorIndex: ~p", [SubAgentPid, ErrorStatus, ErrorIndex]),
set_phase_two_undo_subagents(SubagentVarbinds),
{ErrorStatus, ErrorIndex}
end;
set_phase_two_subagents([]) ->
+ ?vtrace("set phase two: subagent(s) set ok", []),
{noError, 0}.
%%-----------------------------------------------------------------
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index a9142d911d..d9b01536ea 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -180,7 +180,7 @@ emakebuild: $(EMAKEFILE)
targets: mib $(EMAKEFILE)
erl -make
-old_targets: $(TARGET_FILES) $(TEST_SERVER_TARGETS)
+old_targets: mib $(TARGET_FILES) $(TEST_SERVER_TARGETS)
$(EMAKEFILE): Makefile
$(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' > $(EMAKEFILE)
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 8b6547f9a9..ec3870dbd8 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -42,6 +42,8 @@ SUITE_MODULES = \
snmp_manager_test
TEST_UTIL_MODULES = \
+ snmp_test_global_sys_monitor \
+ snmp_test_sys_monitor \
snmp_test_lib \
snmp_test_manager \
snmp_test_mgr \
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 71e3fa3b9a..a45cfa9e98 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -557,6 +557,8 @@ init_per_suite(Config0) when is_list(Config0) ->
Config3 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2],
+ snmp_test_global_sys_monitor:start(),
+ snmp_test_sys_monitor:start(), % We need one on this node also
snmp_test_mgr_counter_server:start(),
p("init_per_suite -> end when"
@@ -580,6 +582,8 @@ end_per_suite(Config) when is_list(Config) ->
p("end_per_suite -> failed stopping counter server"
"~n Reason: ~p", [Reason])
end,
+ snmp_test_sys_monitor:stop(),
+ snmp_test_global_sys_monitor:stop(),
p("end_per_suite -> end when"
"~n Nodes: ~p", [erlang:nodes()]),
@@ -667,22 +671,39 @@ init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
init_per_group_ipv6(GroupName, Config, Init) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- Init(
- snmp_test_lib:init_group_top_dir(
- GroupName,
- [{ipfamily, inet6},
- {ip, ?LOCALHOST(inet6)}
- | lists:keydelete(ip, 1, Config)]));
- false ->
- {skip, "Host does not support IPV6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
+ %% <OS-CONDITIONAL-SKIP>
+ %% This is a higly questionable test.
+ %% But until we have time to figure out what IPv6 issues
+ %% are actually causing the failures...
+ OSSkipable = [{unix,
+ [
+ {darwin, fun(V) when (V > {9, 8, 0}) ->
+ %% This version is OK: No Skip
+ false;
+ (_) ->
+ %% This version is *not* ok: Skip
+ true
+ end}
+ ]
+ }],
+ %% </OS-CONDITIONAL-SKIP>
+ case ?OS_BASED_SKIP(OSSkipable) of
+ true ->
+ {skip, "Host *may* not *properly* support IPV6"};
+ false ->
+ %% Even if this host supports IPv6 we don't use it unless its
+ %% one of the configured/supported IPv6 hosts...
+ case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ true ->
+ Init(
+ snmp_test_lib:init_group_top_dir(
+ GroupName,
+ [{ipfamily, inet6},
+ {ip, ?LOCALHOST(inet6)}
+ | lists:keydelete(ip, 1, Config)]));
+ false ->
+ {skip, "Host does not support IPv6"}
+ end
end.
end_per_group(all_tcs, Config) ->
@@ -751,6 +772,8 @@ init_per_testcase(Case, Config) when is_list(Config) ->
Result = init_per_testcase1(Case, Config),
+ snmp_test_global_sys_monitor:reset_events(),
+
p("init_per_testcase -> done when"
"~n Result: ~p"
"~n Nodes: ~p", [Result, erlang:nodes()]),
@@ -800,6 +823,9 @@ end_per_testcase(Case, Config) when is_list(Config) ->
"~n Nodes: ~p", [Config, erlang:nodes()]),
display_log(Config),
+
+ p("system events during test: "
+ "~n ~p", [snmp_test_global_sys_monitor:events()]),
Result = end_per_testcase1(Case, Config),
@@ -1637,7 +1663,7 @@ create_local_db_dir(Config) when is_list(Config) ->
Name = list_to_atom(atom_to_list(create_local_db_dir)
++"-"++As++"-"++Bs++"-"++Cs),
Pa = filename:dirname(code:which(?MODULE)),
- {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa "++Pa}]),
+ {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]),
%% first start with a nonexisting DbDir
Fun1 = fun() ->
@@ -6567,7 +6593,6 @@ otp_4394_test() ->
gn([[1,1]]),
Res =
case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
- %% {error, 1, {"?",[]}, {"~w",[timeout]}}
{error, 1, _, {_, [timeout]}} ->
?DBG("otp_4394_test -> expected result: timeout", []),
ok;
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 6defdadb5a..615d6774b9 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -66,7 +66,7 @@
]).
%% Internal exports
--export([wait/5, run/4]).
+-export([tc_wait/5, tc_run/4]).
-include_lib("kernel/include/file.hrl").
-include_lib("common_test/include/ct.hrl").
@@ -276,87 +276,186 @@ init_case(Config) when is_list(Config) ->
%%% configuration.
%%%--------------------------------------------------
-try_test(Mod, Func) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, [], []]).
-
-try_test(Mod, Func, A) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, A, []]).
-
-try_test(Mod, Func, A, Opts) ->
- call(get(mgr_node), ?MODULE, run, [Mod, Func, A, Opts]).
-
-call(N,M,F,A) ->
- ?DBG("call -> entry with~n"
- " N: ~p~n"
- " M: ~p~n"
- " F: ~p~n"
- " A: ~p~n"
- " when~n"
- " get(): ~p",
- [N,M,F,A,get()]),
- spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+try_test(TcRunMod, TcRunFunc) ->
+ try_test(TcRunMod, TcRunFunc, []).
+
+try_test(TcRunMod, TcRunFunc, TcRunArgs) ->
+ try_test(TcRunMod, TcRunFunc, TcRunArgs, []).
+
+try_test(TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts) ->
+ Node = get(mgr_node),
+ Mod = ?MODULE,
+ Func = tc_run,
+ Args = [TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts],
+ tc_try(Node, Mod, Func, Args).
+
+%% We spawn a test case runner process on the manager node.
+%% The assumption is that the manager shall do something, but
+%% not all test cases have the manager perform actions.
+%% In some cases we make a rpc call back to the agent node directly
+%% and call something in the agent... (for example the info_test
+%% test case).
+%% We should use link (instead of monitor) in order for the test case
+%% timeout cleanup (kills) should have effect on the test case runner
+%% process as well.
+
+tc_try(N, M, F, A) ->
+ ?PRINT2("tc_try -> entry with"
+ "~n N: ~p"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n when"
+ "~n get(): ~p"
+ "~n", [N,
+ M, F, A,
+ get()]),
+ case net_adm:ping(N) of
+ pong ->
+ ?PRINT2("tc_try -> ~p still running - start runner~n", [N]),
+ OldFlag = trap_exit(true), % Make sure we catch it
+ Runner = spawn_link(N, ?MODULE, tc_wait, [self(), get(), M, F, A]),
+ await_tc_runner_started(Runner, OldFlag),
+ await_tc_runner_done(Runner, OldFlag);
+ pang ->
+ ?EPRINT2("tc_try -> ~p *not* running~n", [N]),
+ skip({node_not_running, N})
+ end.
+
+await_tc_runner_started(Runner, OldFlag) ->
+ ?PRINT2("await tc-runner (~p) start ack~n", [Runner]),
receive
- {done, {'EXIT', Rn}, Loc} ->
- ?DBG("call -> done with exit: "
- "~n Rn: ~p"
- "~n Loc: ~p", [Rn, Loc]),
+ {'EXIT', Runner, Reason} ->
+ ?EPRINT2("TC runner start failed: "
+ "~n ~p~n", [Reason]),
+ exit({tx_runner_start_failed, Reason});
+ {tc_runner_started, Runner} ->
+ ?PRINT2("TC runner start acknowledged~n"),
+ ok
+ after 10000 -> %% We should *really* not have to wait this long, but...
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
+ RunnerInfo = process_info(Runner),
+ ?EPRINT2("TC runner start timeout: "
+ "~n ~p", [RunnerInfo]),
+ %% If we don't get a start ack within 10 seconds, we are f*ed
+ exit(Runner, kill),
+ exit({tc_runner_start, timeout, RunnerInfo})
+ end.
+
+await_tc_runner_done(Runner, OldFlag) ->
+ receive
+ {'EXIT', Runner, Reason} ->
+ %% This is not a normal (tc) failure (that is the clause below).
+ %% Instead the tc runner process crashed, for some reason. So
+ %% check if have got any system events, and if so, skip.
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ if
+ (SysEvs =:= []) ->
+ ?EPRINT2("TC runner failed: "
+ "~n ~p~n", [Reason]),
+ exit({tx_runner_failed, Reason});
+ true ->
+ ?EPRINT2("TC runner failed when we got system events: "
+ "~n Reason: ~p"
+ "~n Sys Events: ~p"
+ "~n", [Reason, SysEvs]),
+ skip([{reason, Reason}, {system_events, SysEvs}])
+ end;
+ {tc_runner_done, Runner, {'EXIT', {skip, Reason}}, Loc} ->
+ ?PRINT2("call -> done with skip: "
+ "~n Reason: ~p"
+ "~n Loc: ~p"
+ "~n", [Reason, Loc]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
+ put(test_server_loc, Loc),
+ skip(Reason);
+ {tc_runner_done, Runner, {'EXIT', Rn}, Loc} ->
+ ?PRINT2("call -> done with exit: "
+ "~n Rn: ~p"
+ "~n Loc: ~p"
+ "~n", [Rn, Loc]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
put(test_server_loc, Loc),
exit(Rn);
- {done, Ret, _Zed} ->
+ {tc_runner_done, Runner, Ret, _Zed} ->
?DBG("call -> done:"
"~n Ret: ~p"
"~n Zed: ~p", [Ret, _Zed]),
+ trap_exit(OldFlag),
+ unlink_and_flush_exit(Runner),
case Ret of
{error, Reason} ->
exit(Reason);
+ {skip, Reason} ->
+ skip(Reason);
OK ->
OK
end
end.
-wait(From, Env, M, F, A) ->
- ?DBG("wait -> entry with"
- "~n From: ~p"
- "~n Env: ~p"
- "~n M: ~p"
- "~n F: ~p"
- "~n A: ~p", [From, Env, M, F, A]),
+trap_exit(Flag) when is_boolean(Flag) ->
+ erlang:process_flag(trap_exit, Flag).
+
+unlink_and_flush_exit(Pid) ->
+ unlink(Pid),
+ receive
+ {'EXIT', Pid, _} ->
+ ok
+ after 0 ->
+ ok
+ end.
+
+tc_wait(From, Env, M, F, A) ->
+ ?PRINT2("tc_wait -> entry with"
+ "~n From: ~p"
+ "~n Env: ~p"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [From, Env, M, F, A]),
+ From ! {tc_runner_started, self()},
lists:foreach(fun({K,V}) -> put(K,V) end, Env),
- Rn = (catch apply(M, F, A)),
- ?DBG("wait -> Rn: ~n~p", [Rn]),
- From ! {done, Rn, get(test_server_loc)},
- exit(Rn).
-
-run(Mod, Func, Args, Opts) ->
- ?DBG("run -> entry with"
- "~n Mod: ~p"
- "~n Func: ~p"
- "~n Args: ~p"
- "~n Opts: ~p", [Mod, Func, Args, Opts]),
- M = get(mib_dir),
- Dir = get(mgr_dir),
- User = snmp_misc:get_option(user, Opts, "all-rights"),
- SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
- EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ ?PRINT2("tc_wait -> env set - now run tc~n"),
+ Res = (catch apply(M, F, A)),
+ ?PRINT2("tc_wait -> tc run done: "
+ "~n ~p"
+ "~n", [Res]),
+ From ! {tc_runner_done, self(), Res, get(test_server_loc)},
+ exit(Res).
+
+tc_run(Mod, Func, Args, Opts) ->
+ ?PRINT2("tc_run -> entry with"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Opts: ~p"
+ "~n", [Mod, Func, Args, Opts]),
+ (catch snmp_test_mgr:stop()), % If we had a running mgr from a failed case
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
- Community = snmp_misc:get_option(community, Opts, "all-rights"),
- ?DBG("run -> start crypto app",[]),
- _CryptoRes = ?CRYPTO_START(),
- ?DBG("run -> Crypto: ~p", [_CryptoRes]),
- catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
- StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
- Vsn = get(vsn),
- ?DBG("run -> config:"
- "~n M: ~p"
- "~n Vsn: ~p"
- "~n Dir: ~p"
- "~n User: ~p"
- "~n SecLevel: ~p"
- "~n EngineID: ~p"
- "~n CtxEngineID: ~p"
- "~n Community: ~p"
- "~n StdM: ~p",
- [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("tc_run -> start crypto app",[]),
+ _CryptoRes = ?CRYPTO_START(),
+ ?DBG("tc_run -> Crypto: ~p", [_CryptoRes]),
+ StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
+ Vsn = get(vsn),
+ ?PRINT2("tc_run -> config:"
+ "~n M: ~p"
+ "~n Vsn: ~p"
+ "~n Dir: ~p"
+ "~n User: ~p"
+ "~n SecLevel: ~p"
+ "~n EngineID: ~p"
+ "~n CtxEngineID: ~p"
+ "~n Community: ~p"
+ "~n StdM: ~p"
+ "~n", [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
{packet_server_debug, true},
{debug, true},
@@ -376,24 +475,45 @@ run(Mod, Func, Args, Opts) ->
{mibs, mibs(StdM, M)}]) of
{ok, _Pid} ->
case (catch apply(Mod, Func, Args)) of
+ {'EXIT', {skip, Reason}} ->
+ ?EPRINT2("apply skip detected: "
+ "~n ~p", [Reason]),
+ (catch snmp_test_mgr:stop()),
+ ?SKIP(Reason);
{'EXIT', Reason} ->
- catch snmp_test_mgr:stop(),
- ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
+ %% We have hosts (mostly *very* slooow VMs) that
+ %% can timeout anything. Since we are basically
+ %% testing communication, we therefor must check
+ %% for system events at every failure. Grrr!
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ (catch snmp_test_mgr:stop()),
+ if
+ (SysEvs =:= []) ->
+ ?EPRINT2("TC runner failed: "
+ "~n ~p~n", [Reason]),
+ ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
+ true ->
+ ?EPRINT2("apply exit catched when we got system events: "
+ "~n Reason: ~p"
+ "~n Sys Events: ~p"
+ "~n", [Reason, SysEvs]),
+ ?SKIP([{reason, Reason}, {system_events, SysEvs}])
+ end;
Res ->
- catch snmp_test_mgr:stop(),
+ (catch snmp_test_mgr:stop()),
Res
end;
{error, Reason} ->
?EPRINT2("Failed starting (test) manager: "
"~n ~p", [Reason]),
- catch snmp_test_mgr:stop(),
+ (catch snmp_test_mgr:stop()),
?line ?FAIL({mgr_start_error, Reason});
Err ->
?EPRINT2("Failed starting (test) manager: "
"~n ~p", [Err]),
- catch snmp_test_mgr:stop(),
+ (catch snmp_test_mgr:stop()),
?line ?FAIL({mgr_start_failure, Err})
end.
@@ -907,10 +1027,22 @@ expect2(Mod, Line, F) ->
%% ----------------------------------------------------------------------
-get_timeout() ->
- get_timeout(os:type()).
+-define(BASE_REQ_TIMEOUT, 3500).
-get_timeout(_) -> 3500.
+get_timeout() ->
+ %% Try to figure out how "fast" a machine is.
+ %% We assume that the number of schedulers
+ %% (which depends on the number of core:s)
+ %% effect the performance of the host...
+ %% This is obviously not enough. The network
+ %% also matterns, clock freq or the CPU, ...
+ %% But its better than what we had before...
+ case erlang:system_info(schedulers) of
+ N when is_integer(N) ->
+ ?BASE_REQ_TIMEOUT + timer:seconds(10 div N);
+ _ ->
+ ?BASE_REQ_TIMEOUT
+ end.
receive_pdu(To) ->
receive
@@ -1083,6 +1215,18 @@ do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
{PureE, Generic, Specific, ExpVBs},
{Ent2, G2, Spec2, VBs}}};
+ {error, timeout} = Error ->
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ io_format_expect("[expecting trap] got timeout when system events:"
+ "~n ~p", [SysEvs]),
+ if
+ (SysEvs =:= []) ->
+ Error;
+ true ->
+ skip({system_events, SysEvs})
+ end;
+
+
Error ->
Error
end.
@@ -1184,7 +1328,7 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
io_format_expect("received unexpected pdu with (11) "
"~n Type: ~p"
"~n ReqId: ~p"
- "~n Errot status: ~p"
+ "~n Error status: ~p"
"~n Error index: ~p",
[Type2, ReqId, Err2, Idx2]),
{error,
@@ -1247,7 +1391,7 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
io_format_expect("received unexpected pdu with (15) "
"~n Type: ~p"
"~n ReqId: ~p"
- "~n Errot status: ~p"
+ "~n Error status: ~p"
"~n Error index: ~p"
"~n Varbinds: ~p",
[Type2, ReqId, Err2, Idx2, VBs2]),
@@ -1257,10 +1401,23 @@ do_expect2(Check, Type, Err, Idx, ExpVBs, To)
{Type2, Err2, Idx2, VBs2},
ReqId}};
- Error ->
- io_format_expect("received error (16): "
+
+ {error, timeout} = Error ->
+ SysEvs = snmp_test_global_sys_monitor:events(),
+ io_format_expect("got timeout (16) when system events:"
+ "~n ~p", [SysEvs]),
+ if
+ (SysEvs =:= []) ->
+ Error;
+ true ->
+ skip({system_events, SysEvs})
+ end;
+
+
+ Error ->
+ io_format_expect("received error (17): "
"~n Error: ~p", [Error]),
- Error
+ Error
end.
@@ -1378,12 +1535,15 @@ start_node(Name) ->
""
end,
%% Do not use start_link!!! (the proc that calls this one is tmp)
- ?DBG("start_node -> Args: ~p~n",[Args]),
- A = Args ++ " -pa " ++ Pa,
+ ?DBG("start_node -> Args: ~p~n", [Args]),
+ A = Args ++ " -pa " ++ Pa ++
+ " -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++
+ " -s global sync",
case (catch ?START_NODE(Name, A)) of
{ok, Node} ->
%% Tell the test_server to not clean up things it never started.
?DBG("start_node -> Node: ~p",[Node]),
+ global:sync(),
{ok, Node};
Else ->
?ERR("start_node -> failed with(other): Else: ~p",[Else]),
@@ -1701,6 +1861,10 @@ rpc(Node, F, A) ->
join(Dir, File) ->
filename:join(Dir, File).
+
+skip(R) ->
+ exit({skip, R}).
+
%% await_pdu(To) ->
%% await_response(To, pdu).
%%
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 5b0ebf8647..7cd3eae0c7 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -619,38 +619,47 @@ init_per_group(event_tests_mt = GroupName, Config) ->
GroupName,
[{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6_mt = GroupName, Config) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ipv6_init(
- snmp_test_lib:init_group_top_dir(
- GroupName,
- [{manager_net_if_module, snmpm_net_if_mt}
- | Config]));
- false ->
- {skip, "Host does not support IPv6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
- end;
+ init_per_group_ipv6(GroupName,
+ [{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6 = GroupName, Config) ->
- {ok, Hostname0} = inet:gethostname(),
- case ct:require(ipv6_hosts) of
- ok ->
- case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
- true ->
- ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
- false ->
- {skip, "Host does not support IPv6"}
- end;
- _ ->
- {skip, "Test config ipv6_hosts is missing"}
- end;
+ init_per_group_ipv6(GroupName, Config);
init_per_group(GroupName, Config) ->
snmp_test_lib:init_group_top_dir(GroupName, Config).
+
+init_per_group_ipv6(GroupName, Config) ->
+ %% <OS-CONDITIONAL-SKIP>
+ OSSkipable = [{unix,
+ [
+ {darwin, fun(V) when (V > {9, 8, 0}) ->
+ %% This version is OK: No Skip
+ false;
+ (_) ->
+ %% This version is *not* ok: Skip
+ %% We need a fully qualified hostname
+ %% to get a proper IPv6 address (in this
+ %% version), but its just to messy, so
+ %% instead we skip this **OLD** darwin...
+ true
+ end}
+ ]
+ }],
+ %% </OS-CONDITIONAL-SKIP>
+ case ?OS_BASED_SKIP(OSSkipable) of
+ true ->
+ {skip, "Host *may* not *properly* support IPV6"};
+ false ->
+ %% Even if this host supports IPv6 we don't use it unless its
+ %% one of the configures/supported IPv6 hosts...
+ case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ true ->
+ ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
+ false ->
+ {skip, "Host does not support IPv6"}
+ end
+ end.
+
+
end_per_group(_GroupName, Config) ->
%% Do we really need to do this?
lists:keydelete(snmp_group_top_dir, 1, Config).
@@ -4832,7 +4841,7 @@ inform2(Config) when is_list(Config) ->
"~n ~p", [Addr]),
ok;
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- p("<ERROR> received expected \"no response\" "
+ e("Received unexpected \"no response\" "
"notification from: "
"~n ~p", [Addr]),
{error, no_response}
@@ -4966,7 +4975,7 @@ inform3(Config) when is_list(Config) ->
"~n ~p", [Addr]),
ok;
{snmp_notification, inform3_tag1, {got_response, Addr}} ->
- p("<ERROR> received unexpected \"got response\" "
+ e("Received unexpected \"got response\" "
"notification from: "
"~n ~p",
[Addr]),
@@ -5253,7 +5262,7 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
inform_swarm_collector(N, SentAckCnt, RecvCnt+1, RespCnt,
Timeout);
{Err, Idx, VBs} ->
- p("<ERROR> unexpected error status: "
+ e("Unexpected error status: "
"~n Err: ~p"
"~n Idx: ~p"
"~n VBs: ~p", [Err, Idx, VBs]),
@@ -5272,7 +5281,7 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
%% The agent did not received ack from the manager in time
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- p("<ERROR> received expected \"no response\" notification "
+ e("Received expected \"no response\" notification "
"from: "
"~n ~p", [Addr]),
Reason = {no_response, Addr, {N, SentAckCnt, RecvCnt, RespCnt}},
@@ -5449,10 +5458,10 @@ command_handler([{No, Desc, Cmd}|Cmds]) ->
p("command_handler -> ~w: ok",[No]),
command_handler(Cmds);
{error, Reason} ->
- p("<ERROR> command_handler -> ~w error: ~n~p",[No, Reason]),
+ e("Command_handler -> ~w error: ~n~p",[No, Reason]),
?line ?FAIL({command_failed, No, Reason});
Error ->
- p("<ERROR> command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ e("Command_handler -> ~w unexpected: ~n~p",[No, Error]),
?line ?FAIL({unexpected_command_result, No, Error})
end.
@@ -6318,6 +6327,8 @@ start_manager_node() ->
start_node(snmp_manager).
start_node(Name) ->
+ start_node(Name, true).
+start_node(Name, Retry) ->
Pa = filename:dirname(code:which(?MODULE)),
Args = case init:get_argument('CC_TEST') of
{ok, [[]]} ->
@@ -6328,30 +6339,47 @@ start_node(Name) ->
""
end,
A = Args ++ " -pa " ++ Pa,
- case (catch ?START_NODE(Name, A)) of
+ try ?START_NODE(Name, A) of
{ok, Node} ->
Node;
- Else ->
- ?line ?FAIL(Else)
+ {error, timeout} ->
+ e("Failed starting node ~p: timeout", [Name]),
+ ?line ?FAIL({error_starting_node, Name, timeout});
+ {error, {already_running, Node}} when (Retry =:= true) ->
+ %% Ouch
+ %% Either we previously failed to (properly) stop the node
+ %% or it was a failed start, that reported failure (for instance
+ %% timeout) but actually succeeded. Regardless, we don't know
+ %% the state of this node, so (try) stop it and then (re-) try
+ %% start again.
+ e("Failed starting node ~p: Already Running - try stop", [Node]),
+ case ?STOP_NODE(Node) of
+ true ->
+ p("Successfully stopped old node ~p", [Node]),
+ start_node(Name, false);
+ false ->
+ e("Failed stop old node ~p", [Node]),
+ ?line ?FAIL({error_starting_node, Node, Retry, already_running})
+ end;
+ {error, {already_running, Node}} ->
+ e("Failed starting node ~p: Already Running", [Node]),
+ ?line ?FAIL({error_starting_node, Node, Retry, already_running});
+ {error, Reason} ->
+ e("Failed starting node ~p: ~p", [Name, Reason]),
+ ?line ?FAIL({error_starting_node, Name, Reason})
+ catch
+ exit:{suite_failed, Reason} ->
+ e("(suite) Failed starting node ~p: ~p", [Name, Reason]),
+ ?line ?FAIL({failed_starting_node, Name, Reason})
end.
-stop_node(Node) ->
- rpc:cast(Node, erlang, halt, []),
- await_stopped(Node, 5).
-await_stopped(Node, 0) ->
- p("await_stopped -> ~p still exist: giving up", [Node]),
- ok;
-await_stopped(Node, N) ->
- Nodes = erlang:nodes(),
- case lists:member(Node, Nodes) of
- true ->
- p("await_stopped -> ~p still exist: ~w", [Node, N]),
- ?SLEEP(1000),
- await_stopped(Node, N-1);
- false ->
- p("await_stopped -> ~p gone: ~w", [Node, N]),
- ok
+stop_node(Node) ->
+ case ?STOP_NODE(Node) of
+ true ->
+ ok;
+ false ->
+ ?line ?FAIL({failed_stop_node, Node})
end.
@@ -6596,12 +6624,15 @@ rcall(Node, Mod, Func, Args) ->
%% ------
+e(F, A) ->
+ p("<ERROR> " ++ F, A).
+
p(F) ->
p(F, []).
p(F, A) ->
p(get(tname), F, A).
-
+
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
"~n " ++ F ++ "~n", [TName, formated_timestamp()|A]).
diff --git a/lib/snmp/test/snmp_test_global_sys_monitor.erl b/lib/snmp/test/snmp_test_global_sys_monitor.erl
new file mode 100644
index 0000000000..eafb96621a
--- /dev/null
+++ b/lib/snmp/test/snmp_test_global_sys_monitor.erl
@@ -0,0 +1,214 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_test_global_sys_monitor).
+
+-export([start/0, stop/0,
+ reset_events/0,
+ events/0,
+ log/1]).
+-export([init/1]).
+
+-define(NAME, ?MODULE).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ Parent = self(),
+ proc_lib:start(?MODULE, init, [Parent]).
+
+stop() ->
+ cast(stop).
+
+%% This does not reset the global counter but the "collector"
+%% See events for more info.
+reset_events() ->
+ cast(reset_events).
+
+events() ->
+ call(events).
+
+log(Event) ->
+ cast({node(), Event}).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(Parent) ->
+ process_flag(priority, high),
+ case global:register_name(?NAME, self()) of
+ yes ->
+ info_msg("Starting", []),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(#{parent => Parent, ev_cnt => 0, evs => []});
+ no ->
+ warning_msg("Already started", []),
+ proc_lib:init_ack(Parent, {error, already_started}),
+ exit(normal)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+loop(State) ->
+ receive
+ {?MODULE, stop} ->
+ warning_msg("Stopping with ~w events counted",
+ [maps:get(ev_cnt, State)]),
+ exit(normal);
+
+ {?MODULE, reset_events} ->
+ loop(State#{evs => []});
+
+ {?MODULE, Ref, From, events} ->
+ Evs = maps:get(evs, State),
+ From ! {?MODULE, Ref, lists:reverse(Evs)},
+ loop(State);
+
+ {?MODULE, {Node, Event}} ->
+ State2 = process_event(State, Node, Event),
+ loop(State2);
+
+ {nodedown = Event, Node} ->
+ State2 = process_event(State, Node, Event),
+ loop(State2);
+
+ _ ->
+ loop(State)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+process_event(State, Node, {Pid, TS, Tag, Info}) ->
+ process_system_event(State, Node, Pid, TS, Tag, Info);
+
+process_event(State, Node, {TS, starting}) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ info_msg("System Monitor on node ~p starting at ~s", [Node, FTS]),
+ if
+ (Node =/= node()) ->
+ erlang:monitor_node(Node, true);
+ true ->
+ ok
+ end,
+ State;
+
+process_event(State, Node, {TS, already_started}) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ info_msg("System Monitor on node ~p already started", [Node, FTS]),
+ State;
+
+process_event(State, Node, nodedown) ->
+ info_msg("Node ~p down", [Node]),
+ State;
+
+process_event(State, Node, Event) ->
+ warning_msg("Received unknown event from node ~p:"
+ "~n ~p", [Node, Event]),
+ State.
+
+
+%% System Monitor events
+%% We only *count* system events
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, long_gc = Ev, Info) ->
+ print_system_event("Long GC", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, long_schedule = Ev, Info) ->
+ print_system_event("Long Schedule", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, large_heap = Ev, Info) ->
+ print_system_event("Large Heap", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, busy_port = Ev, Info) ->
+ print_system_event("Busy port", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+process_system_event(#{ev_cnt := Cnt, evs := Evs} = State,
+ Node, Pid, TS, busy_dist_port = Ev, Info) ->
+ print_system_event("Busy dist port", Node, Pid, TS, Info),
+ State#{ev_cnt => Cnt + 1, evs => [{Node, Ev} | Evs]};
+
+%% And everything else
+process_system_event(State, Node, Pid, TS, Tag, Info) ->
+ Pre = f("Unknown Event '~p'", [Tag]),
+ print_system_event(Pre, Node, Pid, TS, Info),
+ State.
+
+
+print_system_event(Pre, Node, Pid, TS, Info) ->
+ FTS = snmp_misc:format_timestamp(TS),
+ warning_msg("~s from ~p (~p) at ~s:"
+ "~n ~p", [Pre, Node, Pid, FTS, Info]).
+
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+cast(Msg) ->
+ try global:send(?NAME, {?MODULE, Msg}) of
+ Pid when is_pid(Pid) ->
+ ok
+ catch
+ C:E:_ ->
+ {error, {catched, C, E}}
+ end.
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ Ref = make_ref(),
+ try global:send(?NAME, {?MODULE, Ref, self(), Req}) of
+ Pid when is_pid(Pid) ->
+ receive
+ {?MODULE, Ref, Rep} ->
+ Rep
+ after Timeout ->
+ {error, timeout}
+ end
+ catch
+ C:E:_ ->
+ {error, {catched, C, E}}
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+info_msg(F, A) ->
+ error_logger:info_msg(format_msg(F, A), []).
+
+warning_msg(F, A) ->
+ error_logger:warning_msg(format_msg(F, A), []).
+
+
+format_msg(F, A) ->
+ f("~n" ++
+ "****** SNMP TEST GLOBAL SYSTEM MONITOR ******~n~n" ++
+ F ++
+ "~n~n",
+ A).
+
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index a483690653..35bc535a80 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -25,7 +25,9 @@
-export([hostname/0, hostname/1, localhost/0, localhost/1, os_type/0, sz/1,
display_suite_info/1]).
--export([non_pc_tc_maybe_skip/4, os_based_skip/1]).
+-export([non_pc_tc_maybe_skip/4, os_based_skip/1,
+ has_support_ipv6/0, has_support_ipv6/1,
+ is_ipv6_host/0, is_ipv6_host/1]).
-export([fix_data_dir/1,
init_suite_top_dir/2, init_group_top_dir/2, init_testcase_top_dir/2,
lookup/2,
@@ -34,7 +36,7 @@
-export([hours/1, minutes/1, seconds/1, sleep/1]).
-export([flush_mqueue/0, trap_exit/0, trap_exit/1]).
-export([ping/1, local_nodes/0, nodes_on/1]).
--export([start_node/2]).
+-export([start_node/2, stop_node/1]).
-export([is_app_running/1,
is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0]).
-export([crypto_start/0, crypto_support/0]).
@@ -52,11 +54,12 @@ hostname() ->
hostname(node()).
hostname(Node) ->
- from($@, atom_to_list(Node)).
-
-from(H, [H | T]) -> T;
-from(H, [_ | T]) -> from(H, T);
-from(_H, []) -> [].
+ case string:tokens(atom_to_list(Node), [$@]) of
+ [_, Host] ->
+ Host;
+ _ ->
+ []
+ end.
%% localhost() ->
%% {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
@@ -78,7 +81,9 @@ localhost(Family) ->
{error, Reason1} ->
fail({getifaddrs, Reason1}, ?MODULE, ?LINE)
end;
- {ok, {0, _, _, _, _, _, _, _}} when (Family =:= inet6) ->
+ {ok, {A1, _, _, _, _, _, _, _}} when (Family =:= inet6) andalso
+ ((A1 =:= 0) orelse
+ (A1 =:= 16#fe80)) ->
%% Ouch, we need to use something else
case inet:getifaddrs() of
{ok, IfList} ->
@@ -207,53 +212,108 @@ non_pc_tc_maybe_skip(Config, Condition, File, Line)
end.
+%% The type and spec'ing is just to increase readability
+-type os_family() :: win32 | unix.
+-type os_name() :: atom().
+-type os_version() :: string() | {non_neg_integer(),
+ non_neg_integer(),
+ non_neg_integer()}.
+-type os_skip_check() :: fun(() -> boolean()) |
+ fun((os_version()) -> boolean()).
+-type skippable() :: any | [os_family() |
+ {os_family(), os_name() |
+ [os_name() | {os_name(),
+ os_skip_check()}]}].
+
+-spec os_based_skip(skippable()) -> boolean().
+
os_based_skip(any) ->
- io:format("os_based_skip(any) -> entry"
- "~n", []),
true;
os_based_skip(Skippable) when is_list(Skippable) ->
- io:format("os_based_skip -> entry with"
- "~n Skippable: ~p"
- "~n", [Skippable]),
- {OsFam, OsName} =
- case os:type() of
- {_Fam, _Name} = FamAndName ->
- FamAndName;
- Fam ->
- {Fam, undefined}
- end,
- io:format("os_based_skip -> os-type: "
- "~n OsFam: ~p"
- "~n OsName: ~p"
- "~n", [OsFam, OsName]),
+ os_base_skip(Skippable, os:type());
+os_based_skip(_Crap) ->
+ false.
+
+os_base_skip(Skippable, {OsFam, OsName}) ->
+ os_base_skip(Skippable, OsFam, OsName);
+os_base_skip(Skippable, OsFam) ->
+ os_base_skip(Skippable, OsFam, undefined).
+
+os_base_skip(Skippable, OsFam, OsName) ->
+ %% Check if the entire family is to be skipped
+ %% Example: [win32, unix]
case lists:member(OsFam, Skippable) of
true ->
true;
false ->
- case lists:keysearch(OsFam, 1, Skippable) of
- {value, {OsFam, OsName}} ->
- true;
- {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ %% Example: [{unix, freebsd}] | [{unix, [freebsd, darwin]}]
+ case lists:keysearch(OsFam, 1, Skippable) of
+ {value, {OsFam, OsName}} ->
+ true;
+ {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ %% OsNames is a list of:
+ %% [atom()|{atom(), function/0 | function/1}]
case lists:member(OsName, OsNames) of
true ->
true;
false ->
- case lists:keymember(OsName, 1, OsNames) of
- {value, {OsName, Check}} when is_function(Check) ->
- Check();
- _ ->
- false
- end
+ os_based_skip_check(OsName, OsNames)
end;
- _ ->
- false
- end
- end;
-os_based_skip(_Crap) ->
- io:format("os_based_skip -> entry with"
- "~n _Crap: ~p"
- "~n", [_Crap]),
- false.
+ _ ->
+ false
+ end
+ end.
+
+%% Performs a check via a provided fun with arity 0 or 1.
+%% The argument is the result of os:version().
+os_based_skip_check(OsName, OsNames) ->
+ case lists:keysearch(OsName, 1, OsNames) of
+ {value, {OsName, Check}} when is_function(Check, 0) ->
+ Check();
+ {value, {OsName, Check}} when is_function(Check, 1) ->
+ Check(os:version());
+ _ ->
+ false
+ end.
+
+
+%% A basic test to check if current host supports IPv6
+has_support_ipv6() ->
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ has_support_ipv6(Hostname);
+ _ ->
+ false
+ end.
+
+has_support_ipv6(Hostname) ->
+ case inet:getaddr(Hostname, inet6) of
+ {ok, Addr} when (size(Addr) =:= 8) andalso
+ (element(1, Addr) =/= 0) andalso
+ (element(1, Addr) =/= 16#fe80) ->
+ true;
+ {ok, _} ->
+ false;
+ {error, _} ->
+ false
+ end.
+
+
+is_ipv6_host() ->
+ case inet:gethostname() of
+ {ok, Hostname} ->
+ is_ipv6_host(Hostname);
+ {error, _} ->
+ false
+ end.
+
+is_ipv6_host(Hostname) ->
+ case ct:require(ipv6_hosts) of
+ ok ->
+ lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts));
+ _ ->
+ false
+ end.
%% ----------------------------------------------------------------
@@ -452,10 +512,14 @@ nodes_on(Host) when is_list(Host) ->
start_node(Name, Args) ->
- Opts = [{cleanup,false}, {args,Args}],
+ Opts = [{cleanup, false}, {args, Args}],
test_server:start_node(Name, slave, Opts).
+stop_node(Node) ->
+ test_server:stop_node(Node).
+
+
%% ----------------------------------------------------------------
%% Application and Crypto utility functions
%%
diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl
index 335f3fff3c..99b86a928c 100644
--- a/lib/snmp/test/snmp_test_lib.hrl
+++ b/lib/snmp/test/snmp_test_lib.hrl
@@ -49,8 +49,12 @@
snmp_test_lib:os_based_skip(Skippable)).
-define(NON_PC_TC_MAYBE_SKIP(Config, Condition),
snmp_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)).
--define(SKIP(Reason), snmp_test_lib:skip(Reason, ?MODULE, ?LINE)).
--define(FAIL(Reason), snmp_test_lib:fail(Reason, ?MODULE, ?LINE)).
+-define(SKIP(Reason), snmp_test_lib:skip(Reason, ?MODULE, ?LINE)).
+-define(FAIL(Reason), snmp_test_lib:fail(Reason, ?MODULE, ?LINE)).
+-define(IS_IPV6_HOST(), snmp_test_lib:is_ipv6_host()).
+-define(IS_IPV6_HOST(H), snmp_test_lib:is_ipv6_host(H)).
+-define(HAS_SUPPORT_IPV6(), snmp_test_lib:has_support_ipv6()).
+-define(HAS_SUPPORT_IPV6(H), snmp_test_lib:has_support_ipv6(H)).
%% - Time macros -
@@ -88,6 +92,7 @@
-define(LNODES(), snmp_test_lib:local_nodes()).
-define(NODES(H), snmp_test_lib:nodes_on(H)).
-define(START_NODE(N,A), snmp_test_lib:start_node(N,A)).
+-define(STOP_NODE(N), snmp_test_lib:stop_node(N)).
%% - Application and Crypto utility macros -
@@ -150,8 +155,10 @@
snmp_test_lib:print(P, ?MODULE, ?LINE, F, A)).
-define(PRINT1(F, A), snmp_test_lib:print1(F, A)).
+-define(PRINT1(F), ?PRINT1(F, [])).
-define(EPRINT1(F, A), ?PRINT1("<ERROR> " ++ F, A)).
-define(PRINT2(F, A), snmp_test_lib:print2(F, A)).
+-define(PRINT2(F), ?PRINT2(F, [])).
-define(EPRINT2(F, A), ?PRINT2("<ERROR> " ++ F, A)).
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 9190c07e6d..9d6be65088 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -247,10 +247,21 @@ init({Options, CallerPid}) ->
IpFamily = get_value(ipfamily, Options, inet),
print("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
AgIp = case snmp_misc:assq(agent, Options) of
- {value, Tuple4} when is_tuple(Tuple4) andalso
- (size(Tuple4) =:= 4) ->
- Tuple4;
+ {value, Addr} when is_tuple(Addr) andalso
+ (size(Addr) =:= 4) andalso
+ (IpFamily =:= inet) ->
+ print("[~w] ~p -> Addr: ~p~n",
+ [?MODULE, self(), Addr]),
+ Addr;
+ {value, Addr} when is_tuple(Addr) andalso
+ (size(Addr) =:= 8) andalso
+ (IpFamily =:= inet6) ->
+ print("[~w] ~p -> Addr: ~p~n",
+ [?MODULE, self(), Addr]),
+ Addr;
{value, Host} when is_list(Host) ->
+ print("[~w] ~p -> Host: ~p~n",
+ [?MODULE, self(), Host]),
{ok, Ip} = snmp_misc:ip(Host, IpFamily),
Ip
end,
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index 315e3ebd9e..6608a88c00 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -576,6 +576,7 @@ vsn('version-2') -> v2c.
udp_send(UdpId, AgentIp, UdpPort, B) ->
+ ?vlog("attempt send message (~w bytes) to ~p", [sz(B), {AgentIp, UdpPort}]),
case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of
{error,ErrorReason} ->
error("failed (error) sending message to ~p:~p: "
@@ -880,7 +881,7 @@ display_prop_hdr(S) ->
%%----------------------------------------------------------------------
sz(L) when is_list(L) ->
- length(lists:flatten(L));
+ iolist_size(L);
sz(B) when is_binary(B) ->
size(B);
sz(O) ->
diff --git a/lib/snmp/test/snmp_test_server.erl b/lib/snmp/test/snmp_test_server.erl
index a77bdc142c..ab7dbbbaa0 100644
--- a/lib/snmp/test/snmp_test_server.erl
+++ b/lib/snmp/test/snmp_test_server.erl
@@ -207,7 +207,7 @@ do_subcases(Mod, Fun, [{conf, Init, Cases, Finish}|SubCases], Config, Acc)
[{failed, {Mod, Fun}, Error}]
end,
do_subcases(Mod, Fun, SubCases, Config, [R|Acc]);
-do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when atom(SubCase) ->
+do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when is_atom(SubCase) ->
R = do_case(Mod, SubCase, Config),
do_subcases(Mod, Fun, SubCases,Config, [R|Acc]).
@@ -407,7 +407,7 @@ d(_, _, _, _) ->
ok.
timestamp() ->
- {Date, Time} = calendar:now_to_datetime( now() ),
+ {Date, Time} = calendar:now_to_datetime( erlang:timestamp() ),
{YYYY, MM, DD} = Date,
{Hour, Min, Sec} = Time,
FormatDate =
diff --git a/lib/snmp/test/snmp_test_sys_monitor.erl b/lib/snmp/test/snmp_test_sys_monitor.erl
new file mode 100644
index 0000000000..2291c6ca97
--- /dev/null
+++ b/lib/snmp/test/snmp_test_sys_monitor.erl
@@ -0,0 +1,86 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(snmp_test_sys_monitor).
+
+-export([start/0, stop/0,
+ init/1]).
+
+-define(NAME, ?MODULE).
+-define(GSM, snmp_test_global_sys_monitor).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start() ->
+ Parent = self(),
+ proc_lib:start(?MODULE, init, [Parent]).
+
+stop() ->
+ case whereis(?NAME) of
+ Pid when is_pid(Pid) ->
+ Pid ! {?MODULE, stop},
+ ok;
+ _ ->
+ ok
+ end.
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(Parent) ->
+ process_flag(priority, high),
+ try register(?NAME, self()) of
+ true ->
+ global:sync(),
+ MonSettings = [
+ busy_port,
+ busy_dist_port,
+ {long_gc, 1000},
+ {long_schedule, 1000},
+ {large_heap, 8*1024*1024} % 8 MB
+ ],
+ erlang:system_monitor(self(), MonSettings),
+ ?GSM:log({erlang:timestamp(), starting}),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(#{parent => Parent})
+ catch
+ _:_:_ ->
+ ?GSM:log({erlang:timestamp(), already_started}),
+ proc_lib:init_ack(Parent, {error, already_started}),
+ exit(normal)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+loop(State) ->
+ receive
+ {monitor, Pid, Tag, Info} ->
+ ?GSM:log({Pid, erlang:timestamp(), Tag, Info}),
+ loop(State);
+
+ _ ->
+ loop(State)
+ end.
+
+
+
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index b83c7461d1..b8bdb30271 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -247,9 +247,17 @@ erlang_agent_netsnmp_get(Config) when is_list(Config) ->
start_agent(Config),
Oid = ?sysDescr_instance,
Expected = expected(Oid, get),
- [Expected = snmpget(Oid, Transport, Config)
- || Transport <- Transports],
- ok.
+ try
+ begin
+ [Expected = snmpget(Oid, Transport, Config)
+ || Transport <- Transports],
+ ok
+ end
+ catch
+ throw:{skip, _} = SKIP ->
+ SKIP
+ end.
+
%%--------------------------------------------------------------------
erlang_manager_netsnmp_get() ->
@@ -260,29 +268,34 @@ erlang_manager_netsnmp_get(Config) when is_list(Config) ->
SysDescr = "Net-SNMP agent",
TargetName = "Target Net-SNMP agent",
Transports = ?config(transports, Config),
- ProgHandle = start_snmpd(Community, SysDescr, Config),
- start_manager(Config),
- snmp_manager_user:start_link(self(), test_user),
- [snmp_manager_user:register_agent(
- TargetName++domain_suffix(Domain),
- [{reg_type, target_name},
- {tdomain, Domain}, {taddress, Addr},
- {community, Community}, {engine_id, "EngineId"},
- {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
- || {Domain, Addr} <- Transports],
- Results =
- [snmp_manager_user:sync_get(
- TargetName++domain_suffix(Domain),
- [?sysDescr_instance])
- || {Domain, _} <- Transports],
- ct:pal("sync_get -> ~p", [Results]),
- snmp_manager_user:stop(),
- stop_program(ProgHandle),
- [{ok,
- {noError, 0,
- [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
- _} = R || R <- Results],
- ok.
+ case start_snmpd(Community, SysDescr, Config) of
+ {skip, _} = SKIP ->
+ SKIP;
+ ProgHandle ->
+ start_manager(Config),
+ snmp_manager_user:start_link(self(), test_user),
+ [snmp_manager_user:register_agent(
+ TargetName++domain_suffix(Domain),
+ [{reg_type, target_name},
+ {tdomain, Domain}, {taddress, Addr},
+ {community, Community}, {engine_id, "EngineId"},
+ {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
+ || {Domain, Addr} <- Transports],
+ Results =
+ [snmp_manager_user:sync_get(
+ TargetName++domain_suffix(Domain),
+ [?sysDescr_instance])
+ || {Domain, _} <- Transports],
+ ct:pal("sync_get -> ~p", [Results]),
+ snmp_manager_user:stop(),
+ stop_program(ProgHandle),
+ [{ok,
+ {noError, 0,
+ [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
+ _} = R || R <- Results],
+ ok
+ end.
+
%%--------------------------------------------------------------------
erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
@@ -292,17 +305,19 @@ erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
start_agent(Config),
ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)),
- ProgHandle = start_snmptrapd(Mib, Config),
-
- snmpa:send_notification(
- snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
-
- receive
- {snmp_targets, erlang_agent_test, Addresses} ->
- ct:pal("Notification sent to: ~p~n", [Addresses]),
- erlang_agent_netsnmp_inform_responses(Addresses)
- end,
- stop_program(ProgHandle).
+ case start_snmptrapd(Mib, Config) of
+ {skip, _} = SKIP ->
+ SKIP;
+ ProgHandle ->
+ snmpa:send_notification(
+ snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
+ receive
+ {snmp_targets, erlang_agent_test, Addresses} ->
+ ct:pal("Notification sent to: ~p~n", [Addresses]),
+ erlang_agent_netsnmp_inform_responses(Addresses)
+ end,
+ stop_program(ProgHandle)
+ end.
erlang_agent_netsnmp_inform_responses([]) ->
receive
@@ -326,6 +341,7 @@ erlang_agent_netsnmp_inform_responses([Address | Addresses]) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
+
snmpget(Oid, Transport, Config) ->
Versions = ?config(snmp_versions, Config),
@@ -335,10 +351,14 @@ snmpget(Oid, Transport, Config) ->
"-Cf",
net_snmp_addr_str(Transport),
oid_str(Oid)],
- ProgHandle = start_program(snmpget, Args, none, Config),
- {_, line, Line} = get_program_output(ProgHandle),
- stop_program(ProgHandle),
- Line.
+ case start_program(snmpget, Args, none, Config) of
+ {skip, _} = SKIP ->
+ throw(SKIP);
+ ProgHandle ->
+ {_, line, Line} = get_program_output(ProgHandle),
+ stop_program(ProgHandle),
+ Line
+ end.
start_snmptrapd(Mibs, Config) ->
DataDir = ?config(data_dir, Config),
@@ -382,12 +402,13 @@ start_program(Prog, Args, StartCheckMP, Config) ->
DataDir = ?config(data_dir, Config),
StartWrapper = filename:join(DataDir, "start_stop_wrapper"),
Parent = self(),
- Pid =
- spawn_link(
+ %% process_flag(trap_exit, true),
+ {Pid, Mon} =
+ spawn_monitor(
fun () ->
run_program(Parent, StartWrapper, [Path | Args])
end),
- start_check(Pid, erlang:monitor(process, Pid), StartCheckMP).
+ start_check(Pid, Mon, StartCheckMP).
start_check(Pid, Mon, none) ->
{Pid, Mon};
@@ -400,6 +421,10 @@ start_check(Pid, Mon, StartCheckMP) ->
nomatch ->
start_check(Pid, Mon, StartCheckMP)
end;
+ {'DOWN', Mon, _, _Pid, {skip, Reason} = SKIP} ->
+ ct:pal("Received DOWN from ~p"
+ "~n Skip Reason: ~p", [_Pid, Reason]),
+ SKIP;
{'DOWN', Mon, _, _, Reason} ->
ct:fail("Prog ~p start failed: ~p", [Pid, Reason])
end.
@@ -446,14 +471,34 @@ run_program_loop(Parent, Port, Buf) ->
{Port, {data, {Flag, Data}}} ->
case Flag of
eol ->
- Line = iolist_to_binary(lists:reverse(Buf, Data)),
- ct:pal("Prog ~p output: ~s", [Port, Line]),
- Parent ! {self(), line, Line},
- run_program_loop(Parent, Port, []);
+ Line = iolist_to_binary(lists:reverse(Buf, Data)),
+ ct:pal("Prog ~p output: ~s", [Port, Line]),
+ %% There are potentially many different fail outputs,
+ %% but for now we test for just this one: illegal option
+ IOpt = "illegal option",
+ case string:find(binary_to_list(Line), IOpt) of
+ nomatch ->
+ Parent ! {self(), line, Line},
+ run_program_loop(Parent, Port, []);
+ Line2 ->
+ %% Try to extract the actual illegal option string
+ IOpt2 =
+ case string:take(
+ string:prefix(Line2, IOpt), [$-, $ ]) of
+ {_, Str} when length(Str) > 0 ->
+ Str;
+ _X ->
+ Line2
+ end,
+ ct:pal("Force program ~p stop", [Port]),
+ true = port_command(Port, <<"stop\n">>),
+ (catch port_close(Port)),
+ exit({skip, {illegal_option, IOpt2}})
+ end;
noeol ->
run_program_loop(Parent, Port, [Data | Buf])
end;
- {Port, {exit_status,ExitStatus}} ->
+ {Port, {exit_status, ExitStatus}} ->
ct:pal("Prog ~p exit: ~p", [Port, ExitStatus]),
catch port_close(Port),
Parent ! {self(), exit, ExitStatus};