diff options
author | Sverker Eriksson <[email protected]> | 2017-08-30 20:55:08 +0200 |
---|---|---|
committer | Sverker Eriksson <[email protected]> | 2017-08-30 20:55:08 +0200 |
commit | 7c67bbddb53c364086f66260701bc54a61c9659c (patch) | |
tree | 92ab0d4b91d5e2f6e7a3f9d61ea25089e8a71fe0 /lib/stdlib/test/fixtable_SUITE.erl | |
parent | 97dc5e7f396129222419811c173edc7fa767b0f8 (diff) | |
parent | 3b7a6ffddc819bf305353a593904cea9e932e7dc (diff) | |
download | otp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.gz otp-7c67bbddb53c364086f66260701bc54a61c9659c.tar.bz2 otp-7c67bbddb53c364086f66260701bc54a61c9659c.zip |
Merge tag 'OTP-19.0' into sverker/19/binary_to_atom-utf8-crash/ERL-474/OTP-14590
Diffstat (limited to 'lib/stdlib/test/fixtable_SUITE.erl')
-rw-r--r-- | lib/stdlib/test/fixtable_SUITE.erl | 514 |
1 files changed, 246 insertions, 268 deletions
diff --git a/lib/stdlib/test/fixtable_SUITE.erl b/lib/stdlib/test/fixtable_SUITE.erl index 57fe4c4508..736e643974 100644 --- a/lib/stdlib/test/fixtable_SUITE.erl +++ b/lib/stdlib/test/fixtable_SUITE.erl @@ -1,18 +1,19 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2016. 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/. +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at %% -%% 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. +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. %% %% %CopyrightEnd% %% @@ -32,7 +33,9 @@ %%% Internal exports -export([command_loop/0,start_commander/0]). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [multiple_fixes, multiple_processes, @@ -55,7 +58,7 @@ end_per_group(_GroupName, Config) -> Config. --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). %%% I wrote this thinking I would use more than one temporary at a time, but %%% I wasn't... Well, maybe in the future... @@ -67,14 +70,11 @@ end_per_group(_GroupName, Config) -> -define(HELPER_NODE, (atom_to_list(?MODULE) ++ "_helper1")). init_per_testcase(_Func, Config) -> - PrivDir = ?config(priv_dir,Config), + PrivDir = proplists:get_value(priv_dir,Config), file:make_dir(PrivDir), - Dog=test_server:timetrap(test_server:seconds(60)), - [{watchdog, Dog}|Config]. + Config. end_per_testcase(_Func, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), lists:foreach(fun(X) -> (catch dets:close(X)), (catch file:delete(dets_filename(X,Config))) @@ -97,302 +97,280 @@ show(Term, Line) -> -endif. -fixbag(doc) -> - ["Check for bug OTP-5087, safe_fixtable for bags could give " - "incorrect lookups"]; -fixbag(suite) -> - []; +%% Check for bug OTP-5087; safe_fixtable for bags could give incorrect +%% lookups. fixbag(Config) when is_list(Config) -> - ?line T = ets:new(x,[bag]), - ?line ets:insert(T,{a,1}), - ?line ets:insert(T,{a,2}), - ?line ets:safe_fixtable(T,true), - ?line ets:match_delete(T,{a,2}), - ?line ets:insert(T,{a,3}), - ?line Res = ets:lookup(T,a), - ?line ets:safe_fixtable(T,false), - ?line Res = ets:lookup(T,a), + T = ets:new(x,[bag]), + ets:insert(T,{a,1}), + ets:insert(T,{a,2}), + ets:safe_fixtable(T,true), + ets:match_delete(T,{a,2}), + ets:insert(T,{a,3}), + Res = ets:lookup(T,a), + ets:safe_fixtable(T,false), + Res = ets:lookup(T,a), ok. -insert_same_key(doc) -> - ["Check correct behaviour if a key is deleted and reinserted during fixation."]; -insert_same_key(suite) -> - []; +%% Check correct behaviour if a key is deleted and reinserted during +%% fixation. insert_same_key(Config) when is_list(Config) -> - ?line {ok,Dets1} = dets:open_file(?DETS_TMP1, - [{file, dets_filename(?DETS_TMP1,Config)}]), - ?line Ets1 = ets:new(ets,[]), - ?line insert_same_key(Dets1,dets,Config), - ?line insert_same_key(Ets1,ets,Config), - ?line ets:insert(Ets1,{1,2}), - ?line 1 = ets:info(Ets1,size), - ?line dets:insert(Dets1,{1,2}), - ?line 1 = dets:info(Dets1,size), - ?line dets:close(Dets1), - ?line (catch file:delete(dets_filename(Dets1,Config))), - ?line ets:delete(Ets1), - ?line {ok,Dets2} = dets:open_file(?DETS_TMP1, - [{type,bag},{file, dets_filename(?DETS_TMP1,Config)}]), - ?line Ets2 = ets:new(ets,[bag]), - ?line insert_same_key(Dets2,dets,Config), - ?line insert_same_key(Ets2,ets,Config), - ?line ets:insert(Ets2,{1,2}), - ?line 2 = ets:info(Ets2,size), - ?line ets:insert(Ets2,{1,2}), - ?line 2 = ets:info(Ets2,size), - ?line dets:insert(Dets2,{1,2}), - ?line 2 = dets:info(Dets2,size), - ?line dets:insert(Dets2,{1,2}), - ?line 2 = dets:info(Dets2,size), - ?line dets:close(Dets2), - ?line (catch file:delete(dets_filename(Dets2,Config))), - ?line ets:delete(Ets2), - ?line {ok,Dets3} = dets:open_file(?DETS_TMP1, - [{type,duplicate_bag}, - {file, dets_filename(?DETS_TMP1,Config)}]), - ?line Ets3 = ets:new(ets,[duplicate_bag]), - ?line insert_same_key(Dets3,dets,Config), - ?line insert_same_key(Ets3,ets,Config), - ?line ets:insert(Ets3,{1,2}), - ?line 2 = ets:info(Ets3,size), - ?line ets:insert(Ets3,{1,2}), - ?line 3 = ets:info(Ets3,size), - ?line dets:insert(Dets3,{1,2}), - ?line 2 = dets:info(Dets3,size), - ?line dets:insert(Dets3,{1,2}), - ?line 3 = dets:info(Dets3,size), - ?line dets:close(Dets3), - ?line (catch file:delete(dets_filename(Dets3,Config))), - ?line ets:delete(Ets3), + {ok,Dets1} = dets:open_file(?DETS_TMP1, + [{file, dets_filename(?DETS_TMP1,Config)}]), + Ets1 = ets:new(ets,[]), + insert_same_key(Dets1,dets,Config), + insert_same_key(Ets1,ets,Config), + ets:insert(Ets1,{1,2}), + 1 = ets:info(Ets1,size), + dets:insert(Dets1,{1,2}), + 1 = dets:info(Dets1,size), + dets:close(Dets1), + (catch file:delete(dets_filename(Dets1,Config))), + ets:delete(Ets1), + {ok,Dets2} = dets:open_file(?DETS_TMP1, + [{type,bag},{file, dets_filename(?DETS_TMP1,Config)}]), + Ets2 = ets:new(ets,[bag]), + insert_same_key(Dets2,dets,Config), + insert_same_key(Ets2,ets,Config), + ets:insert(Ets2,{1,2}), + 2 = ets:info(Ets2,size), + ets:insert(Ets2,{1,2}), + 2 = ets:info(Ets2,size), + dets:insert(Dets2,{1,2}), + 2 = dets:info(Dets2,size), + dets:insert(Dets2,{1,2}), + 2 = dets:info(Dets2,size), + dets:close(Dets2), + (catch file:delete(dets_filename(Dets2,Config))), + ets:delete(Ets2), + {ok,Dets3} = dets:open_file(?DETS_TMP1, + [{type,duplicate_bag}, + {file, dets_filename(?DETS_TMP1,Config)}]), + Ets3 = ets:new(ets,[duplicate_bag]), + insert_same_key(Dets3,dets,Config), + insert_same_key(Ets3,ets,Config), + ets:insert(Ets3,{1,2}), + 2 = ets:info(Ets3,size), + ets:insert(Ets3,{1,2}), + 3 = ets:info(Ets3,size), + dets:insert(Dets3,{1,2}), + 2 = dets:info(Dets3,size), + dets:insert(Dets3,{1,2}), + 3 = dets:info(Dets3,size), + dets:close(Dets3), + (catch file:delete(dets_filename(Dets3,Config))), + ets:delete(Ets3), ok. insert_same_key(Tab,Mod,_Config) -> - ?line Mod:insert(Tab,{1,1}), - ?line Mod:insert(Tab,{1,2}), - ?line Mod:insert(Tab,{2,2}), - ?line Mod:insert(Tab,{2,2}), - ?line Mod:safe_fixtable(Tab,true), - ?line Mod:delete(Tab,1), - ?line Mod:insert(Tab,{1,1}), - ?line Expect = case Mod:info(Tab,type) of - bag -> - Mod:insert(Tab,{1,2}), - 2; - _ -> - 1 - end, - ?line Mod:delete(Tab,2), - ?line Mod:safe_fixtable(Tab,false), - ?line case Mod:info(Tab,size) of - Expect -> - ok; - _ -> - exit({size_field_wrong,{Mod,Mod:info(Tab)}}) - end. - - - - -owner_dies(doc) -> - ["Check correct behaviour if the table owner dies."]; -owner_dies(suite) -> - []; + Mod:insert(Tab,{1,1}), + Mod:insert(Tab,{1,2}), + Mod:insert(Tab,{2,2}), + Mod:insert(Tab,{2,2}), + Mod:safe_fixtable(Tab,true), + Mod:delete(Tab,1), + Mod:insert(Tab,{1,1}), + Expect = case Mod:info(Tab,type) of + bag -> + Mod:insert(Tab,{1,2}), + 2; + _ -> + 1 + end, + Mod:delete(Tab,2), + Mod:safe_fixtable(Tab,false), + case Mod:info(Tab,size) of + Expect -> + ok; + _ -> + exit({size_field_wrong,{Mod,Mod:info(Tab)}}) + end. + + + + +%% Check correct behaviour if the table owner dies. owner_dies(Config) when is_list(Config) -> - ?line P1 = start_commander(), - ?line Ets1 = command(P1,{ets,new,[ets,[]]}), - ?line command(P1,{ets,safe_fixtable,[Ets1,true]}), - ?line {_,[{P1,1}]} = ets:info(Ets1, safe_fixed), - ?line stop_commander(P1), - ?line undefined = ets:info(Ets1, safe_fixed), - ?line P2 = start_commander(), - ?line Ets2 = command(P2,{ets,new,[ets,[public]]}), - ?line command(P2,{ets,safe_fixtable,[Ets2,true]}), - ?line ets:safe_fixtable(Ets2,true), - ?line true = ets:info(Ets2, fixed), - ?line {_,[{_,1},{_,1}]} = ets:info(Ets2, safe_fixed), - ?line stop_commander(P2), - ?line undefined = ets:info(Ets2, safe_fixed), - ?line undefined = ets:info(Ets2, fixed), - ?line P3 = start_commander(), - ?line {ok,Dets} = ?LOG(command(P3, {dets, open_file, - [?DETS_TMP1, - [{file, - dets_filename(?DETS_TMP1, - Config)}]]})), - ?line command(P3, {dets, safe_fixtable, [Dets, true]}), - ?line {_,[{P3,1}]} = dets:info(Dets, safe_fixed), - ?line true = dets:info(Dets, fixed), - ?line stop_commander(P3), - ?line undefined = dets:info(Dets, safe_fixed), - ?line undefined = dets:info(Dets, fixed), - ?line P4 = start_commander(), - ?line {ok,Dets} = command(P4, {dets, open_file, + P1 = start_commander(), + Ets1 = command(P1,{ets,new,[ets,[]]}), + command(P1,{ets,safe_fixtable,[Ets1,true]}), + {_,[{P1,1}]} = ets:info(Ets1, safe_fixed), + stop_commander(P1), + undefined = ets:info(Ets1, safe_fixed), + P2 = start_commander(), + Ets2 = command(P2,{ets,new,[ets,[public]]}), + command(P2,{ets,safe_fixtable,[Ets2,true]}), + ets:safe_fixtable(Ets2,true), + true = ets:info(Ets2, fixed), + {_,[{_,1},{_,1}]} = ets:info(Ets2, safe_fixed), + stop_commander(P2), + undefined = ets:info(Ets2, safe_fixed), + undefined = ets:info(Ets2, fixed), + P3 = start_commander(), + {ok,Dets} = ?LOG(command(P3, {dets, open_file, + [?DETS_TMP1, + [{file, + dets_filename(?DETS_TMP1, + Config)}]]})), + command(P3, {dets, safe_fixtable, [Dets, true]}), + {_,[{P3,1}]} = dets:info(Dets, safe_fixed), + true = dets:info(Dets, fixed), + stop_commander(P3), + undefined = dets:info(Dets, safe_fixed), + undefined = dets:info(Dets, fixed), + P4 = start_commander(), + {ok,Dets} = command(P4, {dets, open_file, [?DETS_TMP1, [{file, dets_filename(?DETS_TMP1,Config)}]]}), - ?line {ok,Dets} = dets:open_file(?DETS_TMP1, + {ok,Dets} = dets:open_file(?DETS_TMP1, [{file, dets_filename(?DETS_TMP1,Config)}]), - ?line false = dets:info(Dets, safe_fixed), - ?line command(P4, {dets, safe_fixtable, [Dets, true]}), - ?line dets:safe_fixtable(Dets, true), - ?line {_,[{_,1},{_,1}]} = dets:info(Dets, safe_fixed), - ?line dets:safe_fixtable(Dets, true), - ?line stop_commander(P4), - ?line S = self(), - ?line {_,[{S,2}]} = dets:info(Dets, safe_fixed), - ?line true = dets:info(Dets, fixed), - ?line dets:close(Dets), - ?line undefined = dets:info(Dets, fixed), - ?line undefined = dets:info(Dets, safe_fixed), + false = dets:info(Dets, safe_fixed), + command(P4, {dets, safe_fixtable, [Dets, true]}), + dets:safe_fixtable(Dets, true), + {_,[{_,1},{_,1}]} = dets:info(Dets, safe_fixed), + dets:safe_fixtable(Dets, true), + stop_commander(P4), + S = self(), + {_,[{S,2}]} = dets:info(Dets, safe_fixed), + true = dets:info(Dets, fixed), + dets:close(Dets), + undefined = dets:info(Dets, fixed), + undefined = dets:info(Dets, safe_fixed), ok. - - -other_process_closes(doc) -> - ["When another process closes an dets table, different " - "things should happen depending on if it has opened it before."]; -other_process_closes(suite) -> - []; +%% When another process closes an dets table, different things should +%% happen depending on if it has opened it before. other_process_closes(Config) when is_list(Config) -> - ?line {ok,Dets} = dets:open_file(?DETS_TMP1, + {ok,Dets} = dets:open_file(?DETS_TMP1, [{file, dets_filename(tmp1,Config)}]), - ?line P2 = start_commander(), - ?line dets:safe_fixtable(Dets,true), - ?line S = self(), - ?line {_,[{S,1}]} = dets:info(Dets, safe_fixed), - ?line command(P2,{dets, safe_fixtable, [Dets, true]}), - ?line {_,[_,_]} = dets:info(Dets, safe_fixed), - ?line {error, not_owner} = command(P2,{dets, close, [Dets]}), - ?line {_,[_,_]} = dets:info(Dets, safe_fixed), - ?line command(P2,{dets, open_file,[?DETS_TMP1, + P2 = start_commander(), + dets:safe_fixtable(Dets,true), + S = self(), + {_,[{S,1}]} = dets:info(Dets, safe_fixed), + command(P2,{dets, safe_fixtable, [Dets, true]}), + {_,[_,_]} = dets:info(Dets, safe_fixed), + {error, not_owner} = command(P2,{dets, close, [Dets]}), + {_,[_,_]} = dets:info(Dets, safe_fixed), + command(P2,{dets, open_file,[?DETS_TMP1, [{file, dets_filename(?DETS_TMP1, Config)}]]}), - ?line {_,[_,_]} = dets:info(Dets, safe_fixed), - ?line command(P2,{dets, close, [Dets]}), - ?line stop_commander(P2), - ?line {_,[{S,1}]} = dets:info(Dets, safe_fixed), - ?line true = dets:info(Dets,fixed), - ?line dets:close(Dets), - ?line undefined = dets:info(Dets,fixed), - ?line undefined = dets:info(Dets, safe_fixed), + {_,[_,_]} = dets:info(Dets, safe_fixed), + command(P2,{dets, close, [Dets]}), + stop_commander(P2), + {_,[{S,1}]} = dets:info(Dets, safe_fixed), + true = dets:info(Dets,fixed), + dets:close(Dets), + undefined = dets:info(Dets,fixed), + undefined = dets:info(Dets, safe_fixed), ok. - -other_process_deletes(doc) -> - ["Check that fixtable structures are cleaned up if another process " - "deletes an ets table"]; -other_process_deletes(suite) -> - []; + +%% Check that fixtable structures are cleaned up if another process +%% deletes an ets table. other_process_deletes(Config) when is_list(Config) -> - ?line Ets = ets:new(ets,[public]), - ?line P = start_commander(), - ?line ets:safe_fixtable(Ets,true), - ?line ets:safe_fixtable(Ets,true), - ?line true = ets:info(Ets, fixed), - ?line {_,_} = ets:info(Ets, safe_fixed), - ?line command(P,{ets,delete,[Ets]}), - ?line stop_commander(P), - ?line undefined = ets:info(Ets, fixed), - ?line undefined = ets:info(Ets, safe_fixed), + Ets = ets:new(ets,[public]), + P = start_commander(), + ets:safe_fixtable(Ets,true), + ets:safe_fixtable(Ets,true), + true = ets:info(Ets, fixed), + {_,_} = ets:info(Ets, safe_fixed), + command(P,{ets,delete,[Ets]}), + stop_commander(P), + undefined = ets:info(Ets, fixed), + undefined = ets:info(Ets, safe_fixed), ok. -multiple_fixes(doc) -> - ["Check that multiple safe_fixtable keeps the reference counter."]; -multiple_fixes(suite) -> - []; +%% Check that multiple safe_fixtable keeps the reference counter. multiple_fixes(Config) when is_list(Config) -> - ?line {ok,Dets} = dets:open_file(?DETS_TMP1, + {ok,Dets} = dets:open_file(?DETS_TMP1, [{file, dets_filename(?DETS_TMP1,Config)}]), - ?line Ets = ets:new(ets,[]), - ?line multiple_fixes(Dets,dets), - ?line multiple_fixes(Ets,ets), - ?line dets:close(Dets), + Ets = ets:new(ets,[]), + multiple_fixes(Dets,dets), + multiple_fixes(Ets,ets), + dets:close(Dets), ok. multiple_fixes(Tab, Mod) -> - ?line false = Mod:info(Tab,fixed), - ?line false = Mod:info(Tab, safe_fixed), - ?line Mod:safe_fixtable(Tab, true), - ?line true = Mod:info(Tab,fixed), - ?line S = self(), - ?line {_,[{S,1}]} = Mod:info(Tab, safe_fixed), - ?line Mod:safe_fixtable(Tab, true), - ?line Mod:safe_fixtable(Tab, true), - ?line {_,[{S,3}]} = Mod:info(Tab, safe_fixed), - ?line true = Mod:info(Tab,fixed), - ?line Mod:safe_fixtable(Tab, false), - ?line {_,[{S,2}]} = Mod:info(Tab, safe_fixed), - ?line true = Mod:info(Tab,fixed), - ?line Mod:safe_fixtable(Tab, false), - ?line {_,[{S,1}]} = Mod:info(Tab, safe_fixed), - ?line true = Mod:info(Tab,fixed), - ?line Mod:safe_fixtable(Tab, false), - ?line false = Mod:info(Tab, safe_fixed), - ?line false = Mod:info(Tab,fixed). - -multiple_processes(doc) -> - ["Check that multiple safe_fixtable across processes are reference " - "counted OK"]; -multiple_processes(suite) -> - []; + false = Mod:info(Tab,fixed), + false = Mod:info(Tab, safe_fixed), + Mod:safe_fixtable(Tab, true), + true = Mod:info(Tab,fixed), + S = self(), + {_,[{S,1}]} = Mod:info(Tab, safe_fixed), + Mod:safe_fixtable(Tab, true), + Mod:safe_fixtable(Tab, true), + {_,[{S,3}]} = Mod:info(Tab, safe_fixed), + true = Mod:info(Tab,fixed), + Mod:safe_fixtable(Tab, false), + {_,[{S,2}]} = Mod:info(Tab, safe_fixed), + true = Mod:info(Tab,fixed), + Mod:safe_fixtable(Tab, false), + {_,[{S,1}]} = Mod:info(Tab, safe_fixed), + true = Mod:info(Tab,fixed), + Mod:safe_fixtable(Tab, false), + false = Mod:info(Tab, safe_fixed), + false = Mod:info(Tab,fixed). + +%% Check that multiple safe_fixtable across processes are reference +%% counted OK. multiple_processes(Config) when is_list(Config) -> - ?line {ok,Dets} = dets:open_file(?DETS_TMP1,[{file, + {ok,Dets} = dets:open_file(?DETS_TMP1,[{file, dets_filename(?DETS_TMP1, Config)}]), - ?line Ets = ets:new(ets,[public]), - ?line multiple_processes(Dets,dets), - ?line multiple_processes(Ets,ets), + Ets = ets:new(ets,[public]), + multiple_processes(Dets,dets), + multiple_processes(Ets,ets), ok. multiple_processes(Tab, Mod) -> - ?line io:format("Mod = ~p\n", [Mod]), - ?line P1 = start_commander(), - ?line P2 = start_commander(), - ?line false = Mod:info(Tab,fixed), - ?line false = Mod:info(Tab, safe_fixed), - ?line command(P1, {Mod, safe_fixtable, [Tab,true]}), - ?line true = Mod:info(Tab,fixed), - ?line {_,[{P1,1}]} = Mod:info(Tab, safe_fixed), - ?line command(P2, {Mod, safe_fixtable, [Tab,true]}), - ?line true = Mod:info(Tab,fixed), - ?line {_,L} = Mod:info(Tab,safe_fixed), - ?line true = (lists:sort(L) == lists:sort([{P1,1},{P2,1}])), - ?line command(P2, {Mod, safe_fixtable, [Tab,true]}), - ?line {_,L2} = Mod:info(Tab,safe_fixed), - ?line true = (lists:sort(L2) == lists:sort([{P1,1},{P2,2}])), - ?line command(P2, {Mod, safe_fixtable, [Tab,false]}), - ?line true = Mod:info(Tab,fixed), - ?line {_,L3} = Mod:info(Tab,safe_fixed), - ?line true = (lists:sort(L3) == lists:sort([{P1,1},{P2,1}])), - ?line command(P2, {Mod, safe_fixtable, [Tab,false]}), - ?line true = Mod:info(Tab,fixed), - ?line {_,[{P1,1}]} = Mod:info(Tab, safe_fixed), - ?line stop_commander(P1), - ?line receive after 1000 -> ok end, - ?line false = Mod:info(Tab,fixed), - ?line false = Mod:info(Tab, safe_fixed), - ?line command(P2, {Mod, safe_fixtable, [Tab,true]}), - ?line true = Mod:info(Tab,fixed), - ?line {_,[{P2,1}]} = Mod:info(Tab, safe_fixed), + io:format("Mod = ~p\n", [Mod]), + P1 = start_commander(), + P2 = start_commander(), + false = Mod:info(Tab,fixed), + false = Mod:info(Tab, safe_fixed), + command(P1, {Mod, safe_fixtable, [Tab,true]}), + true = Mod:info(Tab,fixed), + {_,[{P1,1}]} = Mod:info(Tab, safe_fixed), + command(P2, {Mod, safe_fixtable, [Tab,true]}), + true = Mod:info(Tab,fixed), + {_,L} = Mod:info(Tab,safe_fixed), + true = (lists:sort(L) == lists:sort([{P1,1},{P2,1}])), + command(P2, {Mod, safe_fixtable, [Tab,true]}), + {_,L2} = Mod:info(Tab,safe_fixed), + true = (lists:sort(L2) == lists:sort([{P1,1},{P2,2}])), + command(P2, {Mod, safe_fixtable, [Tab,false]}), + true = Mod:info(Tab,fixed), + {_,L3} = Mod:info(Tab,safe_fixed), + true = (lists:sort(L3) == lists:sort([{P1,1},{P2,1}])), + command(P2, {Mod, safe_fixtable, [Tab,false]}), + true = Mod:info(Tab,fixed), + {_,[{P1,1}]} = Mod:info(Tab, safe_fixed), + stop_commander(P1), + receive after 1000 -> ok end, + false = Mod:info(Tab,fixed), + false = Mod:info(Tab, safe_fixed), + command(P2, {Mod, safe_fixtable, [Tab,true]}), + true = Mod:info(Tab,fixed), + {_,[{P2,1}]} = Mod:info(Tab, safe_fixed), case Mod of dets -> - ?line dets:close(Tab); + dets:close(Tab); ets -> - ?line ets:delete(Tab) + ets:delete(Tab) end, - ?line stop_commander(P2), - ?line receive after 1000 -> ok end, - ?line undefined = Mod:info(Tab, safe_fixed), + stop_commander(P2), + receive after 1000 -> ok end, + undefined = Mod:info(Tab, safe_fixed), ok. - - + + %%% Helpers dets_filename(Base, Config) when is_atom(Base) -> dets_filename(atom_to_list(Base) ++ ".dat", Config); dets_filename(Basename, Config) -> - PrivDir = ?config(priv_dir,Config), + PrivDir = proplists:get_value(priv_dir,Config), filename:join(PrivDir, Basename). command_loop() -> |