aboutsummaryrefslogblamecommitdiffstats
path: root/lib/cosTransactions/test/transactions_SUITE.erl
blob: 8385d5a0fb52c37beb21ceaf22623ba0c8c2ca1d (plain) (tree)










































































































































































































































































































































































































                                                                                                                                                                            
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1999-2009. 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%
%%
%%
-module(transactions_SUITE).

%%--------------- INCLUDES -----------------------------------
-include_lib("orber/include/corba.hrl").
-include_lib("orber/include/ifr_types.hrl").

%% Local
-include_lib("cosTransactions/src/ETraP_Common.hrl").
-include_lib("cosTransactions/include/CosTransactions.hrl").
-include("etrap_test_lib.hrl").
 
-include("test_server.hrl").

-define(default_timeout, ?t:minutes(20)).


%%-----------------------------------------------------------------
%% External exports
%%-----------------------------------------------------------------
-export([all/1, cases/0, init_all/1, finish_all/1, resource_api/1, etrap_api/1,
	init_per_testcase/2, fin_per_testcase/2, app_test/1]).
 
%%-----------------------------------------------------------------
%% Func: all/1
%% Args: 
%% Returns: 
%%-----------------------------------------------------------------
all(doc) -> ["API tests for the cosTransactions interfaces", ""];
all(suite) -> {req,
               [mnesia, orber],
               {conf, init_all, cases(), finish_all}}.
 
cases() ->
    [etrap_api, resource_api, app_test].


	
%%-----------------------------------------------------------------
%% Init and cleanup functions.
%%-----------------------------------------------------------------

init_per_testcase(_Case, Config) ->
    Path = code:which(?MODULE),
    code:add_pathz(filename:join(filename:dirname(Path), "idl_output")),
    'oe_CosTransactions':'oe_register'(), 
    'oe_etrap_test':'oe_register'(), 
    ?line Dog=test_server:timetrap(?default_timeout),
    [{watchdog, Dog}|Config].


fin_per_testcase(_Case, Config) ->
    'oe_etrap_test':'oe_unregister'(), 
    'oe_CosTransactions':'oe_unregister'(), 
    Path = code:which(?MODULE),
    code:del_path(filename:join(filename:dirname(Path), "idl_output")),
    Dog = ?config(watchdog, Config),
    test_server:timetrap_cancel(Dog),
    ok.

init_all(Config) ->
    mnesia:delete_schema([node()]),
    mnesia:create_schema([node()]),
    orber:install([node()]),
    application:start(mnesia),
    application:start(orber),
    if
        is_list(Config) ->
	    Config;
        true ->
            exit("Config not a list")
    end.
 
finish_all(Config) ->
    application:stop(orber),
    application:stop(mnesia),
    mnesia:delete_schema([node()]),
    Config.
 
%%-----------------------------------------------------------------
%%  Tests app file
%%-----------------------------------------------------------------
app_test(doc) -> [];
app_test(suite) -> [];
app_test(_Config) ->
    ok=test_server:app_test(cosTransactions),
    ok.

%%-----------------------------------------------------------------
%%  API tests 
%%-----------------------------------------------------------------
etrap_api(doc) -> ["ETraP_Server tests", ""];
etrap_api(suite) -> [];
etrap_api(_Config) ->
    ?line ?match(ok, application:start(cosTransactions),
		 "Starting the cosTransactions application"),
    ?line TrFac = cosTransactions:start_factory(),
    %% Start a new transaction:
    %%      RootCoord
    %%      /       \
    %% SubCoord1  SubCoord2
    Control = 'CosTransactions_TransactionFactory':create(TrFac, 0),
    Term = 'CosTransactions_Control':get_terminator(Control),
    Coord = 'CosTransactions_Control':get_coordinator(Control),
    SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
    SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
    SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1),
    SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2),


    %%------ Test CosTransactions::Coordinator ------
    ?line ?match(true, 
		 'CosTransactions_Coordinator':is_same_transaction(Coord, Coord),
		 "'CosTransactions_Coordinator':is_same_transaction"),
    ?line ?match(false, 
		 'CosTransactions_Coordinator':is_same_transaction(Coord, SubCoord1),
		 "'CosTransactions_Coordinator':is_same_transaction"),
    ?line ?match(true, 
		 'CosTransactions_Coordinator':is_descendant_transaction(Coord, Coord),
		 "'CosTransactions_Coordinator':is_descendant_transaction"),
    ?line ?match(false, 
		 'CosTransactions_Coordinator':is_descendant_transaction(Coord, SubCoord1),
		 "'CosTransactions_Coordinator':is_descendant_transaction"),
    ?line ?match(true, 
		 'CosTransactions_Coordinator':is_descendant_transaction(SubCoord1, Coord),
		 "'CosTransactions_Coordinator':is_descendant_transaction"),
    ?line ?match(false, 
		 'CosTransactions_Coordinator':is_descendant_transaction(SubCoord1, SubCoord2),
		 "'CosTransactions_Coordinator':is_descendant_transaction"),
    ?line ?match(true, 
		 'CosTransactions_Coordinator':is_top_level_transaction(Coord),
		 "'CosTransactions_Coordinator':is_top_level_transaction"),
    ?line ?match(false, 
		 'CosTransactions_Coordinator':is_top_level_transaction(SubCoord2),
		 "'CosTransactions_Coordinator':is_top_level_transaction"),

    RootHash  = 'CosTransactions_Coordinator':hash_transaction(Coord),
    RepeatHash= 'CosTransactions_Coordinator':hash_transaction(Coord),
    RootHash2 = 'CosTransactions_Coordinator':hash_top_level_tran(SubCoord1),
    RootHash3 = 'CosTransactions_Coordinator':hash_top_level_tran(Coord),
    _SubHash   = 'CosTransactions_Coordinator':hash_transaction(SubCoord2),
    ?line ?match(RootHash, RepeatHash,
		 "'CosTransactions_Coordinator':hash_transaction"),
    ?line ?match(RootHash, RootHash2,
		 "'CosTransactions_Coordinator':hash_top_level_tran"),
    ?line ?match(RootHash, RootHash3,
		 "'CosTransactions_Coordinator':hash_top_level_tran"),
%    ?line ?match_inverse(RootHash, SubHash,
%		 "'CosTransactions_Coordinator':hash_transaction"),

    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_status(Coord),
		 "'CosTransactions_Coordinator':get_status"),
    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_status(SubCoord1),
		 "'CosTransactions_Coordinator':get_status"),
    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_parent_status(Coord),
		 "'CosTransactions_Coordinator':get_parent_status"),
    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_parent_status(SubCoord1),
		 "'CosTransactions_Coordinator':get_parent_status"),
    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_top_level_status(Coord),
		 "'CosTransactions_Coordinator':get_top_level_status"),
    ?line ?match('StatusActive', 
		 'CosTransactions_Coordinator':get_top_level_status(SubCoord1),
		 "'CosTransactions_Coordinator':get_top_level_status"),

    %% Create a CosTransactions::Resource to experiments with.
    %% Start a new transaction:
    %%      RootCoord
    %%      /       \
    %% SubCoord1  SubCoord2
    %%    /
    %% Resource
    N1 = 'ETraP_Common':create_name("test"),
    O1 = etrap_test_server:oe_create(?nop, {global, N1}),
    _RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
%    'CosTransactions_Coordinator':register_synchronization(SubCoord1, O1),

    ?line ?match('VoteCommit',
		 'CosTransactions_Resource':prepare(SubCoord1),
		 "'CosTransactions_Coordinator':prepare"),
    %% The Transaction are no longer in 'StatusActive' state. No new
    %% "members" allowed.
    ?line ?match('StatusPrepared',
		 'CosTransactions_Coordinator':get_status(SubCoord1),
		 "'CosTransactions_Coordinator':get_status"),
%    ?line ?match({'EXCEPTION', ?tr_inactive},
%		 'CosTransactions_Coordinator':register_synchronization(SubCoord1, O1),
%		 "'CosTransactions_Coordinator':register_synchronization"),
    ?line ?match({'EXCEPTION', ?tr_inactive},
		 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
		 "'CosTransactions_Coordinator':register_resource"),
    ?line ?match({'EXCEPTION', ?tr_inactive},
		 'CosTransactions_Coordinator':create_subtransaction(SubCoord1),
		 "'CosTransactions_Coordinator':create_subtransaction"),

    catch corba:dispose(SubCoord1),
    catch corba:dispose(SubCoord2),
    catch corba:dispose(SubCont1),
    catch corba:dispose(SubCont2),
    catch corba:dispose(Term),
    catch corba:dispose(Control),
    catch corba:dispose(Coord),
    catch corba:dispose(O1),

    ?line cosTransactions:stop_factory(TrFac),
    ?line application:stop(cosTransactions),
    ok.

%%-----------------------------------------------------------------
%%  API tests 
%%-----------------------------------------------------------------
resource_api(doc) -> ["cosTransactions API tests", ""];
resource_api(suite) -> [];
resource_api(_Config) ->
    ?line ?match(ok, application:start(cosTransactions),
		 "Starting the cosTransactions application"),
    ?line TrFac = cosTransactions:start_factory([{typecheck, true}]),

    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
		 run(TrFac, 0, {?nop, ?nop, ?nop, ?prepare_rollback}),
		 "TESTCASE #1: Prepare rollback Resource 4"),
    ?line ?match({'EXCEPTION', ?tr_mixed},
		 run(TrFac, 0, {?nop, ?nop, ?commit_mix, ?nop}),
		 "TESTCASE #2: Heuristic Mixed exception Resource 3"),
    ?line ?match(ok, 
		 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop}),
		 "TESTCASE #3: Normal completion. No errors."),
    ?line ?match(ok,
		 run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_cm}),
		 "TESTCASE #4: Heuristic Commit Exception Resource 4"),
    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
		 run(TrFac, 0, {?nop, ?rollback_rb, ?nop, ?prepare_rollback}),
		 "TESTCASE #5: Heuristic Rollbac Resource 2, Resource 4 reply 'VoteRollback'"),
    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
		 run(TrFac, 0, {?nop, ?nop, ?prepare_rollback, ?rollback_rb}),
		 "TESTCASE #6: Heuristic Rollbac Resource 4, Resource 3 reply 'VoteRollback'"),
    ?line ?match(ok,
		 run(TrFac, 0, {?nop, ?nop, ?commit_delay, ?nop}),
		 "TESTCASE #7: Resource 3 delay during commit. No timeout."),
    ?line ?match(ok,
		 run(TrFac, 0, {?nop, ?nop, ?prepare_delay, ?nop}),
		 "TESTCASE #8: Resource 3 delay during prepare. No timeout."),
    ?line ?match(ok,
		 run(TrFac, ?TIMEOUT, {?nop, ?commit_delay, ?nop, ?nop}),
		 "TESTCASE #9: Resource 3 delay during commit. Timeout."),
    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
		 run(TrFac, ?TIMEOUT, {?nop, ?prepare_delay, ?nop, ?nop}),
		 "TESTCASE #10: Resource 3 delay during prepare. Timeout."),
    case ?is_debug_compiled of
	true ->
	    %% Testing the Coordinators (root and sub).
	    ?line ?match(ok,
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_transient(commit), ?nop]}),
			 "TESTCASE #11: SubCoord 3 crash transient during commit."),
	    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_transient(send_prepare), ?nop]}),
			 "TESTCASE #12: SubCoord 3 crash transient during send prepare."),
	    ?line ?match({'EXCEPTION', ?tr_hazard},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_permanent(commit), ?nop]}),
			 "TESTCASE #13: SubCoord 3 crash permanent during commit."),
	    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop,?crash_permanent(send_prepare), ?nop]}),
			 "TESTCASE #14: SubCoord 3 crash permanent during prepare."),
	    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?crash_transient(send_prepare), ?crash_transient(commit), ?nop]}),
			 "TESTCASE #15: SubCoord 2 crash transient during prepare. SubCoord 3 crash transient during commit"),
	    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?crash_transient(send_prepare), ?nop, ?nop, ?nop]}),
			 "TESTCASE #16: RootCoord crash transient during send prepare."),
	    ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{}},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?nop, [?nop, ?crash_transient(prepare1), ?nop, ?nop]}),
			 "TESTCASE #17: SubCoord 1 crash transient during prepare1."),
	    ?line ?match({'EXCEPTION', ?tr_mixed}, 
			 run(TrFac, 0, {?nop, ?prepare_mix, ?nop, ?nop, [?nop, ?nop, ?crash_transient(prepare2), ?nop]}),
			 "TESTCASE #18: SubCoord 3 crash transient during prepare2. Resource 2 raise Heuristic Mixed during prepare"),
	    ?line ?match({'EXCEPTION', ?tr_mixed},
			 run(TrFac, 0, {?nop, ?commit_mix, ?nop, ?nop, [?nop, ?nop, ?crash_transient(commit2), ?nop]}),
			 "TESTCASE #19: Resource 2 raise Heurist mixed during commit. SubCoord crash transient commit2"),
	    ?line ?match({'EXCEPTION', ?tr_mixed},
			 run(TrFac, 0, {?nop, ?rollback_cm, ?nop, ?prepare_rollback, [?nop, ?crash_transient(rollback2), ?nop, ?nop]}),
			 "TESTCASE #20: Resource 2 raise Heuristic Commit during rollback. Resource 4 'VoteRollback'. SubCoord 2 crash transient rollback2."),
	    ?line ?match({'EXCEPTION', ?tr_mixed},
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?nop, ?nop, ?crash_transient(send_forget1), ?nop]}),
			 "TESTCASE #21: Resource 4 raise Heuristic Mixed during commit. SubCoord 2 crash transient send_forget1."),
	    ?line ?match({'EXCEPTION', ?tr_mixed}, 
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?crash_transient(send_forget1), ?nop, ?nop, ?nop]}),
			 "TESTCASE #22: Resource 4 raise Heuristic Mixed during commit. Root Coord crash transient send_forget1."),
	    ?line ?match({'EXCEPTION', ?tr_mixed}, 
			 run(TrFac, 0, {?nop, ?nop, ?nop, ?commit_mix, [?crash_transient(send_forget3), ?nop, ?crash_transient(send_forget1), ?nop]}),
			 "TESTCASE #23: Resource 4 raise Heuristic Mixed during commit. Root Coord crash transient send_forget3. SubCoord 3 crash transient send_forget1."),
		 ?line ?match({'EXCEPTION', #'TRANSACTION_ROLLEDBACK'{completion_status=?COMPLETED_YES}},
			 run(TrFac, ?TIMEOUT, {?nop, ?nop, ?nop, ?nop, [?delay_transient(root_delay, ?TIMEOUT*2), ?nop, ?nop, ?nop]}),
			 "TESTCASE #24: Delay RootCoord. Timeout."),
	    %% Testing the Terminator.
	    ?line ?match({'EXCEPTION', ?tr_mixed},
			 run(TrFac, ?TIMEOUT, {?nop, ?prepare_mix, ?nop, ?nop, [?nop, ?nop, ?nop, ?crash_transient(commit_heuristic1)]}),
			 "TESTCASE #25: Terminator crash transient after received and logged Heuristic mix."),
	    ?line ?match(ok,
			 run(TrFac, ?TIMEOUT, {?nop, ?nop, ?nop, ?nop, [?nop, ?nop, ?nop, ?crash_transient(commit_ok2)]}),
			 "TESTCASE #26: Terminator crash transient after received and logged 'ok'.");
	_ ->
	    ok
    end,

    ?line cosTransactions:stop_factory(TrFac),
    ?line application:stop(cosTransactions),
    ok.
 
%%-----------------------------------------------------------------
%% Internal functions
%%-----------------------------------------------------------------

run(TrFac, Time, Spec) ->
    Control = 'CosTransactions_TransactionFactory':create(TrFac, Time),
    Term = 'CosTransactions_Control':get_terminator(Control),
    Coord = 'CosTransactions_Control':get_coordinator(Control),
    SubCont1 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
    SubCont2 = 'CosTransactions_Coordinator':create_subtransaction(Coord),
    SubCoord1 = 'CosTransactions_Control':get_coordinator(SubCont1),
    SubCoord2 = 'CosTransactions_Control':get_coordinator(SubCont2),
    %% Start resources/participants.
    {O1, O2, O3, O4, Ctx} = start_resources(Spec),

    %% Get generated names to use for debugging.
    CoordN = 'CosTransactions_Coordinator':get_transaction_name(Coord),
    SubC1N = 'CosTransactions_Coordinator':get_transaction_name(SubCoord1),
    SubC2N = 'CosTransactions_Coordinator':get_transaction_name(SubCoord2),

   ?set_debug_context([CoordN, SubC1N, SubC2N, Term], Ctx),

    %% Register the resources as participants.
    _RC1 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O1),
    _RC2 = 'CosTransactions_Coordinator':register_resource(SubCoord1, O2),
    _RC3 = 'CosTransactions_Coordinator':register_resource(SubCoord2, O3),
    _RC4 = 'CosTransactions_Coordinator':register_resource(SubCoord2, O4),

    'CosTransactions_Coordinator':register_subtran_aware(SubCoord1, O4),
%    'CosTransactions_Coordinator':register_synchronization(SubCoord1, O2),

%    Reply = (catch 'CosTransactions_Terminator':commit(Term, true)),
    Reply = (catch 'ETraP_Common':send_stubborn('CosTransactions_Terminator',
						commit, [Term, true],
						?tr_max_retries,
						?tr_comm_failure_wait)),

    catch corba:dispose(SubCoord1),
    catch corba:dispose(SubCoord2),
    catch corba:dispose(SubCont1),
    catch corba:dispose(SubCont2),
    catch corba:dispose(Term),
    catch corba:dispose(Control),
    catch corba:dispose(Coord),
    catch corba:dispose(O1),
    catch corba:dispose(O2),
    catch corba:dispose(O3),
    catch corba:dispose(O4),
    Reply.



start_resources({A1, A2, A3, A4})->
    start_resources({A1, A2, A3, A4, ?no_context});
start_resources({A1, A2, A3, A4, Ctx})->
    N1 = 'ETraP_Common':create_name("test"),
    N2 = 'ETraP_Common':create_name("test"),
    N3 = 'ETraP_Common':create_name("test"),
    N4 = 'ETraP_Common':create_name("test"),
    {_,_,O1} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A1, N1)),
    {_,_,O2} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A2, N2)),
%    {_,_,O2} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST([{sync,true}|A2], N2)),
    {_,_,O3} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A3, N3)),
    {_,_,O4} = supervisor:start_child(?SUPERVISOR_NAME, ?SUP_TEST(A4, N4)),
    {O1, O2, O3, O4, Ctx}.