%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1997-2018. All Rights Reserved. %% %% 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 %% %% 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% -module(efile_SUITE). -export([all/0, suite/0]). -export([iter_max_files/1, proc_zero_sized_files/1]). -export([do_iter_max_files/2]). -include_lib("common_test/include/ct.hrl"). -include_lib("stdlib/include/assert.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [iter_max_files, proc_zero_sized_files]. %% %% Open as many files as possible. Do this several times and check %% that we get the same number of files every time. %% iter_max_files(Config) when is_list(Config) -> case os:type() of {win32, _} -> {skip, "Windows lacks a hard limit on file handles"}; _ -> iter_max_files_1(Config) end. iter_max_files_1(Config) -> DataDir = proplists:get_value(data_dir,Config), TestFile = filename:join(DataDir, "existing_file"), case erlang:system_info(debug_compiled) of true -> N = 5; false -> N = 10 end, %% Run on a different node in order to make the test more stable. Dir = filename:dirname(code:which(?MODULE)), {ok,Node} = test_server:start_node(test_iter_max_files,slave, [{args,"-pa " ++ Dir}]), L = rpc:call(Node,?MODULE,do_iter_max_files,[N, TestFile]), test_server:stop_node(Node), io:format("Number of files opened in each test:~n~w\n", [L]), verify_max_files(L), Head = hd(L), if Head >= 2 -> ok; true -> ct:fail(too_few_files) end, {comment, "Max files: " ++ integer_to_list(hd(L))}. do_iter_max_files(N, Name) when N > 0 -> [max_files(Name)| do_iter_max_files(N-1, Name)]; do_iter_max_files(_, _) -> []. %% The attempts shouldn't vary too much; we used to require that they were all %% exactly equal, but after we reimplemented the file driver as a NIF we %% noticed that the only reason it was stable on Darwin was because the port %% limit was hit before ulimit. verify_max_files(Attempts) -> N = length(Attempts), Mean = lists:sum(Attempts) / N, Variance = lists:sum([(X - Mean) * (X - Mean) || X <- Attempts]) / N, true = math:sqrt(Variance) =< 1 + (Mean / 1000). max_files(Name) -> Fds = open_files(Name), N = length(Fds), close_files(Fds), N. close_files([Fd| Fds]) -> file:close(Fd), close_files(Fds); close_files([]) -> ok. open_files(Name) -> case file:open(Name, [read,raw]) of {ok, Fd} -> [Fd| open_files(Name)]; {error, _Reason} -> % io:format("Error reason: ~p", [_Reason]), [] end. %% @doc If /proc filesystem exists (no way to know if it is real proc or just %% a /proc directory), let's read some zero sized files 500 times each, while %% ensuring that response isn't empty << >> proc_zero_sized_files(Config) when is_list(Config) -> TestFiles0 = [%% Some files which exist on Linux but might be missing on %% other systems "/proc/cpuinfo", "/proc/meminfo", "/proc/partitions", "/proc/swaps", "/proc/version", "/proc/uptime", %% curproc is present on FreeBSD "/proc/curproc/cmdline"], TestFiles = [F || F <- TestFiles0, filelib:is_file(F)], case TestFiles of [_|_] -> %% For 6 inputs and 500 attempts each this do run anywhere %% between 500 and 3000 function calls. [do_proc_zero_sized(F, 500) || F <- TestFiles], ok; [] -> {skip, "Failed to find any known zero-sized files"} end. %% @doc Test one file N times to also trigger possible leaking fds and memory do_proc_zero_sized(_Filename, 0) -> ok; do_proc_zero_sized(Filename, N) -> Data = file:read_file(Filename), ?assertNotEqual(<<>>, Data), do_proc_zero_sized(Filename, N-1).