Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

examples, documentation

  • Loading branch information...
commit 3c94486309513eeb36da095ee0deae831b211df9 1 parent b721a63
@hyperthunk hyperthunk authored
View
3  Makefile
@@ -26,6 +26,7 @@ SOURCE_DIR=src
TEST_DIR=test
EBIN_DIR=ebin
DEPS=$(shell erl -noshell -eval '[io:format("~p~n", [element(1, D)]) || D <- proplists:get_value(deps, element(2, file:consult("rebar.config")))], halt(0).').
+LATEST_STABLE=$(shell git log stable --oneline -1 --format="%h")
## rules start here
@@ -46,7 +47,7 @@ all: escriptize
.PHONY: info
info: $(REBAR)
- $(info SysTest $(shell git describe --abbrev=0))
+ $(info SysTest $(shell git describe --abbrev=0 ${LATEST_STABLE}))
$(info $(shell $(REBAR) -V))
$(info 3rd Party Dependencies: ${DEPS})
View
47 examples/quickstart/Makefile
@@ -0,0 +1,47 @@
+## ----------------------------------------------------------------------------
+##
+## Copyright (c) 2005 - 2012 Nebularis.
+##
+## Permission is hereby granted, free of charge, to any person obtaining a copy
+## of this software and associated documentation files (the "Software"), deal
+## in the Software without restriction, including without limitation the rights
+## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+## copies of the Software, and to permit persons to whom the Software is
+## furnished to do so, subject to the following conditions:
+##
+## The above copyright notice and this permission notice shall be included in
+## all copies or substantial portions of the Software.
+##
+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+## IN THE SOFTWARE.
+## ----------------------------------------------------------------------------
+TOPDIR_1=$(abspath ../../../)/
+TOPDIR=$(abspath ../..)/
+REBAR=$(addprefix $(TOPDIR),bin/rebar)
+SYSTEST=$(addprefix $(TOPDIR),priv/bin/systest)
+LOGLEVEL ?= 0
+VERBOSE ?= 'false'
+
+ifneq ($(VERBOSE), 'false')
+NOISE=-L framework -L operator
+else
+NOISE=
+endif
+
+.PHONY: test-compile
+test-compile: $(REBAR)
+ ERL_LIBS="${TOPDIR_1}:${ERL_LIBS}" $(REBAR) compile -v $(LOGLEVEL)
+
+.PHONY: test-compile
+test: test-compile $(SYSTEST)
+ ERL_LIBS="${TOPDIR_1}:${ERL_LIBS}" $(SYSTEST) $(NOISE)
+
+$(REBAR): $(SYSTEST)
+
+$(SYSTEST):
+ make -C ${TOPDIR}
View
6 examples/quickstart/resources/example_1.resource
@@ -0,0 +1,6 @@
+{system_1, [
+ {sut, [{localhost, [node1, node2]}]},
+ {processes, [{node1, [sasl_node]}, {node2, [sasl_node]}]}
+]}.
+
+{example_1_SUITE, [{all, system_1}]}.
View
7 examples/quickstart/resources/nodes.resource
@@ -0,0 +1,7 @@
+{sasl_node, [
+ {startup, [{handler, systest_slave}]},
+ {flags, [{start, "-boot start_sasl +W w +K true +A30 +P 1048576"
+ " -pa ${settings.base_dir}/ebin "
+ "-sasl sasl_error_logger false"}]},
+ {apps, [{sasl, [{errlog_type, error}]}]}
+]}.
View
43 examples/quickstart/src/example_1_SUITE.erl
@@ -0,0 +1,43 @@
+%% file ./test/example_1_SUITE.erl
+-module(example_1_SUITE).
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eunit/include/eunit.hrl").
+-compile(export_all).
+
+-import(systest_utils, [make_node/1]).
+
+all() ->
+ systest_suite:export_all(?MODULE).
+
+check_that_our_nodes_are_up(_Config) ->
+ ?assertEqual(pong, net_adm:ping(make_node('node1'))),
+ ?assertEqual(pong, net_adm:ping(make_node('node2'))).
+
+%% NB: this test *is* going to fail!!!
+deliberately_kill_node(_Config) ->
+ rpc:call(make_node('node1'), init, stop, []),
+ %% we need enough time to 'detect' the node is down before the test ends
+ timer:sleep(2000),
+ ok.
+
+stopping_and_restarting_nodes(Config) ->
+ %% the active_sut/1 call will fail if there is no SUT configured
+ %% for this particular test case
+ Sut = systest:active_sut(Config),
+
+ %% we can print out status info to the console like so:
+ systest_sut:print_status(Sut),
+
+ %% and we can get the process info for the SUT as well
+ [{Id1, Ref1},{Id2, Ref2}] = systest:procs(Sut),
+
+ %% let's stop one and wait long enough to ensure it shuts down...
+ systest:stop_and_wait(Ref1),
+
+ %% and let's restart the second one!
+ {ok, {Id2, NewRef2}} = systest:restart_process(Sut, Ref2),
+
+ %% and our assertions....
+ ?assertEqual(pang, net_adm:ping(Id1)),
+ ?assertEqual(pong, net_adm:ping(Id2)).
+
View
12 examples/quickstart/src/quickstart.app.src
@@ -0,0 +1,12 @@
+{application, quickstart,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, { quickstart_app, []}},
+ {env, []}
+ ]}.
View
2  src/systest.app.src
@@ -1,7 +1,7 @@
{application, systest,
[
{description, ""},
- {vsn, {cmd, "git describe --abbrev=0 | sed 's/v//g'"}},
+ {vsn, {cmd, "git describe --abbrev=0 `git log stable --oneline -1 --format=\"%h\"` | sed 's/v//g'"}},
{registered, []},
{applications, [
kernel,
View
10 src/systest.erl
@@ -143,6 +143,16 @@ sigkill(Pid) ->
Result = os:cmd("kill -9 " ++ Pid),
systest_log:log(framework, Result).
+%% @doc Stops the Systest (Operating) Process ProcRef
+%% @end
+stop_no_wait(ProcRef) ->
+ systest_proc:stop(ProcRef).
+
+%% @doc Stops the Systest (Operating) Process ProcRef
+%% @end
+kill_no_wait(ProcRef) ->
+ systest_proc:kill(ProcRef).
+
%% @doc Instructs the {@link systest_proc. <em>Process</em>} to stop and waits
%% until it has completed its shutdown and fully stopped. Stopping a
%% {@link systest_proc. <em>Process</em>} in this way does <em>not</em> cause
View
23 src/systest_event.erl
@@ -45,24 +45,27 @@ descriptor(Other) ->
console(Msg, Args) ->
systest_log:log(Msg, Args).
+framework(Msg, Args) ->
+ systest_log:log(framework, Msg, Args).
+
init([]) ->
{ok, []}.
handle_event(#event{name=tc_start, data={Suite,FuncOrGroup}}, State) ->
case FuncOrGroup of
init_per_suite ->
- console("starting test suite ~p~n", [Suite]);
+ framework("starting test suite ~p~n", [Suite]);
end_per_suite ->
ok;
{Conf,GroupName,_GroupProperties} ->
case Conf of
init_per_group ->
- console("starting test case group ~p~n", [GroupName]);
+ framework("starting test case group ~p~n", [GroupName]);
end_per_group ->
ok
end;
Func ->
- console("starting ~p test case ~p~n", [Suite, Func])
+ framework("starting ~p test case ~p~n", [Suite, Func])
end,
{ok, State};
handle_event(#event{name=tc_done,
@@ -70,7 +73,11 @@ handle_event(#event{name=tc_done,
{N, Desc} = descriptor(FuncOrGroup),
case Result of
ok ->
- console("~s ~p completed successfully~n", [Desc, N]);
+ LogF = case is_ct_wrap_function(N) of
+ true -> fun framework/2;
+ false -> fun console/2
+ end,
+ LogF("~s ~p completed successfully~n", [Desc, N]);
{skipped, SkipReason} ->
case SkipReason of
{require_failed, {_, Key}} ->
@@ -119,6 +126,14 @@ fail_info({failed,{_Suite,end_per_testcase,FailInfo}}) ->
fail_info(Other) ->
io_lib:format("Fail Info ~p", [Other]).
+is_ct_wrap_function(init_per_testcase) -> true;
+is_ct_wrap_function(init_per_group) -> true;
+is_ct_wrap_function(init_per_suite) -> true;
+is_ct_wrap_function(end_per_testcase) -> true;
+is_ct_wrap_function(end_per_group) -> true;
+is_ct_wrap_function(end_per_suite) -> true;
+is_ct_wrap_function(_) -> false.
+
%%
%% @private
%%
View
3  static/HOME.md
@@ -3,6 +3,9 @@
This is the *SysTest* wiki. Below you will find links to information about
the tool and accessing its API documentation.
+The user guide is still a work in progress, but you can (and should) read the
+[[QuickStart|quickstart]] if you want to get going immediately.
+
## User Guide
The user guide consists of four sections, which should be read together.
View
2  static/concepts.asciidoc
@@ -4,8 +4,6 @@ framework is key to getting the most out of it.
== Overview
-
-
== Runtime Environment
== The _System Under Test_
View
4 static/developers.md
@@ -18,7 +18,9 @@ components installed on your system:
- To use (optional) `systest_ssh` handlers, an [ssh client][ssh]
In order to use the (optional) `systest_foreign_node` handler, you will need a
-valid install of the target language/platform on your system.
+valid install of the target language/platform on your system. For `systest_script`
+interfaces, you will need to acquire the correct Lua and/or Python dependencies.
+This process has not yet been fully automated.
For `{target, jvm}` you will need a JRE installed on your system and should
ensure that your `JAVA_HOME` environment variable is set properly. You will also
View
70 static/quickstart.md
@@ -1,4 +1,4 @@
-## Installing
+## Installing SysTest
To install from source, clone the repository using git, or download the version
you want to use from the [github downloads page][downloads]. The git clone
@@ -23,6 +23,12 @@ main *SysTest* directory somewhere where it can be utilised by your tests at
runtime, or adding it to your `ERL_LIBS` environment variable. This will also
be necessary if you plan on running `xref` or `dialyzer` on your test code.
+## Getting the sources for this tutorial
+
+The source for this tutorial are included in the `./examples/quickstart` folder
+inside the top level systest repository. There is also a sample `Makefile` which
+exports a `test` target that you can run to see everything working as expected.
+
## Writing your first test case
We will consider how to configure and use *SysTest* via the Erlang/OTP
@@ -112,9 +118,14 @@ A minimal example looks something like this:
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
+-import(systest_utils, [make_node/1]).
+
+all() ->
+ systest_suite:export_all(?MODULE).
+
check_that_our_nodes_are_up(_Config) ->
- ?assertEqual(pong, net_adm:ping('node1@host1')),
- ?assertEqual(pong, net_adm:ping('node2@host1')).
+ ?assertEqual(pong, net_adm:ping(make_node('node1'))),
+ ?assertEqual(pong, net_adm:ping(make_node('node2'))).
```
Note that we can safely assume that our nodes survive for the duration of the
@@ -134,19 +145,56 @@ slave nodes without _informing_ *SysTest* about it, which the testing framework
will construe as a failure.
```erlang
-%% file ./test/example_1_SUITE.erl
--module(example_1_SUITE).
--include_lib("common_test/include/ct.hrl").
--include_lib("eunit/include/eunit.hrl").
--compile(export_all).
-
deliberately_kill_node(_Config) ->
- rpc:call('node1@host1', init, stop, []),
+ rpc:call(make_node('node1'), init, stop, []),
+ %% we need enough time to 'detect' the node is down before the test ends
+ timer:sleep(2000),
ok.
+```
+
+Do be aware that this test case _will_ fail when it is run. You can delete it
+from the test suite (or remove the function name from the results of all/0) if
+you wish to keep it but not let it run.
+
+### Handling deliberate shut down and restarts
-%% etc
+If the framework assumes a test case has failed whenever a _Process_ (e.g., an
+Erlang node in our example) ceases unexpectedly, how are we to test situations
+in which a stop or restart is actually required, for example a cluster failover
+handling scenario?
+
+*SysTest* provides an API for explicitly performing such actions without causing
+test cases to fail. We will stop one node and restart another, and verify the
+state of both afterwards. In order to interact with our nodes, we must acquire
+references to them, using a *SUT* reference to do so. The latter reference can
+be acquired from the common test config parameter.
+
+```erlang
+stopping_and_restarting_nodes(Config) ->
+ %% the active_sut/1 call will fail if there is no SUT configured
+ %% for this particular test case
+ Sut = systest:get_system_under_test(Config),
+
+ %% we can print out status info to the console like so:
+ systest_sut:print_status(Sut),
+
+ %% and we can get the process info for the SUT as well
+ [{Id1, Ref1},{Id2, Ref2}] = systest:procs(Sut)],
+
+ %% let's stop one and wait long enough to ensure it shuts down...
+ systest:stop_and_wait(Ref1),
+
+ %% and let's restart the second one!
+ {ok, {Id2, NewRef2}} = systest:restart_process(Sut, Ref2),
+
+ %% and our assertions....
+ ?assertEqual(pang, net_adm:ping(Id1)),
+ ?assertEqual(pong, net_adm:ping(Id2)).
```
+As we can see, the nodes (which are our operating _Processes_ for this *SUT*)
+are left in exactly the state we expect them to be in.
+
## Links
[wiki]: https://github.com/nebularis/systest/wiki
Please sign in to comment.
Something went wrong with that request. Please try again.