148
139
ct_event:add_handler([{vts,VtsPid}])
151
case read_config_files(Opts) of
154
case lists:keysearch(event_handler,1,Opts) of
155
{value,{_,Handlers}} ->
156
Add = fun({H,Args}) ->
157
case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
159
{'EXIT',Why} -> exit(Why);
160
Other -> exit({event_handler,Other})
163
case catch lists:foreach(Add,Handlers) of
165
Parent ! {self(),Reason};
142
%% start ct_config server
143
ct_config:start(Mode),
144
%% add user event handlers
145
case lists:keysearch(event_handler,1,Opts) of
146
{value,{_,Handlers}} ->
147
Add = fun({H,Args}) ->
148
case catch gen_event:add_handler(?CT_EVMGR_REF,H,Args) of
150
{'EXIT',Why} -> exit(Why);
151
Other -> exit({event_handler,Other})
154
case catch lists:foreach(Add,Handlers) of
156
Parent ! {self(),Reason};
172
{StartTime,TestLogDir} = ct_logs:init(Mode),
173
ct_event:notify(#event{name=test_start,
176
lists:flatten(TestLogDir)}}),
177
Parent ! {self(),started},
178
loop(Mode,[],StartDir);
180
Parent ! {self(),ReadError},
163
{StartTime,TestLogDir} = ct_logs:init(Mode),
166
case catch ct_hooks:init(Opts) of
170
ct_logs:tc_print('Suite Callback',CTHReason,[]),
171
Parent ! {self(), CTHReason},
172
self() ! {{stop,normal},{self(),make_ref()}}
175
ct_event:notify(#event{name=test_start,
178
lists:flatten(TestLogDir)}}),
179
Parent ! {self(),started},
180
loop(Mode,[],StartDir).
184
182
create_table(TableName,KeyPos) ->
185
183
create_table(TableName,set,KeyPos).
197
195
{error,{bad_installation,Error}}
200
read_config_files(Opts) ->
202
lists:foldl(fun({config,Files},Acc) ->
207
read_config_files1(ConfigFiles).
209
read_config_files1([ConfigFile|Files]) ->
210
case file:consult(ConfigFile) of
213
read_config_files1(Files);
215
{user_error,{config_file_error,ConfigFile,enoent}};
218
case application:get_env(common_test, decrypt) of
224
get_crypt_key_from_file(F)
227
get_crypt_key_from_file()
230
{error,no_crypt_file} ->
231
{user_error,{config_file_error,ConfigFile,Reason}};
232
{error,CryptError} ->
233
{user_error,{decrypt_file_error,ConfigFile,CryptError}};
234
_ when is_list(Key) ->
235
case decrypt_config_file(ConfigFile, undefined, {key,Key}) of
237
case read_config_terms(CfgBin) of
239
{user_error,{config_file_error,ConfigFile,ReadFail}};
242
read_config_files1(Files)
244
{error,DecryptFail} ->
245
{user_error,{decrypt_config_error,ConfigFile,DecryptFail}}
248
{user_error,{bad_decrypt_key,ConfigFile,Key}}
251
read_config_files1([]) ->
254
read_config_terms(Bin) when is_binary(Bin) ->
255
case catch binary_to_list(Bin) of
257
{error,invalid_textfile};
259
read_config_terms(Lines)
261
read_config_terms(Lines) when is_list(Lines) ->
262
read_config_terms1(erl_scan:tokens([], Lines, 0), 1, [], []).
264
read_config_terms1({done,{ok,Ts,EL},Rest}, L, Terms, _) ->
265
case erl_parse:parse_term(Ts) of
266
{ok,Term} when Rest == [] ->
267
lists:reverse([Term|Terms]);
269
read_config_terms1(erl_scan:tokens([], Rest, 0),
270
EL+1, [Term|Terms], Rest);
272
{error,{bad_term,{L,EL}}}
274
read_config_terms1({done,{eof,_},_}, _, Terms, Rest) when Rest == [] ->
275
lists:reverse(Terms);
276
read_config_terms1({done,{eof,EL},_}, L, _, _) ->
277
{error,{bad_term,{L,EL}}};
278
read_config_terms1({done,{error,Info,EL},_}, L, _, _) ->
279
{error,{Info,{L,EL}}};
280
read_config_terms1({more,_}, L, Terms, Rest) ->
281
case string:tokens(Rest, [$\n,$\r,$\t]) of
283
lists:reverse(Terms);
288
set_default_config(NewConfig, Scope) ->
289
call({set_default_config, {NewConfig, Scope}}).
291
set_default_config(Name, NewConfig, Scope) ->
292
call({set_default_config, {Name, NewConfig, Scope}}).
294
delete_default_config(Scope) ->
295
call({delete_default_config, Scope}).
297
update_config(Name, Config) ->
298
call({update_config, {Name, Config}}).
300
199
save_suite_data(Key, Value) ->
301
200
call({save_suite_data, {Key, undefined, Value}}).
342
247
ct_logs:make_last_run_index(),
344
249
loop(Mode,TestData,StartDir);
345
{{require,Name,Tag,SubTags},From} ->
346
Result = do_require(Name,Tag,SubTags),
348
loop(Mode,TestData,StartDir);
349
{{set_default_config,{Config,Scope}},From} ->
350
set_config(Config,{true,Scope}),
352
loop(Mode,TestData,StartDir);
353
{{set_default_config,{Name,Config,Scope}},From} ->
354
set_config(Name,Config,{true,Scope}),
356
loop(Mode,TestData,StartDir);
357
{{delete_default_config,Scope},From} ->
358
delete_config({true,Scope}),
360
loop(Mode,TestData,StartDir);
361
{{update_config,{Name,NewConfig}},From} ->
362
update_conf(Name,NewConfig),
364
loop(Mode,TestData,StartDir);
365
250
{{save_suite_data,{Key,Name,Value}},From} ->
366
251
ets:insert(?suite_table, #suite_data{key=Key,
571
get_name_from_ref(TargetRef);
468
ct_config:get_name_from_ref(TargetRef);
573
470
{error,{unknown_connection,ConnPid}}
577
%%%-----------------------------------------------------------------
579
%%% @equiv ct:require/1
580
require(Key) when is_atom(Key) ->
582
require({Key,SubKeys}) when is_atom(Key) ->
583
allocate('_UNDEF',Key,to_list(SubKeys));
585
{error,{invalid,Key}}.
588
%%%-----------------------------------------------------------------
590
%%% @equiv ct:require/2
591
require(Name,Key) when is_atom(Key) ->
592
require(Name,{Key,[]});
593
require(Name,{Key,SubKeys}) when is_atom(Name), is_atom(Key) ->
594
call({require,Name,Key,to_list(SubKeys)});
595
require(Name,Keys) ->
596
{error,{invalid,{Name,Keys}}}.
598
to_list(X) when is_list(X) -> X;
601
do_require(Name,Key,SubKeys) when is_list(SubKeys) ->
602
case get_key_from_name(Name) of
604
allocate(Name,Key,SubKeys);
606
%% already allocated - check that it has all required subkeys
607
Vals = [Val || {_Ref,Val} <- lookup_name(Name)],
608
case get_subconfig(SubKeys,Vals) of
615
{error,{name_in_use,Name,OtherKey}}
618
allocate(Name,Key,SubKeys) ->
619
case ets:match_object(?attr_table,#ct_conf{key=Key,name='_UNDEF',_='_'}) of
621
{error,{not_available,Key}};
623
case allocate_subconfig(Name,SubKeys,Available,false) of
631
allocate_subconfig(Name,SubKeys,[C=#ct_conf{value=Value}|Rest],Found) ->
632
case do_get_config(SubKeys,Value,[]) of
634
ets:insert(?attr_table,C#ct_conf{name=Name}),
635
allocate_subconfig(Name,SubKeys,Rest,true);
637
allocate_subconfig(Name,SubKeys,Rest,Found)
639
allocate_subconfig(_Name,_SubKeys,[],true) ->
641
allocate_subconfig(_Name,SubKeys,[],false) ->
642
{error,{not_available,SubKeys}}.
647
%%%-----------------------------------------------------------------
649
%%% @equiv ct:get_config/1
650
get_config(KeyOrName) ->
651
get_config(KeyOrName,undefined,[]).
653
%%%-----------------------------------------------------------------
655
%%% @equiv ct:get_config/2
656
get_config(KeyOrName,Default) ->
657
get_config(KeyOrName,Default,[]).
659
%%%-----------------------------------------------------------------
661
%%% @equiv ct:get_config/3
662
get_config(KeyOrName,Default,Opts) when is_atom(KeyOrName) ->
663
case lookup_config(KeyOrName) of
666
[{_Ref,Val}|_] = Vals ->
667
case {lists:member(all,Opts),lists:member(element,Opts)} of
669
[{KeyOrName,V} || {_R,V} <- lists:sort(Vals)];
671
[V || {_R,V} <- lists:sort(Vals)];
679
get_config({KeyOrName,SubKey},Default,Opts) ->
680
case lookup_config(KeyOrName) of
684
Vals1 = case [Val || {_Ref,Val} <- lists:sort(Vals)] of
685
Result=[L|_] when is_list(L) ->
695
case get_subconfig([SubKey],Vals1,[],Opts) of
696
{ok,[{_,SubVal}|_]=SubVals} ->
697
case {lists:member(all,Opts),lists:member(element,Opts)} of
699
[{{KeyOrName,SubKey},Val} || {_,Val} <- SubVals];
701
[Val || {_SubKey,Val} <- SubVals];
703
{{KeyOrName,SubKey},SubVal};
713
get_subconfig(SubKeys,Values) ->
714
get_subconfig(SubKeys,Values,[],[]).
716
get_subconfig(SubKeys,[Value|Rest],Mapped,Opts) ->
717
case do_get_config(SubKeys,Value,[]) of
719
case lists:member(all,Opts) of
721
get_subconfig(SubKeys,Rest,Mapped++SubMapped,Opts);
726
get_subconfig(SubKeys,Rest,Mapped,Opts)
728
get_subconfig(SubKeys,[],[],_) ->
729
{error,{not_available,SubKeys}};
730
get_subconfig(_SubKeys,[],Mapped,_) ->
733
do_get_config([Key|Required],Available,Mapped) ->
734
case lists:keysearch(Key,1,Available) of
735
{value,{Key,Value}} ->
736
NewAvailable = lists:keydelete(Key,1,Available),
737
NewMapped = [{Key,Value}|Mapped],
738
do_get_config(Required,NewAvailable,NewMapped);
740
{error,{not_available,Key}}
742
do_get_config([],_Available,Mapped) ->
743
{ok,lists:reverse(Mapped)}.
746
ets:select(?attr_table,[{#ct_conf{name='$1',key='$2',value='$3',
749
[{{'$1','$2','$3','$4'}}]}]).
751
lookup_config(KeyOrName) ->
752
case lookup_name(KeyOrName) of
754
lookup_key(KeyOrName);
760
ets:select(?attr_table,[{#ct_conf{ref='$1',value='$2',name=Name,_='_'},
764
ets:select(?attr_table,[{#ct_conf{key=Key,ref='$1',value='$2',name='_UNDEF',_='_'},
768
set_config(Config) ->
769
set_config('_UNDEF',Config,false).
771
set_config(Config,Default) ->
772
set_config('_UNDEF',Config,Default).
774
set_config(Name,Config,Default) ->
775
[ets:insert(?attr_table,
776
#ct_conf{key=Key,value=Val,ref=ct_make_ref(),
777
name=Name,default=Default}) ||
778
{Key,Val} <- Config].
780
delete_config(Default) ->
781
ets:match_delete(?attr_table,#ct_conf{default=Default,_='_'}),
785
%%%-----------------------------------------------------------------
786
%%% @spec release_allocated() -> ok
788
%%% @doc Release all allocated resources, but don't take down any
790
release_allocated() ->
791
Allocated = ets:select(?attr_table,[{#ct_conf{name='$1',_='_'},
792
[{'=/=','$1','_UNDEF'}],
794
release_allocated(Allocated).
795
release_allocated([H|T]) ->
796
ets:delete_object(?attr_table,H),
797
ets:insert(?attr_table,H#ct_conf{name='_UNDEF'}),
798
release_allocated(T);
799
release_allocated([]) ->
802
%%%-----------------------------------------------------------------
806
update_conf(Name, NewConfig) ->
807
Old = ets:select(?attr_table,[{#ct_conf{name=Name,_='_'},[],['$_']}]),
808
lists:foreach(fun(OldElem) ->
809
NewElem = OldElem#ct_conf{value=NewConfig},
810
ets:delete_object(?attr_table, OldElem),
811
ets:insert(?attr_table, NewElem)
815
473
%%%-----------------------------------------------------------------
816
474
%%% @spec close_connections() -> ok
929
587
%%% @equiv ct:parse_table/1
930
588
parse_table(Data) ->
932
[remove_space(string:tokens(L, "|"),[]) || L <- Data, hd(L)==$|],
589
{Heading, Rest} = get_headings(Data),
590
Lines = parse_row(Rest,[],size(Heading)),
593
get_headings(["|" ++ Headings | Rest]) ->
594
{remove_space(string:tokens(Headings, "|"),[]), Rest};
595
get_headings([_ | Rest]) ->
600
parse_row(["|" ++ _ = Row | T], Rows, NumCols) when NumCols > 1 ->
601
case string:tokens(Row, "|") of
602
Values when length(Values) =:= NumCols ->
603
parse_row(T,[remove_space(Values,[])|Rows], NumCols);
604
Values when length(Values) < NumCols ->
605
parse_row([Row ++"\n"++ hd(T) | tl(T)], Rows, NumCols)
607
parse_row(["|" ++ _ = Row | T], Rows, 1 = NumCols) ->
608
case string:rchr(Row, $|) of
610
parse_row([Row ++"\n"++hd(T) | tl(T)], Rows, NumCols);
612
parse_row(T, [remove_space(string:tokens(Row,"|"),[])|Rows],
615
parse_row([_Skip | T], Rows, NumCols) ->
616
parse_row(T, Rows, NumCols);
617
parse_row([], Rows, _NumCols) ->
935
620
remove_space([Str|Rest],Acc) ->
936
621
remove_space(Rest,[string:strip(string:strip(Str),both,$')|Acc]);
937
622
remove_space([],Acc) ->
998
encrypt_config_file(SrcFileName, EncryptFileName) ->
999
case get_crypt_key_from_file() of
1003
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
1006
%%%-----------------------------------------------------------------
1010
encrypt_config_file(SrcFileName, EncryptFileName, {file,KeyFile}) ->
1011
case get_crypt_key_from_file(KeyFile) of
1015
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key})
1018
encrypt_config_file(SrcFileName, EncryptFileName, {key,Key}) ->
1020
{K1,K2,K3,IVec} = make_crypto_key(Key),
1021
case file:read_file(SrcFileName) of
1023
Bin1 = term_to_binary({SrcFileName,Bin0}),
1024
Bin2 = case byte_size(Bin1) rem 8 of
1026
N -> list_to_binary([Bin1,random_bytes(8-N)])
1028
EncBin = crypto:des3_cbc_encrypt(K1, K2, K3, IVec, Bin2),
1029
case file:write_file(EncryptFileName, EncBin) of
1031
io:format("~s --(encrypt)--> ~s~n",
1032
[SrcFileName,EncryptFileName]),
1035
{error,{Reason,EncryptFileName}}
1038
{error,{Reason,SrcFileName}}
1041
%%%-----------------------------------------------------------------
1045
decrypt_config_file(EncryptFileName, TargetFileName) ->
1046
case get_crypt_key_from_file() of
1050
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key})
1054
%%%-----------------------------------------------------------------
1058
decrypt_config_file(EncryptFileName, TargetFileName, {file,KeyFile}) ->
1059
case get_crypt_key_from_file(KeyFile) of
1063
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key})
1066
decrypt_config_file(EncryptFileName, TargetFileName, {key,Key}) ->
1068
{K1,K2,K3,IVec} = make_crypto_key(Key),
1069
case file:read_file(EncryptFileName) of
1071
DecBin = crypto:des3_cbc_decrypt(K1, K2, K3, IVec, Bin),
1072
case catch binary_to_term(DecBin) of
1075
{_SrcFile,SrcBin} ->
1076
case TargetFileName of
1080
case file:write_file(TargetFileName, SrcBin) of
1082
io:format("~s --(decrypt)--> ~s~n",
1083
[EncryptFileName,TargetFileName]),
1086
{error,{Reason,TargetFileName}}
1091
{error,{Reason,EncryptFileName}}
1095
get_crypt_key_from_file(File) ->
1096
case file:read_file(File) of
1098
case catch string:tokens(binary_to_list(Bin), [$\n,$\r]) of
1102
{error,{bad_crypt_file,File}}
1105
{error,{Reason,File}}
1108
get_crypt_key_from_file() ->
1109
CwdFile = filename:join(".",?cryptfile),
1111
case file:read_file(CwdFile) of
1115
case init:get_argument(home) of
1117
HomeFile = filename:join(Home,?cryptfile),
1118
case file:read_file(HomeFile) of
1122
{{error,no_crypt_file},noent}
1125
{{error,no_crypt_file},noent}
1132
case catch string:tokens(binary_to_list(Result), [$\n,$\r]) of
1134
io:format("~nCrypt key file: ~s~n", [FullName]),
1137
{error,{bad_crypt_file,FullName}}
1141
make_crypto_key(String) ->
1142
<<K1:8/binary,K2:8/binary>> = First = erlang:md5(String),
1143
<<K3:8/binary,IVec:8/binary>> = erlang:md5([First|lists:reverse(String)]),
1148
random:seed(A, B, C),
1149
random_bytes_1(N, []).
1151
random_bytes_1(0, Acc) -> Acc;
1152
random_bytes_1(N, Acc) -> random_bytes_1(N-1, [random:uniform(255)|Acc]).
1155
%%%-----------------------------------------------------------------
1159
683
get_attached(TCPid) ->
1160
684
case dbg_iserver:safe_call({get_attpid,TCPid}) of
1161
685
{ok,AttPid} when is_pid(AttPid) ->