1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(sasl_SUITE).
21-include_lib("common_test/include/ct.hrl").
22
23%% Test server specific exports
24-export([init_per_suite/1,end_per_suite/1]).
25-export([all/0,groups/0,init_per_group/2,end_per_group/2]).
26-export([init_per_testcase/2, end_per_testcase/2]).
27
28%% Test cases must be exported.
29-export([app_test/1,
30	 appup_test/1,
31	 log_mf_h_env/1,
32	 log_file/1,
33	 utc_log/1]).
34
35-compile(r21).
36
37all() ->
38    [log_mf_h_env, log_file, app_test, appup_test, utc_log].
39
40groups() ->
41    [].
42
43init_per_suite(Config) ->
44    S = application:get_env(kernel,logger_sasl_compatible),
45    application:set_env(kernel,logger_sasl_compatible,true),
46    [{sasl_compatible,S}|Config].
47
48end_per_suite(Config) ->
49    case ?config(sasl_compatible,Config) of
50        {ok,X} ->
51            application:set_env(kernel,logger_sasl_compatible,X);
52        undefined ->
53            application:unset_env(kernel,logger_sasl_compatible)
54    end.
55
56init_per_group(_GroupName, Config) ->
57    Config.
58
59end_per_group(_GroupName, Config) ->
60    Config.
61
62
63init_per_testcase(_Case, Config) ->
64    Config.
65end_per_testcase(_Case, _Config) ->
66    ok.
67
68app_test(Config) when is_list(Config) ->
69    test_server:app_test(sasl, allow),
70    ok.
71
72%% Test that appup allows upgrade from/downgrade to a maximum of one
73%% major release back.
74appup_test(_Config) ->
75    appup_tests(sasl,create_test_vsns(sasl)).
76
77appup_tests(_App,{[],[]}) ->
78    {skip,"no previous releases available"};
79appup_tests(App,{OkVsns0,NokVsns}) ->
80    application:load(App),
81    {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()),
82    AppupFileName = atom_to_list(App) ++ ".appup",
83    AppupFile = filename:join([code:lib_dir(App),ebin,AppupFileName]),
84    {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile),
85    ct:log("~p~n",[AppupScript]),
86    OkVsns =
87	case OkVsns0 -- [Vsn] of
88	    OkVsns0 ->
89		OkVsns0;
90	    Ok ->
91		ct:log("Current version, ~p, is same as in previous release.~n"
92		       "Removing this from the list of ok versions.",
93		      [Vsn]),
94		Ok
95	end,
96    ct:log("Testing that appup allows upgrade from these versions: ~p~n",
97	   [OkVsns]),
98    check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}),
99    check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}),
100    ct:log("Testing that appup does not allow upgrade from these versions: ~p~n",
101	   [NokVsns]),
102    check_appup(NokVsns,UpFrom,error),
103    check_appup(NokVsns,DownTo,error),
104    ok.
105
106create_test_vsns(App) ->
107    ThisMajor = erlang:system_info(otp_release),
108    FirstMajor = previous_major(ThisMajor),
109    SecondMajor = previous_major(previous_major(FirstMajor)),
110    Ok = app_vsn(App,[ThisMajor,FirstMajor]),
111    Nok0 = app_vsn(App,[SecondMajor]),
112    Nok = case Ok of
113	       [Ok1|_] ->
114		   [Ok1 ++ ",1" | Nok0]; % illegal
115	       _ ->
116		   Nok0
117	   end,
118    {Ok,Nok}.
119
120previous_major("17") ->
121    "r16b";
122previous_major("r16b") ->
123    "r15b";
124previous_major(Rel) ->
125    integer_to_list(list_to_integer(Rel)-1).
126
127app_vsn(App,[R|Rs]) ->
128    OldRel =
129	case test_server:is_release_available(R) of
130	    true ->
131		{release,R};
132	    false ->
133		case ct:get_config({otp_releases,list_to_atom(R)}) of
134		    undefined ->
135			false;
136		    Prog0 ->
137			case os:find_executable(Prog0) of
138			    false ->
139				false;
140			    Prog ->
141				{prog,Prog}
142			end
143		end
144	end,
145    case OldRel of
146	false ->
147	    app_vsn(App,Rs);
148	_ ->
149	    {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]),
150	    _ = rpc:call(N,application,load,[App]),
151	    As = rpc:call(N,application,loaded_applications,[]),
152	    {_,_,V} = lists:keyfind(App,1,As),
153	    test_server:stop_node(N),
154	    [V|app_vsn(App,Rs)]
155    end;
156app_vsn(_App,[]) ->
157    [].
158
159check_appup([Vsn|Vsns],Instrs,Expected) ->
160    case systools_relup:appup_search_for_version(Vsn, Instrs) of
161	Expected -> check_appup(Vsns,Instrs,Expected);
162	Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other})
163    end;
164check_appup([],_,_) ->
165    ok.
166
167
168%% OTP-9185 - fail sasl start if some but not all log_mf_h env vars
169%% are given.
170log_mf_h_env(Config) ->
171    PrivDir = ?config(priv_dir,Config),
172    LogDir = filename:join(PrivDir,sasl_SUITE_log_dir),
173    ok = filelib:ensure_dir(LogDir),
174    application:stop(sasl),
175    clear_env(sasl),
176
177    ok = application:set_env(sasl,error_logger_mf_dir,LogDir),
178    match_error(missing_config,application:start(sasl)),
179
180    ok = application:set_env(sasl,error_logger_mf_maxbytes,"xx"),
181    match_error(bad_config,application:start(sasl)),
182
183    ok = application:set_env(sasl,error_logger_mf_maxbytes,50000),
184    match_error(missing_config,application:start(sasl)),
185
186    ok = application:set_env(sasl,error_logger_mf_maxfiles,"xx"),
187    match_error(bad_config,application:start(sasl)),
188
189    ok = application:set_env(sasl,error_logger_mf_maxfiles,2),
190    ok = application:unset_env(sasl,error_logger_mf_dir),
191    match_error(missing_config,application:start(sasl)),
192
193    ok = application:set_env(sasl,error_logger_mf_dir,xx),
194    match_error(bad_config,application:start(sasl)),
195
196    ok = application:set_env(sasl,error_logger_mf_dir,LogDir),
197    ok = application:start(sasl).
198
199log_file(Config) ->
200    PrivDir = ?config(priv_dir,Config),
201    LogDir  = filename:join(PrivDir,sasl_SUITE_log_dir),
202    File    = filename:join(LogDir, "file.log"),
203    ok      = filelib:ensure_dir(File),
204    application:stop(sasl),
205    clear_env(sasl),
206
207    _ = test_log_file(File, {file,File}),
208    _ = test_log_file(File, {file,File,[write]}),
209
210    ok = file:write_file(File, <<"=PROGRESS preserve me\n">>),
211    <<"=PROGRESS preserve me\n",_/binary>> =
212	test_log_file(File, {file,File,[append]}),
213
214    ok = application:set_env(sasl,sasl_error_logger, tty,
215			     [{persistent, false}]),
216    ok = application:start(sasl).
217
218test_log_file(File, Arg) ->
219    ok = application:set_env(sasl, sasl_error_logger, Arg,
220			     [{persistent, true}]),
221    ok = application:start(sasl),
222    application:stop(sasl),
223    {ok,Bin} = file:read_file(File),
224    ok = file:delete(File),
225    Lines0 = binary:split(Bin, <<"\n">>, [trim_all,global]),
226    Lines = [L || L <- Lines0,
227		  binary:match(L, <<"=PROGRESS">>) =:= {0,9}],
228    io:format("~p:\n~p\n", [Arg,Lines]),
229
230    %% There must be at least four PROGRESS lines.
231    if
232	length(Lines) >= 4 -> ok;
233	true -> ct:fail({progress, Lines})
234    end,
235    Bin.
236
237%% Make a basic test of utc_log.
238utc_log(Config) ->
239    PrivDir = ?config(priv_dir, Config),
240    LogDir = filename:join(PrivDir, sasl_SUITE_log_dir),
241    Log = filename:join(LogDir, "utc.log"),
242    ok = filelib:ensure_dir(Log),
243
244    application:stop(sasl),
245    clear_env(sasl),
246
247    %% Test that the UTC marker gets added to PROGRESS lines
248    %% when the utc_log configuration variable is set to true.
249    ok = application:set_env(sasl, sasl_error_logger, {file,Log},
250			     [{persistent,true}]),
251    ok = application:set_env(sasl, utc_log, true, [{persistent,true}]),
252    ok = application:start(sasl),
253    application:stop(sasl),
254
255    verify_utc_log(Log, true),
256
257    %% Test that no UTC markers gets added to PROGRESS lines
258    %% when the utc_log configuration variable is set to false.
259    ok = application:set_env(sasl, utc_log, false, [{persistent,true}]),
260    ok = application:start(sasl),
261    application:stop(sasl),
262
263    verify_utc_log(Log, false),
264
265    %% Test that no UTC markers gets added to PROGRESS lines
266    %% when the utc_log configuration variable is unset.
267    ok = application:unset_env(sasl, utc_log, [{persistent,true}]),
268    ok = application:start(sasl),
269    application:stop(sasl),
270
271    verify_utc_log(Log, false),
272
273    %% Change back to the standard TTY error logger.
274    ok = application:set_env(sasl,sasl_error_logger, tty,
275			     [{persistent, false}]),
276    ok = application:start(sasl).
277
278verify_utc_log(Log, UTC) ->
279    {ok,Bin} = file:read_file(Log),
280    ok = file:delete(Log),
281
282    Lines0 = binary:split(Bin, <<"\n">>, [trim_all,global]),
283    Lines = [L || L <- Lines0,
284		  binary:match(L, <<"=PROGRESS">>) =:= {0,9}],
285    Setting = application:get_env(sasl, utc_log),
286    io:format("utc_log ~p:\n~p\n", [Setting,Lines]),
287    Filtered = [L || L <- Lines,
288		     binary:match(L, <<" UTC ===">>) =:= nomatch],
289    %% Filtered now contains all lines WITHOUT any UTC markers.
290    case UTC of
291	false ->
292	    %% No UTC marker on the PROGRESS line.
293	    Filtered = Lines;
294	true ->
295	    %% Each PROGRESS line must have an UTC marker.
296	    [] = Filtered
297    end,
298    ok.
299
300
301%%-----------------------------------------------------------------
302%% Internal
303match_error(Expected,{error,{bad_return,{_,{'EXIT',{Expected,{sasl,_}}}}}}) ->
304    ok;
305match_error(Expected,Actual) ->
306    ct:fail({unexpected_return,Expected,Actual}).
307
308clear_env(App) ->
309    [application:unset_env(App,Opt) || {Opt,_} <- application:get_all_env(App)],
310    ok.
311