From 3e8f9e8b712af4dc0ac63aa6aae779fa35b986e1 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Wed, 6 Dec 2023 10:47:19 +0100 Subject: [PATCH 1/3] Renaming var names to avoid collisions --- test/amoc_config_attributes_SUITE.erl | 99 ++++++++++++----------- test/amoc_config_scenario_SUITE.erl | 110 +++++++++++++------------- 2 files changed, 108 insertions(+), 101 deletions(-) diff --git a/test/amoc_config_attributes_SUITE.erl b/test/amoc_config_attributes_SUITE.erl index 9becfd47..7ec03634 100644 --- a/test/amoc_config_attributes_SUITE.erl +++ b/test/amoc_config_attributes_SUITE.erl @@ -13,27 +13,32 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% these attributes and functions are required for the testing purposes %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --required_variable(#{name => var0, description => "var0"}). --required_variable(#{name => var1, description => "var1", default_value => def1}). +-required_variable(#{name => config_attrs_var0, + description => "config_attrs_var0"}). +-required_variable(#{name => config_attrs_var1, + description => "config_attrs_var1", + default_value => def1}). -required_variable([ - #{name => var2, description => "var2", default_value => def2, verification => none}, - #{name => var3, description => "var3", default_value => def3, - verification => [def3, another_atom]}, - #{name => var4, description => "var4", default_value => def4, - verification => {?MODULE, verify_value, 1}}, - #{name => var4b, description => "var4b", default_value => def4b, - verification => fun ?MODULE:verify_value/1} + #{name => config_attrs_var2, description => "config_attrs_var2", + default_value => def2, verification => none}, + #{name => config_attrs_var3, description => "config_attrs_var3", + default_value => def3, verification => [def3, another_atom]}, + #{name => config_attrs_var4, description => "config_attrs_var4", + default_value => def4, verification => {?MODULE, verify_value, 1}}, + #{name => config_attrs_var4b, description => "config_attrs_var4b", + default_value => def4b, verification => fun ?MODULE:verify_value/1} ]). --required_variable(#{name => var5, description => "var5", default_value => def5, - update => read_only}). --required_variable(#{name => var6, description => "var6", default_value => def6, - verification => none, update => none}). +-required_variable(#{name => config_attrs_var5, description => "config_attrs_var5", + default_value => def5, update => read_only}). +-required_variable(#{name => config_attrs_var6, description => "config_attrs_var6", + default_value => def6, verification => none, update => none}). -required_variable([ - #{name => var7, description => "var7", default_value => def7, - verification => none, update => {?MODULE, update_value, 2}} + #{name => config_attrs_var7, description => "config_attrs_var7", + default_value => def7, verification => none, update => {?MODULE, update_value, 2}} ]). --required_variable(#{name => var7b, description => "var7b", default_value => def7, - verification => none, update => fun ?MODULE:update_value/2}). +-required_variable(#{name => config_attrs_var7b, description => "config_attrs_var7b", + default_value => def7, verification => none, + update => fun ?MODULE:update_value/2}). %% verification functions -export([verify_value/1]). @@ -53,23 +58,23 @@ all() -> get_module_attributes(_) -> Result = amoc_config_attributes:get_module_attributes(required_variable, ?MODULE), ExpectedResult = [ - #{name => var0, description => "var0"}, - #{name => var1, description => "var1", default_value => def1}, - #{name => var2, description => "var2", default_value => def2, + #{name => config_attrs_var0, description => "config_attrs_var0"}, + #{name => config_attrs_var1, description => "config_attrs_var1", default_value => def1}, + #{name => config_attrs_var2, description => "config_attrs_var2", default_value => def2, verification => none}, - #{name => var3, description => "var3", default_value => def3, + #{name => config_attrs_var3, description => "config_attrs_var3", default_value => def3, verification => [def3, another_atom]}, - #{name => var4, description => "var4", default_value => def4, + #{name => config_attrs_var4, description => "config_attrs_var4", default_value => def4, verification => {?MODULE, verify_value, 1}}, - #{name => var4b, description => "var4b", default_value => def4b, + #{name => config_attrs_var4b, description => "config_attrs_var4b", default_value => def4b, verification => fun ?MODULE:verify_value/1}, - #{name => var5, description => "var5", default_value => def5, + #{name => config_attrs_var5, description => "config_attrs_var5", default_value => def5, update => read_only}, - #{name => var6, description => "var6", default_value => def6, + #{name => config_attrs_var6, description => "config_attrs_var6", default_value => def6, verification => none, update => none}, - #{name => var7, description => "var7", default_value => def7, + #{name => config_attrs_var7, description => "config_attrs_var7", default_value => def7, verification => none, update => {?MODULE, update_value, 2}}, - #{name => var7b, description => "var7b", default_value => def7, + #{name => config_attrs_var7b, description => "config_attrs_var7b", default_value => def7, verification => none, update => fun ?MODULE:update_value/2}], ?assertEqual(ExpectedResult, Result). @@ -81,47 +86,47 @@ get_module_configuration(_) -> UpdateNone = fun amoc_config_attributes:none/2, VerificationNone = fun amoc_config_attributes:none/1, ?assertMatch( - [#module_parameter{name = var0, mod = ?MODULE, value = undefined, + [#module_parameter{name = config_attrs_var0, mod = ?MODULE, value = undefined, verification_fn = VerificationNone, update_fn = read_only}, - #module_parameter{name = var1, mod = ?MODULE, value = def1, + #module_parameter{name = config_attrs_var1, mod = ?MODULE, value = def1, verification_fn = VerificationNone, update_fn = read_only}, - #module_parameter{name = var2, mod = ?MODULE, value = def2, + #module_parameter{name = config_attrs_var2, mod = ?MODULE, value = def2, verification_fn = VerificationNone, update_fn = read_only}, - #module_parameter{name = var3, mod = ?MODULE, value = def3, + #module_parameter{name = config_attrs_var3, mod = ?MODULE, value = def3, update_fn = read_only}, %% verification_fn is checked in %% 'one_of_function' test case. - #module_parameter{name = var4, mod = ?MODULE, value = def4, + #module_parameter{name = config_attrs_var4, mod = ?MODULE, value = def4, verification_fn = VerifyValueFN, update_fn = read_only}, - #module_parameter{name = var4b, mod = ?MODULE, value = def4b, + #module_parameter{name = config_attrs_var4b, mod = ?MODULE, value = def4b, verification_fn = VerifyValueFN, update_fn = read_only}, - #module_parameter{name = var5, mod = ?MODULE, value = def5, + #module_parameter{name = config_attrs_var5, mod = ?MODULE, value = def5, verification_fn = VerificationNone, update_fn = read_only}, - #module_parameter{name = var6, mod = ?MODULE, value = def6, + #module_parameter{name = config_attrs_var6, mod = ?MODULE, value = def6, verification_fn = VerificationNone, update_fn = UpdateNone}, - #module_parameter{name = var7, mod = ?MODULE, value = def7, + #module_parameter{name = config_attrs_var7, mod = ?MODULE, value = def7, verification_fn = VerificationNone, update_fn = UpdateValueFN}, - #module_parameter{name = var7b, mod = ?MODULE, value = def7, + #module_parameter{name = config_attrs_var7b, mod = ?MODULE, value = def7, verification_fn = VerificationNone, update_fn = UpdateValueFN}], Config). errors_reporting(_) -> - InvalidParam0 = #{name => "invalid_var0", description => "var0"}, + InvalidParam0 = #{name => "invalid_var0", description => "config_attrs_var0"}, InvalidParam1 = #{name => invalid_var1, description => [$a, -2]}, - InvalidParam2 = #{name => invalid_var2, description => "var2", + InvalidParam2 = #{name => invalid_var2, description => "config_attrs_var2", verification => <<"invalid_verification_method">>}, - ValidParam3 = #{name => valid_var3, description => "var3", default_value => def3, + ValidParam3 = #{name => valid_var3, description => "config_attrs_var3", default_value => def3, verification => [def3, another_atom]}, - InvalidParam4 = #{name => invalid_var4, description => "var4", + InvalidParam4 = #{name => invalid_var4, description => "config_attrs_var4", verification => {erlang, not_exported_function, 1}}, - InvalidParam4b = #{name => invalid_var4b, description => "var4b", + InvalidParam4b = #{name => invalid_var4b, description => "config_attrs_var4b", verification => fun erlang:not_exported_function/1}, - InvalidParam5 = #{name => invalid_var5, description => "var5", + InvalidParam5 = #{name => invalid_var5, description => "config_attrs_var5", update => invalid_update_method}, - InvalidParam6 = #{name => invalid_var6, description => "var6", + InvalidParam6 = #{name => invalid_var6, description => "config_attrs_var6", update => fun invalid_module:not_exported_function/2}, - InvalidParam7 = #{name => invalid_var7, description => "var7", + InvalidParam7 = #{name => invalid_var7, description => "config_attrs_var7", update => fun update_value/2}, %% local function - InvalidParam7b = #{name => invalid_var7, description => "var7b", + InvalidParam7b = #{name => invalid_var7, description => "config_attrs_var7b", update => fun update_value/2}, %% local function Attributes = [InvalidParam0, InvalidParam1, InvalidParam2, ValidParam3, InvalidParam4, InvalidParam4b, InvalidParam5, InvalidParam6, InvalidParam7, InvalidParam7b], @@ -141,7 +146,7 @@ errors_reporting(_) -> one_of_function(_) -> OneOf = [def3, another_atom], - Param = #{name => var0, description => "var0", default_value => def0, + Param = #{name => config_attrs_var0, description => "config_attrs_var0", default_value => def0, verification => OneOf}, {ok, [#module_parameter{verification_fn = OneOfFN}]} = amoc_config_attributes:process_module_attributes(?MODULE, [Param]), diff --git a/test/amoc_config_scenario_SUITE.erl b/test/amoc_config_scenario_SUITE.erl index 850a6a26..6ab04ba3 100644 --- a/test/amoc_config_scenario_SUITE.erl +++ b/test/amoc_config_scenario_SUITE.erl @@ -21,24 +21,26 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% declaring required variables %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --required_variable(#{name => var0, description => "var0"}). -%% without overriding, verification of var1 should fail. --required_variable(#{name => var1, description => "var1", +-required_variable(#{name => config_scenario_var0, description => "config_scenario_var0"}). +%% without overriding, verification of config_scenario_var1 should fail. +-required_variable(#{name => config_scenario_var1, description => "config_scenario_var1", verification => [unused_value]}). --required_variable(#{name => var2, description => "var2", default_value => def2}). +-required_variable(#{name => config_scenario_var2, description => "config_scenario_var2", + default_value => def2}). %%%%%%%%%%%%%%%%%%%%%%%%%% %% overriding variables %% %%%%%%%%%%%%%%%%%%%%%%%%%% --override_variable([#{name => var1, description => "var1", default_value => val1, - verification => fun ?MOCK_MOD:verify_fun/1}, - #{name => var2, description => "var2", default_value => val2, - verification => [new_val2, val2], +-override_variable([#{name => config_scenario_var1, description => "config_scenario_var1", + default_value => val1, verification => fun ?MOCK_MOD:verify_fun/1}, + #{name => config_scenario_var2, description => "config_scenario_var2", + default_value => val2, verification => [new_val2, val2], update => {?MOCK_MOD, update_mfa, 2}}]). -%% var3 is not declared with -required_variable(...), but it's fine. --override_variable(#{name => var3, description => "var3", default_value => def3}). --override_variable(#{name => var3, description => "var3", default_value => val3, - update => fun ?MOCK_MOD:update_fun/2, +%% config_scenario_var3 is not declared with -required_variable(...), but it's fine. +-override_variable(#{name => config_scenario_var3, description => "config_scenario_var3", + default_value => def3}). +-override_variable(#{name => config_scenario_var3, description => "config_scenario_var3", + default_value => val3, update => fun ?MOCK_MOD:update_fun/2, verification => {?MOCK_MOD, verify_mfa, 1}}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -93,7 +95,7 @@ parse_scenario_settings(_) -> mock_ets_tables(), ets:insert(configurable_modules, {amoc_controller, configurable}), ScenarioSettings = [{interarrival, 500}, - {var1, def1}], + {config_scenario_var1, def1}], Ret = amoc_config_scenario:parse_scenario_settings(?MODULE, ScenarioSettings), ?assertEqual(ok, Ret), %% check verification function calls @@ -104,13 +106,13 @@ parse_scenario_settings(_) -> %% undefined variable ?assertThrow({invalid_setting, undefined_var}, amoc_config:get(undefined_var)), %% undefined value - ?assertEqual(undefined, amoc_config:get(var0)), - ?assertEqual(some_value, amoc_config:get(var0, some_value)), + ?assertEqual(undefined, amoc_config:get(config_scenario_var0)), + ?assertEqual(some_value, amoc_config:get(config_scenario_var0, some_value)), %% defined (in settings) value - ?assertEqual(def1, amoc_config:get(var1)), - ?assertEqual(def1, amoc_config:get(var1, some_value)), + ?assertEqual(def1, amoc_config:get(config_scenario_var1)), + ?assertEqual(def1, amoc_config:get(config_scenario_var1, some_value)), %% overwritten variable - ?assertEqual(val2, amoc_config:get(var2)), + ?assertEqual(val2, amoc_config:get(config_scenario_var2)), %% configurable module variable (defined in amoc_controller) ?assertEqual(500, amoc_config:get(interarrival)). @@ -119,21 +121,21 @@ update_settings(_) -> %% update 2 parameters and check all values and %% verification/update function calls - ScenarioSettings = [{var3, new_val3}, - {var2, new_val2}], + ScenarioSettings = [{config_scenario_var3, new_val3}, + {config_scenario_var2, new_val2}], Ret = amoc_config_scenario:update_settings(ScenarioSettings), ?assertEqual(ok, Ret), %% updated variables - ?assertEqual(new_val2, amoc_config:get(var2)), - ?assertEqual(new_val3, amoc_config:get(var3)), + ?assertEqual(new_val2, amoc_config:get(config_scenario_var2)), + ?assertEqual(new_val3, amoc_config:get(config_scenario_var3)), %% unchanged variables - ?assertEqual(undefined, amoc_config:get(var0)), - ?assertEqual(val1, amoc_config:get(var1)), + ?assertEqual(undefined, amoc_config:get(config_scenario_var0)), + ?assertEqual(val1, amoc_config:get(config_scenario_var1)), %% execution of update functions is done asynchronously %% and execution of verification functions is synchronous meck:wait(?MOCK_MOD, verify_mfa, [new_val3], ?VERIFY_TIMEOUT), - meck:wait(?MOCK_MOD, update_fun, [var3, new_val3], ?UPDATE_TIMEOUT), - meck:wait(?MOCK_MOD, update_mfa, [var2, new_val2], ?UPDATE_TIMEOUT), + meck:wait(?MOCK_MOD, update_fun, [config_scenario_var3, new_val3], ?UPDATE_TIMEOUT), + meck:wait(?MOCK_MOD, update_mfa, [config_scenario_var2, new_val2], ?UPDATE_TIMEOUT), ?assertEqual(3, length(meck:history(?MOCK_MOD))). update_just_one_parameter(_) -> @@ -141,25 +143,25 @@ update_just_one_parameter(_) -> %% update only 1 parameter and check that update %% function is call for that parameter - ?assertEqual(ok, amoc_config_scenario:update_settings([{var2, new_val2}])), + ?assertEqual(ok, amoc_config_scenario:update_settings([{config_scenario_var2, new_val2}])), %% updated variables - ?assertEqual(new_val2, amoc_config:get(var2)), + ?assertEqual(new_val2, amoc_config:get(config_scenario_var2)), %% execution of update functions is done asynchronously %% and execution of verification functions is synchronous - meck:wait(?MOCK_MOD, update_mfa, [var2, new_val2], ?UPDATE_TIMEOUT), + meck:wait(?MOCK_MOD, update_mfa, [config_scenario_var2, new_val2], ?UPDATE_TIMEOUT), ?assertError(timeout, meck:wait(?MOCK_MOD, verify_fun, 2, ?VERIFY_TIMEOUT)), ?assertEqual(1, length(meck:history(?MOCK_MOD))), meck:reset(?MOCK_MOD), %% update another parameter and check that update %% function is call for it - ?assertEqual(ok, amoc_config_scenario:update_settings([{var3, new_val3}])), + ?assertEqual(ok, amoc_config_scenario:update_settings([{config_scenario_var3, new_val3}])), %% updated variables - ?assertEqual(new_val3, amoc_config:get(var3)), + ?assertEqual(new_val3, amoc_config:get(config_scenario_var3)), %% execution of update functions is done asynchronously %% and execution of verification functions is synchronous meck:wait(?MOCK_MOD, verify_mfa, [new_val3], ?VERIFY_TIMEOUT), - meck:wait(?MOCK_MOD, update_fun, [var3, new_val3], ?UPDATE_TIMEOUT), + meck:wait(?MOCK_MOD, update_fun, [config_scenario_var3, new_val3], ?UPDATE_TIMEOUT), ?assertEqual(2, length(meck:history(?MOCK_MOD))), meck:reset(?MOCK_MOD), @@ -173,12 +175,12 @@ update_parameters_with_the_same_values(_) -> %% update 2 parameters with inital values, check that values are unchanged %% and no verification/update functions called - ScenarioSettings = [{var3, val3}, - {var2, val2}], + ScenarioSettings = [{config_scenario_var3, val3}, + {config_scenario_var2, val2}], ?assertEqual(ok, amoc_config_scenario:update_settings(ScenarioSettings)), %% updated variables - ?assertEqual(val2, amoc_config:get(var2)), - ?assertEqual(val3, amoc_config:get(var3)), + ?assertEqual(val2, amoc_config:get(config_scenario_var2)), + ?assertEqual(val3, amoc_config:get(config_scenario_var3)), assert_no_update_calls(), assert_no_verify_calls(), @@ -186,28 +188,28 @@ update_parameters_with_the_same_values(_) -> %% update 2 parameters but only one with the new value, check the value is %% changed and no verification/update functions are called only for that %% parameter - ScenarioSettings2 = [{var3, new_val3}, - {var2, val2}], + ScenarioSettings2 = [{config_scenario_var3, new_val3}, + {config_scenario_var2, val2}], ?assertEqual(ok, amoc_config_scenario:update_settings(ScenarioSettings2)), %% updated variables - ?assertEqual(val2, amoc_config:get(var2)), - ?assertEqual(new_val3, amoc_config:get(var3)), + ?assertEqual(val2, amoc_config:get(config_scenario_var2)), + ?assertEqual(new_val3, amoc_config:get(config_scenario_var3)), meck:wait(?MOCK_MOD, verify_mfa, [new_val3], ?VERIFY_TIMEOUT), - meck:wait(?MOCK_MOD, update_fun, [var3, new_val3], ?UPDATE_TIMEOUT), + meck:wait(?MOCK_MOD, update_fun, [config_scenario_var3, new_val3], ?UPDATE_TIMEOUT), ?assertEqual(2, length(meck:history(?MOCK_MOD))). update_settings_readonly(_) -> set_initial_configuration(), Table = ets:tab2list(amoc_config), %% updating readonly parameters - ScenarioSettings = [{var0, val0}, - {var1, val1}, %% the same value as set initially - {var3, val3}], + ScenarioSettings = [{config_scenario_var0, val0}, + {config_scenario_var1, val1}, %% the same value as set initially + {config_scenario_var3, val3}], ReadOnlyRet = amoc_config_scenario:update_settings(ScenarioSettings), ?assertEqual({error, readonly_parameters, - [{var0, ?MODULE}, - {var1, ?MODULE}]}, + [{config_scenario_var0, ?MODULE}, + {config_scenario_var1, ?MODULE}]}, ReadOnlyRet), is_equal_list(Table, ets:tab2list(amoc_config)), assert_no_update_calls(), @@ -217,11 +219,11 @@ update_settings_invalid_value(_) -> set_initial_configuration(), Table = ets:tab2list(amoc_config), %% invalid value - ScenarioSettings2 = [{var3, new_val3}, - {var2, invalid_val2}], + ScenarioSettings2 = [{config_scenario_var3, new_val3}, + {config_scenario_var2, invalid_val2}], InvalidValueRet = amoc_config_scenario:update_settings(ScenarioSettings2), ?assertEqual({error, parameters_verification_failed, - [{var2, invalid_val2, + [{config_scenario_var2, invalid_val2, {verification_failed, {not_one_of, [new_val2, val2]}}}]}, InvalidValueRet), is_equal_list(Table, ets:tab2list(amoc_config)), @@ -233,7 +235,7 @@ update_settings_undef_param(_) -> %% reset initial verification calls. meck:reset(?MOCK_MOD), %% adding undefined parameter in settings - ScenarioSettings3 = [{var3, new_val3}, + ScenarioSettings3 = [{config_scenario_var3, new_val3}, {invalid_var2, val2}], UndefParamRet = amoc_config_scenario:update_settings(ScenarioSettings3), ?assertEqual({error, undefined_parameters, [invalid_var2]}, UndefParamRet), @@ -246,14 +248,14 @@ implicit_variable_redefinition(_) -> mock_ets_tables(), ets:insert(configurable_modules, {?MODULE, configurable}), Ret = amoc_config_scenario:parse_scenario_settings(?MODULE, []), - ?assertEqual({error, parameter_overriding, {var0, ?MODULE, ?MODULE}}, Ret), + ?assertEqual({error, parameter_overriding, {config_scenario_var0, ?MODULE, ?MODULE}}, Ret), assert_no_update_calls(), assert_no_verify_calls(). invalid_settings(_) -> mock_ets_tables(), ScenarioSettings = [{invalid_var1, invalid_value}, - {var2, new_val2}, + {config_scenario_var2, new_val2}, {invalid_var2, invalid_value}], Ret = amoc_config_scenario:parse_scenario_settings(?MODULE, ScenarioSettings), ?assertEqual({error, undefined_parameters, [invalid_var2, invalid_var1]}, Ret), @@ -262,10 +264,10 @@ invalid_settings(_) -> invalid_value(_) -> mock_ets_tables(), - ScenarioSettings = [{var2, invalid_value}], + ScenarioSettings = [{config_scenario_var2, invalid_value}], Ret = amoc_config_scenario:parse_scenario_settings(?MODULE, ScenarioSettings), ?assertEqual({error, parameters_verification_failed, - [{var2, invalid_value, + [{config_scenario_var2, invalid_value, {verification_failed, {not_one_of, [new_val2, val2]}}}]}, Ret), %% check verification function calls, verification From 5942a2349b1266290af72ae1291382452a8f5435 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Wed, 6 Dec 2023 12:07:33 +0100 Subject: [PATCH 2/3] Add tests for amoc_controller --- test/async_helper.erl | 39 ++++++ test/controller_SUITE.erl | 181 +++++++++++++++++++++++++++ test/testing_scenario.erl | 27 ++++ test/testing_scenario_with_state.erl | 30 +++++ 4 files changed, 277 insertions(+) create mode 100644 test/async_helper.erl create mode 100644 test/controller_SUITE.erl create mode 100644 test/testing_scenario.erl create mode 100644 test/testing_scenario_with_state.erl diff --git a/test/async_helper.erl b/test/async_helper.erl new file mode 100644 index 00000000..b913ac10 --- /dev/null +++ b/test/async_helper.erl @@ -0,0 +1,39 @@ +-module(async_helper). + +-export([wait_until/2, wait_until/3]). + +% @doc Waits `TimeLeft` for `Fun` to return `Expected Value`, then returns `ExpectedValue` +% If no value is returned or the result doesn't match `ExpectedValue` error is raised +wait_until(Fun, ExpectedValue) -> + wait_until(Fun, ExpectedValue, #{}). + +%% Example: wait_until(fun () -> ... end, SomeVal, #{time_left => timer:seconds(2)}) +%% if expected value is a function with arity 1, it's treated as a validation function. +wait_until(Fun, ValidatorFn, Opts0) when is_function(ValidatorFn, 1) -> + Defaults = #{time_left => timer:seconds(5), sleep_time => 50}, + Opts1 = maps:merge(Defaults, Opts0), + Opts = Opts1#{validator => ValidatorFn, history => []}, + do_wait_until(Fun, Opts); +wait_until(Fun, ExpectedValue, Opts) -> + ValidatorFn = fun(Value) -> Value =:= ExpectedValue end, + wait_until(Fun, ValidatorFn, Opts). + +do_wait_until(_Fun, #{time_left := TimeLeft, history := History}) when TimeLeft =< 0 -> + error({badmatch, lists:reverse(History)}); + +do_wait_until(Fun, #{validator := Validator} = Opts) -> + try Fun() of + Value -> case Validator(Value) of + true -> {ok, Value}; + _ -> wait_and_continue(Fun, Value, Opts) + end + catch Error:Reason:Stacktrace -> + wait_and_continue(Fun, {Error, Reason, Stacktrace}, Opts) + end. + +wait_and_continue(Fun, FunResult, #{time_left := TimeLeft, + sleep_time := SleepTime, + history := History} = Opts) -> + timer:sleep(SleepTime), + do_wait_until(Fun, Opts#{time_left => TimeLeft - SleepTime, + history => [FunResult | History]}). diff --git a/test/controller_SUITE.erl b/test/controller_SUITE.erl new file mode 100644 index 00000000..0f1b31e0 --- /dev/null +++ b/test/controller_SUITE.erl @@ -0,0 +1,181 @@ +-module(controller_SUITE). +-compile([export_all, nowarn_export_all]). + +-include_lib("stdlib/include/assert.hrl"). + +all() -> + [ + {group, all_tests} + ]. + +groups() -> + [ + {all_tests, [], all_tests()} + ]. + +all_tests() -> + [ + no_scenario_running_status_is_idle, + disable_controller_returns_status_disable, + disable_controller_then_cant_start_scenario, + start_non_existing_scenario_fails, + start_scenario_without_vars_fails, + start_scenario_runs_fine, + start_scenario_check_status, + add_users_to_started_scenario, + add_bad_range_of_users_to_started_scenario_fails, + add_users_scenario_not_started_fails, + remove_users_scenario_not_started_fails, + check_status_with_running_users_is_correct, + check_status_after_killing_one_user_is_correct, + stop_non_running_scenario_fails, + stop_running_scenario_with_no_users_immediately_terminates, + stop_running_scenario_with_users_stays_in_finished, + stop_running_scenario_with_users_eventually_terminates, + scenario_with_state_and_crashing_in_terminate_run_fine + ]. + + +%% setup and teardown +init_per_suite(Config) -> + Config. + +end_per_suite(Config) -> + Config. + +init_per_testcase(_TestCase, Config) -> + application:ensure_all_started(amoc), + Config. + +end_per_testcase(_TestCase, Config) -> + application:stop(amoc), + Config. + +%% test cases +no_scenario_running_status_is_idle(_) -> + Status = amoc_controller:get_status(), + ?assertMatch(idle, Status). + +disable_controller_returns_status_disable(_) -> + amoc_controller:disable(), + Status = amoc_controller:get_status(), + ?assertMatch(disabled, Status). + +disable_controller_then_cant_start_scenario(_) -> + amoc_controller:disable(), + Ret = do_start_scenario(testing_scenario), + ?assertMatch({error, {invalid_status, disabled}}, Ret). + +start_non_existing_scenario_fails(_) -> + Scenario = 'non_existing_come_on_dont_do_this_#(*&$%*(@_))', + Ret = do_start_scenario(Scenario), + ?assertMatch({error, {no_such_scenario, Scenario}}, Ret). + +start_scenario_without_vars_fails(_) -> + Ret = do_start_scenario(testing_scenario), + ?assertMatch({error, {parameters_verification_failed, [{testing_var1, _, _}]}}, Ret). + +start_scenario_runs_fine(_) -> + Ret = do_start_scenario(testing_scenario, regular_vars()), + ?assertMatch(ok, Ret). + +start_scenario_check_status(_) -> + do_start_scenario(testing_scenario, regular_vars()), + Status = amoc_controller:get_status(), + ?assertMatch({running, testing_scenario, 0, 0}, Status). + +add_users_to_started_scenario(_) -> + do_start_scenario(testing_scenario, regular_vars()), + Ret = amoc_controller:add_users(1, 10), + ?assertMatch(ok, Ret). + +add_bad_range_of_users_to_started_scenario_fails(_) -> + do_start_scenario(testing_scenario, regular_vars()), + Ret = amoc_controller:add_users(10, 1), + ?assertMatch({error, invalid_range}, Ret). + +add_users_scenario_not_started_fails(_) -> + Ret = amoc_controller:add_users(1, 10), + ?assertMatch({error, {invalid_status, idle}}, Ret). + +remove_users_scenario_not_started_fails(_) -> + Ret = amoc_controller:add_users(1, 10), + ?assertMatch({error, {invalid_status, idle}}, Ret). + +check_status_with_running_users_is_correct(_) -> + do_start_scenario(testing_scenario, regular_vars()), + amoc_controller:add_users(1, 10), + Status = amoc_controller:get_status(), + ?assertMatch({running, testing_scenario, _, 10}, Status). + +check_status_after_killing_one_user_is_correct(_) -> + do_start_scenario(testing_scenario, regular_vars()), + NumOfUsers = 10, + amoc_controller:add_users(1, NumOfUsers), + wait_until_scenario_has_users(testing_scenario, NumOfUsers, NumOfUsers), + Ret = amoc_controller:remove_users(1, true), + ?assertMatch({ok, 1}, Ret), + wait_until_scenario_has_users(testing_scenario, NumOfUsers - 1, NumOfUsers). + +stop_non_running_scenario_fails(_) -> + Ret = amoc_controller:stop_scenario(), + ?assertMatch({error, {invalid_status, idle}}, Ret). + +stop_running_scenario_with_no_users_immediately_terminates(_) -> + do_start_scenario(testing_scenario, regular_vars()), + Ret = amoc_controller:stop_scenario(), + ?assertMatch(ok, Ret), + Status = amoc_controller:get_status(), + ?assertMatch({finished, testing_scenario}, Status). + +stop_running_scenario_with_users_stays_in_finished(_) -> + do_start_scenario(testing_scenario, regular_vars()), + NumOfUsers = 10, + amoc_controller:add_users(1, NumOfUsers), + wait_until_scenario_has_users(testing_scenario, NumOfUsers, NumOfUsers), + Ret = amoc_controller:stop_scenario(), + Status = amoc_controller:get_status(), + ?assertMatch(ok, Ret), + ?assertMatch({terminating, testing_scenario}, Status). + +stop_running_scenario_with_users_eventually_terminates(_) -> + do_start_scenario(testing_scenario, regular_vars()), + NumOfUsers = 10, + amoc_controller:add_users(1, NumOfUsers), + wait_until_scenario_has_users(testing_scenario, NumOfUsers, NumOfUsers), + amoc_controller:stop_scenario(), + WaitUntilFun = fun amoc_controller:get_status/0, + WaitUntilValue = {finished, testing_scenario}, + async_helper:wait_until(WaitUntilFun, WaitUntilValue). + +scenario_with_state_and_crashing_in_terminate_run_fine(_) -> + do_start_scenario(testing_scenario_with_state, regular_vars_with_state()), + NumOfUsers = 10, + amoc_controller:add_users(1, NumOfUsers), + wait_until_scenario_has_users(testing_scenario_with_state, NumOfUsers, NumOfUsers), + amoc_controller:stop_scenario(), + WaitUntilFun = fun amoc_controller:get_status/0, + WaitUntilValue = {finished, testing_scenario_with_state}, + async_helper:wait_until(WaitUntilFun, WaitUntilValue). + +%% helpers +do_start_scenario(Scenario) -> + do_start_scenario(Scenario, []). + +do_start_scenario(Scenario, Config) -> + Vars = other_vars_to_keep_quiet() ++ Config, + amoc_controller:start_scenario(Scenario, Vars). + +regular_vars() -> + [{interarrival, 1}, {testing_var1, def1}]. + +regular_vars_with_state() -> + [{interarrival, 1}, {testing_state_var1, def1}]. + +other_vars_to_keep_quiet() -> + [{config_scenario_var1, unused_value}]. + +wait_until_scenario_has_users(Scenario, Current, Total) -> + WaitUntilFun = fun amoc_controller:get_status/0, + WaitUntilValue = {running, Scenario, Current, Total}, + async_helper:wait_until(WaitUntilFun, WaitUntilValue). diff --git a/test/testing_scenario.erl b/test/testing_scenario.erl new file mode 100644 index 00000000..5051790a --- /dev/null +++ b/test/testing_scenario.erl @@ -0,0 +1,27 @@ +-module(testing_scenario). + +-behaviour(amoc_scenario). + +-required_variable(#{name => testing_var1, description => "description1", + verification => [def1, another_value]}). + +%% amoc_scenario behaviour +-export([init/0, start/1, terminate/0]). + +-spec init() -> ok. +init() -> + ok. + +-spec start(amoc_scenario:user_id()) -> any(). +start(_Id) -> + %% Wait for any message to be send + receive + Msg -> + ct:pal("Msg ~p~n", [Msg]), + timer:sleep(100), + Msg + end. + +-spec terminate() -> term(). +terminate() -> + ok. diff --git a/test/testing_scenario_with_state.erl b/test/testing_scenario_with_state.erl new file mode 100644 index 00000000..b268f31d --- /dev/null +++ b/test/testing_scenario_with_state.erl @@ -0,0 +1,30 @@ +-module(testing_scenario_with_state). + +-behaviour(amoc_scenario). + +-required_variable(#{name => testing_state_var1, description => "description1", + verification => [def1, another_value]}). + +%% amoc_scenario behaviour +-export([init/0, start/2, terminate/1]). + +-type state() :: #{_ := _}. +-export_type([state/0]). + +-spec init() -> {ok, state()}. +init() -> + {ok, #{some_state => this_has_state}}. + +-spec start(amoc_scenario:user_id(), state()) -> any(). +start(_Id, #{some_state := this_has_state}) -> + %% Wait for anymessage to be send + receive + Msg -> + ct:pal("Msg ~p~n", [Msg]), + timer:sleep(100), + Msg + end. + +-spec terminate(state()) -> any(). +terminate(#{some_state := GiveState}) -> + throw(GiveState). From 07a87f0fde905aa5b0fd344d7a90e99215fb3e56 Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Sun, 17 Dec 2023 14:21:34 +0100 Subject: [PATCH 3/3] Test with a start_id not necessarily 1 --- test/controller_SUITE.erl | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/controller_SUITE.erl b/test/controller_SUITE.erl index 0f1b31e0..b94e76ec 100644 --- a/test/controller_SUITE.erl +++ b/test/controller_SUITE.erl @@ -104,9 +104,10 @@ remove_users_scenario_not_started_fails(_) -> check_status_with_running_users_is_correct(_) -> do_start_scenario(testing_scenario, regular_vars()), - amoc_controller:add_users(1, 10), - Status = amoc_controller:get_status(), - ?assertMatch({running, testing_scenario, _, 10}, Status). + StartId = 6, + EndId = 10, + amoc_controller:add_users(6, 10), + wait_until_scenario_has_users(testing_scenario, EndId - StartId + 1, EndId). check_status_after_killing_one_user_is_correct(_) -> do_start_scenario(testing_scenario, regular_vars()), @@ -175,7 +176,7 @@ regular_vars_with_state() -> other_vars_to_keep_quiet() -> [{config_scenario_var1, unused_value}]. -wait_until_scenario_has_users(Scenario, Current, Total) -> +wait_until_scenario_has_users(Scenario, Current, HighestId) -> WaitUntilFun = fun amoc_controller:get_status/0, - WaitUntilValue = {running, Scenario, Current, Total}, + WaitUntilValue = {running, Scenario, Current, HighestId}, async_helper:wait_until(WaitUntilFun, WaitUntilValue).