blob: ba042610ae2a17d7abbf3f7a4d4717f5437fc05a [file] [log] [blame]
% 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.
-module(couch_log_writer_file_test).
-include_lib("kernel/include/file.hrl").
-include_lib("couch_log/include/couch_log.hrl").
-include_lib("eunit/include/eunit.hrl").
-define(WRITER, couch_log_writer_file).
couch_log_writer_file_test_() ->
{setup,
fun couch_log_test_util:start/0,
fun couch_log_test_util:stop/1,
[
fun check_init_terminate/0,
fun() ->
couch_log_test_util:with_meck(
[{filelib, [unstick]}],
fun check_ensure_dir_fail/0
)
end,
fun() ->
couch_log_test_util:with_meck(
[{file, [unstick, passthrough]}],
fun check_open_fail/0
)
end,
fun() ->
couch_log_test_util:with_meck(
[{file, [unstick, passthrough]}],
fun check_read_file_info_fail/0
)
end,
fun check_file_write/0,
fun check_buffered_file_write/0,
fun check_reopen/0
]
}.
check_init_terminate() ->
{ok, St} = ?WRITER:init(),
ok = ?WRITER:terminate(stop, St).
check_ensure_dir_fail() ->
meck:expect(filelib, ensure_dir, 1, {error, eperm}),
?assertEqual({error, eperm}, ?WRITER:init()),
?assert(meck:called(filelib, ensure_dir, 1)),
?assert(meck:validate(filelib)).
check_open_fail() ->
meck:expect(file, open, 2, {error, enotfound}),
?assertEqual({error, enotfound}, ?WRITER:init()),
?assert(meck:called(file, open, 2)),
?assert(meck:validate(file)).
check_read_file_info_fail() ->
RFI = fun
("./couch.log") -> {error, enoent};
(Path) -> meck:passthrough([Path])
end,
meck:expect(file, read_file_info, RFI),
?assertEqual({error, enoent}, ?WRITER:init()),
?assert(meck:called(file, read_file_info, 1)),
?assert(meck:validate(file)).
check_file_write() ->
% Make sure we have an empty log for this test
IsFile = filelib:is_file("./couch.log"),
if not IsFile -> ok; true ->
file:delete("./couch.log")
end,
Entry = #log_entry{
level = info,
pid = list_to_pid("<0.1.0>"),
msg = "stuff",
msg_id = "msg_id",
time_stamp = "time_stamp"
},
{ok, St} = ?WRITER:init(),
{ok, NewSt} = ?WRITER:write(Entry, St),
ok = ?WRITER:terminate(stop, NewSt),
{ok, Data} = file:read_file("./couch.log"),
Expect = <<"[info] time_stamp nonode@nohost <0.1.0> msg_id stuff\n">>,
?assertEqual(Expect, Data).
check_buffered_file_write() ->
% Make sure we have an empty log for this test
IsFile = filelib:is_file("./couch.log"),
if not IsFile -> ok; true ->
file:delete("./couch.log")
end,
config:set("log", "write_buffer", "1024"),
config:set("log", "write_delay", "10"),
try
Entry = #log_entry{
level = info,
pid = list_to_pid("<0.1.0>"),
msg = "stuff",
msg_id = "msg_id",
time_stamp = "time_stamp"
},
{ok, St} = ?WRITER:init(),
{ok, NewSt} = ?WRITER:write(Entry, St),
ok = ?WRITER:terminate(stop, NewSt)
after
config:delete("log", "write_buffer"),
config:delete("log", "write_delay")
end,
{ok, Data} = file:read_file("./couch.log"),
Expect = <<"[info] time_stamp nonode@nohost <0.1.0> msg_id stuff\n">>,
?assertEqual(Expect, Data).
check_reopen() ->
{ok, St1} = clear_clock(?WRITER:init()),
{ok, St2} = clear_clock(couch_log_writer_file:maybe_reopen(St1)),
?assertEqual(St1, St2),
case os:type() of
{win32, _} ->
% Windows file handling doesn't work the same
% as Unix where you can move or delete an open
% file so these tests make no sense there.
yay_we_pass;
_ ->
% Delete file
file:delete("./couch.log"),
{ok, St3} = clear_clock(couch_log_writer_file:maybe_reopen(St2)),
?assert(element(3, St3) /= element(3, St2)),
% Recreate file
file:delete("./couch.log"),
file:write_file("./couch.log", ""),
{ok, St4} = clear_clock(couch_log_writer_file:maybe_reopen(St3)),
?assert(element(3, St4) /= element(3, St2))
end.
clear_clock({ok, St}) ->
{ok, clear_clock(St)};
clear_clock(St) ->
{st, Path, Fd, INode, _} = St,
{st, Path, Fd, INode, {0, 0, 0}}.