diff options
Diffstat (limited to 'priv/templates')
-rw-r--r-- | priv/templates/ctsuite.erl | 167 | ||||
-rw-r--r-- | priv/templates/ctsuite.template | 2 | ||||
-rw-r--r-- | priv/templates/simplenode.nodetool | 62 | ||||
-rwxr-xr-x | priv/templates/simplenode.runner | 23 |
4 files changed, 244 insertions, 10 deletions
diff --git a/priv/templates/ctsuite.erl b/priv/templates/ctsuite.erl new file mode 100644 index 0000000..33a8fac --- /dev/null +++ b/priv/templates/ctsuite.erl @@ -0,0 +1,167 @@ +%% common_test suite for {{testmod}} + +-module({{testmod}}_SUITE). +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +%%-------------------------------------------------------------------- +%% Function: suite() -> Info +%% +%% Info = [tuple()] +%% List of key/value pairs. +%% +%% Description: Returns list of tuples to set default properties +%% for the suite. +%% +%% Note: The suite/0 function is only meant to be used to return +%% default data values, not perform any other operations. +%%-------------------------------------------------------------------- +suite() -> [{timetrap, {seconds, 20}}]. + +%%-------------------------------------------------------------------- +%% Function: groups() -> [Group] +%% +%% Group = {GroupName,Properties,GroupsAndTestCases} +%% GroupName = atom() +%% The name of the group. +%% Properties = [parallel | sequence | Shuffle | {RepeatType,N}] +%% Group properties that may be combined. +%% GroupsAndTestCases = [Group | {group,GroupName} | TestCase] +%% TestCase = atom() +%% The name of a test case. +%% Shuffle = shuffle | {shuffle,Seed} +%% To get cases executed in random order. +%% Seed = {integer(),integer(),integer()} +%% RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | +%% repeat_until_any_ok | repeat_until_any_fail +%% To get execution of cases repeated. +%% N = integer() | forever +%% +%% Description: Returns a list of test case group definitions. +%%-------------------------------------------------------------------- +groups() -> []. + +%%-------------------------------------------------------------------- +%% Function: all() -> GroupsAndTestCases +%% +%% GroupsAndTestCases = [{group,GroupName} | TestCase] +%% GroupName = atom() +%% Name of a test case group. +%% TestCase = atom() +%% Name of a test case. +%% +%% Description: Returns the list of groups and test cases that +%% are to be executed. +%% +%% NB: By default, we export all 1-arity user defined functions +%%-------------------------------------------------------------------- +all() -> + [ {exports, Functions} | _ ] = ?MODULE:module_info(), + [ FName || {FName, _} <- lists:filter( + fun ({module_info,_}) -> false; + ({all,_}) -> false; + ({init_per_suite,1}) -> false; + ({end_per_suite,1}) -> false; + ({_,1}) -> true; + ({_,_}) -> false + end, Functions)]. + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Reason = term() +%% The reason for skipping the suite. +%% +%% Description: Initialization before the suite. +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config0) -> void() | {save_config,Config1} +%% +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Cleanup after the suite. +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_group(GroupName, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% +%% GroupName = atom() +%% Name of the test case group that is about to run. +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding configuration data for the group. +%% Reason = term() +%% The reason for skipping all test cases and subgroups in the group. +%% +%% Description: Initialization before each test case group. +%%-------------------------------------------------------------------- +init_per_group(_group, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_group(GroupName, Config0) -> +%% void() | {save_config,Config1} +%% +%% GroupName = atom() +%% Name of the test case group that is finished. +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding configuration data for the group. +%% +%% Description: Cleanup after each test case group. +%%-------------------------------------------------------------------- +end_per_group(_group, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config0) -> +%% Config1 | {skip,Reason} | {skip_and_save,Reason,Config1} +%% +%% TestCase = atom() +%% Name of the test case that is about to run. +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Reason = term() +%% The reason for skipping the test case. +%% +%% Description: Initialization before each test case. +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_testcase(TestCase, Config) -> + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config0) -> +%% void() | {save_config,Config1} | {fail,Reason} +%% +%% TestCase = atom() +%% Name of the test case that is finished. +%% Config0 = Config1 = [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Reason = term() +%% The reason for failing the test case. +%% +%% Description: Cleanup after each test case. +%%-------------------------------------------------------------------- +end_per_testcase(TestCase, Config) -> + Config. + +test_{{testmod}}() -> + [{userdata,[{doc,"Testing the {{testmod}} module"}]}]. + +test_{{testmod}}(_Config) -> + {skip,"Not implemented."}. diff --git a/priv/templates/ctsuite.template b/priv/templates/ctsuite.template new file mode 100644 index 0000000..b7de337 --- /dev/null +++ b/priv/templates/ctsuite.template @@ -0,0 +1,2 @@ +{variables, [{testmod, "mymodule"}]}. +{template, "ctsuite.erl", "test/{{testmod}}_SUITE.erl"}. diff --git a/priv/templates/simplenode.nodetool b/priv/templates/simplenode.nodetool index 971f983..eb08fa4 100644 --- a/priv/templates/simplenode.nodetool +++ b/priv/templates/simplenode.nodetool @@ -1,4 +1,5 @@ -%% -*- erlang -*- +%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ft=erlang ts=4 sw=4 et %% ------------------------------------------------------------------- %% %% nodetool: Helper Script for interacting with live nodes @@ -6,6 +7,7 @@ %% ------------------------------------------------------------------- main(Args) -> + ok = start_epmd(), %% Extract the args {RestArgs, TargetNode} = process_args(Args, [], undefined), @@ -30,7 +32,8 @@ main(Args) -> ["reboot"] -> io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); ["rpc", Module, Function | RpcArgs] -> - case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), [RpcArgs], 60000) of + case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), + [RpcArgs], 60000) of ok -> ok; {badrpc, Reason} -> @@ -39,6 +42,15 @@ main(Args) -> _ -> halt(1) end; + ["rpcterms", Module, Function, ArgsAsString] -> + case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), + consult(ArgsAsString), 60000) of + {badrpc, Reason} -> + io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), + halt(1); + Other -> + io:format("~p\n", [Other]) + end; Other -> io:format("Other: ~p\n", [Other]), io:format("Usage: nodetool {ping|stop|restart|reboot}\n") @@ -62,6 +74,27 @@ process_args([Arg | Rest], Acc, Opts) -> process_args(Rest, [Arg | Acc], Opts). +start_epmd() -> + [] = os:cmd(epmd_path() ++ " -daemon"), + ok. + +epmd_path() -> + ErtsBinDir = filename:dirname(escript:script_name()), + Name = "epmd", + case os:find_executable(Name, ErtsBinDir) of + false -> + case os:find_executable(Name) of + false -> + io:format("Could not find epmd.~n"), + halt(1); + GlobalEpmd -> + GlobalEpmd + end; + Epmd -> + Epmd + end. + + nodename(Name) -> case string:tokens(Name, "@") of [_Node, _Host] -> @@ -78,3 +111,28 @@ append_node_suffix(Name, Suffix) -> [Node] -> list_to_atom(lists:concat([Node, Suffix, os:getpid()])) end. + + +%% +%% Given a string or binary, parse it into a list of terms, ala file:consult/0 +%% +consult(Str) when is_list(Str) -> + consult([], Str, []); +consult(Bin) when is_binary(Bin)-> + consult([], binary_to_list(Bin), []). + +consult(Cont, Str, Acc) -> + case erl_scan:tokens(Cont, Str, 0) of + {done, Result, Remaining} -> + case Result of + {ok, Tokens, _} -> + {ok, Term} = erl_parse:parse_term(Tokens), + consult([], Remaining, [Term | Acc]); + {eof, _Other} -> + lists:reverse(Acc); + {error, Info, _} -> + {error, Info} + end; + {more, Cont1} -> + consult(Cont1, eof, Acc) + end. diff --git a/priv/templates/simplenode.runner b/priv/templates/simplenode.runner index cfde552..18fa951 100755 --- a/priv/templates/simplenode.runner +++ b/priv/templates/simplenode.runner @@ -7,6 +7,7 @@ RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd) RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log +# Note the trailing slash on $PIPE_DIR/ PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ RUNNER_USER= @@ -58,10 +59,10 @@ case "$1" in echo "Node is already running!" exit 1 fi - export HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start" + HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start" + export HEART_COMMAND mkdir -p $PIPE_DIR - # Note the trailing slash on $PIPE_DIR/ - $ERTS_PATH/run_erl -daemon $PIPE_DIR/ $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console" 2>&1 + $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console" 2>&1 ;; stop) @@ -70,16 +71,16 @@ case "$1" in Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) # PID COMMAND PID=`ps ax -o pid= -o command=|\ - grep "$RUNNER_BASE_DIR/.*/[b]eam"|cut -d' ' -f1` + grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` ;; SunOS) # PID COMMAND PID=`ps -ef -o pid= -o args=|\ - grep "$RUNNER_BASE_DIR/.*/[b]eam"|cut -d' ' -f1` + grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` ;; CYGWIN*) # UID PID PPID TTY STIME COMMAND - PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|cut -d' ' -f2` + PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'` ;; esac $NODETOOL stop @@ -116,13 +117,19 @@ case "$1" in $ERTS_PATH/to_erl $PIPE_DIR ;; - console) + console|console_clean) + # .boot file typically just $SCRIPT (ie, the app name) + # however, for debugging, sometimes start_clean.boot is useful: + case "$1" in + console) BOOTFILE=$SCRIPT ;; + console_clean) BOOTFILE=start_clean ;; + esac # Setup beam-required vars ROOTDIR=$RUNNER_BASE_DIR BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin EMU=beam PROGNAME=`echo $0 | sed 's/.*\\///'` - CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$SCRIPT -embedded -config $RUNNER_ETC_DIR/app.config -args_file $RUNNER_ETC_DIR/vm.args -- ${1+"$@"}" + CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -embedded -config $RUNNER_ETC_DIR/app.config -args_file $RUNNER_ETC_DIR/vm.args -- ${1+"$@"}" export EMU export ROOTDIR export BINDIR |