From 85272930ebdf97ba8cf65962da17e980403ef06c Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Mon, 19 Sep 2011 11:05:23 +0200 Subject: Migrate app suite to pure ct and simplify --- lib/diameter/test/diameter_app_SUITE.erl | 139 +++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 lib/diameter/test/diameter_app_SUITE.erl (limited to 'lib/diameter/test/diameter_app_SUITE.erl') diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl new file mode 100644 index 0000000000..898f302457 --- /dev/null +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Tests based on the contents of the diameter app file. +%% + +-module(diameter_app_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([keys/1, + modules/1, + exports/1, + applications/1, + undefined_calls/1, undefined_calls/0]). + +-define(APP, diameter). +-define(A, list_to_atom). + +%% =========================================================================== + +suite() -> + [{timetrap, {seconds, 10}}]. + +all() -> + [keys, + modules, + exports, + applications, + undefined_calls]. + +init_per_suite(Config) -> + {ok, App} = diameter_util:appfile(?APP), + [{app, App} | Config]. + +end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +%% keys/1 +%% +%% Ensure that the app file contain required keys. + +keys(Config) -> + App = fetch(app, Config), + [] = lists:filter(fun(K) -> not lists:keymember(K, 1, App) end, + [vsn, description, modules, registered, applications]). + +%% modules/1 +%% +%% Ensure that the app file module list match the installed beams. + +modules(Config) -> + Mods = fetch(modules, fetch(app, Config)), + Installed = installed_mods(), + {[], []} = {Mods -- Installed, Installed -- Mods}. + +installed_mods() -> + Dir = code:lib_dir(?APP, ebin), + {ok, Files} = file:list_dir(Dir), + [?A(lists:reverse(R)) || N <- Files, "maeb." ++ R <- [lists:reverse(N)]]. + +%% exports/1 +%% +%% Ensure that no module does export_all. + +exports(Config) -> + Mods = fetch(modules, fetch(app, Config)), + [] = [M || M <- Mods, exports_all(M)]. + +exports_all(Mod) -> + Opts = fetch(options, Mod:module_info(compile)), + + is_list(Opts) andalso lists:member(export_all, Opts). + +%% applications/1 +%% +%% Ensure that each dependent application is on the code path. + +applications(Config) -> + As = fetch(applications, fetch(app, Config)), + [] = [A || A <- As, {error, _} <- [diameter_util:appfile(A)]]. + +%% undefined_calls/1 +%% +%% Ensure that no function on our application calls an undefined function. + +undefined_calls() -> + [{timetrap, {minutes, 2}}]. + +undefined_calls(Config) -> + Mods = fetch(modules, fetch(app, Config)), + + RootDir = code:root_dir(), + EbinDir = code:lib_dir(?APP, ebin), + + {ok, XRef} = xref:start(make_name(xref_test_name)), + ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]), + + XRefName = make_name(xref_name), + {ok, XRefName} = xref:add_release(XRef, RootDir, {name, XRefName}), + {ok, _} = xref:replace_application(XRef, ?APP, EbinDir), + + {ok, Undefs} = xref:analyze(XRef, undefined_function_calls), + + xref:stop(XRef), + + [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs). + +make_name(Suf) -> + list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). + +%% =========================================================================== + +fetch(Key, List) -> + {Key, Val} = lists:keyfind(Key, 1, List), + Val. -- cgit v1.2.3 From c70314ecb08697d0926c0e86e048cd22dab60068 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 27 Jul 2011 19:26:57 +0200 Subject: Move appup tests into app suite and use systools for both --- lib/diameter/test/diameter_app_SUITE.erl | 139 ++++++++++++++++++++++++++----- 1 file changed, 117 insertions(+), 22 deletions(-) (limited to 'lib/diameter/test/diameter_app_SUITE.erl') diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 898f302457..718f28d066 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -30,10 +30,12 @@ %% testcases -export([keys/1, + vsn/1, modules/1, exports/1, - applications/1, - undefined_calls/1, undefined_calls/0]). + release/1, + xref/1, xref/0, + relup/1]). -define(APP, diameter). -define(A, list_to_atom). @@ -45,46 +47,62 @@ suite() -> all() -> [keys, + vsn, modules, exports, - applications, - undefined_calls]. + release, + xref, + relup]. init_per_suite(Config) -> - {ok, App} = diameter_util:appfile(?APP), + [{application, ?APP, App}] = diameter_util:consult(?APP, app), [{app, App} | Config]. end_per_suite(_Config) -> ok. %% =========================================================================== - -%% keys/1 +%% # keys/1 %% -%% Ensure that the app file contain required keys. +%% Ensure that the app file contains selected keys. Some of these would +%% also be caught by other testcases. +%% =========================================================================== keys(Config) -> App = fetch(app, Config), [] = lists:filter(fun(K) -> not lists:keymember(K, 1, App) end, [vsn, description, modules, registered, applications]). -%% modules/1 +%% =========================================================================== +%% # vsn/1 +%% +%% Ensure that our app version sticks to convention. +%% =========================================================================== + +vsn(Config) -> + true = is_vsn(fetch(vsn, fetch(app, Config))). + +%% =========================================================================== +%% # modules/1 %% %% Ensure that the app file module list match the installed beams. +%% =========================================================================== modules(Config) -> Mods = fetch(modules, fetch(app, Config)), - Installed = installed_mods(), + Installed = code_mods(), {[], []} = {Mods -- Installed, Installed -- Mods}. -installed_mods() -> +code_mods() -> Dir = code:lib_dir(?APP, ebin), {ok, Files} = file:list_dir(Dir), [?A(lists:reverse(R)) || N <- Files, "maeb." ++ R <- [lists:reverse(N)]]. -%% exports/1 +%% =========================================================================== +%% # exports/1 %% %% Ensure that no module does export_all. +%% =========================================================================== exports(Config) -> Mods = fetch(modules, fetch(app, Config)), @@ -95,22 +113,38 @@ exports_all(Mod) -> is_list(Opts) andalso lists:member(export_all, Opts). -%% applications/1 +%% =========================================================================== +%% # release/1 %% -%% Ensure that each dependent application is on the code path. +%% Ensure that it's possible to build a minimal release with our app file. +%% =========================================================================== -applications(Config) -> - As = fetch(applications, fetch(app, Config)), - [] = [A || A <- As, {error, _} <- [diameter_util:appfile(A)]]. +release(Config) -> + App = fetch(app, Config), + Rel = {release, + {"diameter test release", fetch(vsn, App)}, + {erts, erlang:system_info(version)}, + [{A, appvsn(A)} || A <- fetch(applications, App)]}, + Dir = fetch(priv_dir, Config), + ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel), + {ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]}, + {outdir, Dir}, + silent]). + +appvsn(Name) -> + [{application, Name, App}] = diameter_util:consult(Name, app), + fetch(vsn, App). -%% undefined_calls/1 +%% =========================================================================== +%% # xref/1 %% -%% Ensure that no function on our application calls an undefined function. +%% Ensure that no function in our application calls an undefined function. +%% =========================================================================== -undefined_calls() -> +xref() -> [{timetrap, {minutes, 2}}]. -undefined_calls(Config) -> +xref(Config) -> Mods = fetch(modules, fetch(app, Config)), RootDir = code:root_dir(), @@ -133,7 +167,68 @@ make_name(Suf) -> list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). %% =========================================================================== +%% # relup/1 +%% +%% Ensure that we can generate release upgrade files using our appup file. +%% =========================================================================== + +relup(Config) -> + [{Vsn, Up, Down}] = diameter_util:consult(?APP, appup), + true = is_vsn(Vsn), + + App = fetch(app, Config), + Rel = [{erts, erlang:system_info(version)} + | [{A, appvsn(A)} || A <- fetch(applications, App)]], + + Dir = fetch(priv_dir, Config), + + Name = write_rel(Dir, Rel, Vsn), + UpFrom = acc_rel(Dir, Rel, Up), + DownTo = acc_rel(Dir, Rel, Down), + + {[Name], [Name], UpFrom, DownTo} %% no intersections + = {[Name] -- UpFrom, + [Name] -- DownTo, + UpFrom -- DownTo, + DownTo -- UpFrom}, + + {ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]}, + {outdir, Dir}, + silent]). + +acc_rel(Dir, Rel, List) -> + lists:foldl(fun(T,A) -> acc_rel(Dir, Rel, T, A) end, + [], + List). + +acc_rel(Dir, Rel, {Vsn, _}, Acc) -> + [write_rel(Dir, Rel, Vsn) | Acc]. + +%% Write a rel file and return its name. +write_rel(Dir, [Erts | Apps], Vsn) -> + true = is_vsn(Vsn), + Name = "diameter_test_" ++ Vsn, + ok = write_file(filename:join([Dir, Name ++ ".rel"]), + {release, + {"diameter " ++ Vsn ++ " test release", Vsn}, + Erts, + Apps}), + Name. + +%% =========================================================================== +%% =========================================================================== fetch(Key, List) -> - {Key, Val} = lists:keyfind(Key, 1, List), + {Key, {Key, Val}} = {Key, lists:keyfind(Key, 1, List)}, %% useful badmatch Val. + +write_file(Path, T) -> + file:write_file(Path, io_lib:format("~p.", [T])). + +%% Is a version string of the expected form? Return the argument +%% itself for 'false' for a useful badmatch. +is_vsn(V) -> + is_list(V) + andalso length(V) == string:span(V, "0123456789.") + andalso V == string:join(string:tokens(V, [$.]), ".") %% no ".." + orelse {error, V}. -- cgit v1.2.3 From e3902570caa368c759fdf3b19981991bf43b57ec Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Tue, 16 Aug 2011 11:34:18 +0200 Subject: Improve xref testcase --- lib/diameter/test/diameter_app_SUITE.erl | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'lib/diameter/test/diameter_app_SUITE.erl') diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 718f28d066..170166d1e6 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -34,7 +34,7 @@ modules/1, exports/1, release/1, - xref/1, xref/0, + xref/1, relup/1]). -define(APP, diameter). @@ -141,28 +141,42 @@ appvsn(Name) -> %% Ensure that no function in our application calls an undefined function. %% =========================================================================== -xref() -> - [{timetrap, {minutes, 2}}]. - xref(Config) -> - Mods = fetch(modules, fetch(app, Config)), - - RootDir = code:root_dir(), - EbinDir = code:lib_dir(?APP, ebin), + App = fetch(app, Config), + Mods = fetch(modules, App) -- [diameter_codegen, diameter_dbg], + %% Skip modules that aren't required at runtime and that have + %% dependencies beyond those applications listed in the app file. {ok, XRef} = xref:start(make_name(xref_test_name)), ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]), - XRefName = make_name(xref_name), - {ok, XRefName} = xref:add_release(XRef, RootDir, {name, XRefName}), - {ok, _} = xref:replace_application(XRef, ?APP, EbinDir), + %% Only add our application and those it's dependent on according + %% to the app file. Well, almost. erts beams are also required to + %% stop xref from complaining about calls to module erlang, which + %% was previously in kernel. Erts isn't an application however, in + %% the sense that there's no .app file, and isn't listed in + %% applications. Seems less than ideal. + ok = lists:foreach(fun(A) -> add_application(XRef, A) end, + [?APP, erts | fetch(applications, App)]), {ok, Undefs} = xref:analyze(XRef, undefined_function_calls), xref:stop(XRef), + %% Only care about calls from our own application. [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs). +add_application(XRef, App) -> + add_application(XRef, App, code:lib_dir(App)). + +%% erts will not be in the lib directory before installation. +add_application(XRef, erts, {error, _}) -> + Dir = filename:join([code:root_dir(), "erts", "preloaded", "ebin"]), + {ok, _} = xref:add_directory(XRef, Dir, []); +add_application(XRef, App, Dir) + when is_list(Dir) -> + {ok, App} = xref:add_application(XRef, Dir, []). + make_name(Suf) -> list_to_atom(atom_to_list(?APP) ++ "_" ++ atom_to_list(Suf)). -- cgit v1.2.3 From 81f0eeffd5116b7529619b3f4cba1c2ff2144566 Mon Sep 17 00:00:00 2001 From: Anders Svensson Date: Wed, 14 Sep 2011 17:53:23 +0200 Subject: Minor macro cleanup --- lib/diameter/test/diameter_app_SUITE.erl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/diameter/test/diameter_app_SUITE.erl') diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl index 170166d1e6..d710fa155d 100644 --- a/lib/diameter/test/diameter_app_SUITE.erl +++ b/lib/diameter/test/diameter_app_SUITE.erl @@ -37,7 +37,8 @@ xref/1, relup/1]). --define(APP, diameter). +-include("diameter_ct.hrl"). + -define(A, list_to_atom). %% =========================================================================== -- cgit v1.2.3