Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
To run these tests: $ git clone git://github.com/ngerakines/etap.git $ cd etap $ sudo make install $ cd /path/to/couchdb $ ./bootstrap && ./configure && make check So far I've worked through most of couch_file.erl, couch_btree.erl, and couch_doc.erl. Tomorrow I'll be adding coverage reporting so that we can see what code we're actually testing. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@780197 13f79535-47bb-0310-9956-ffa450edef68
- Loading branch information
Showing
8 changed files
with
959 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/usr/bin/env escript | ||
%% -*- erlang -*- | ||
%%! -pa src/couchdb -sasl errlog_type error -boot start_sasl -noshell | ||
|
||
% Test that we can load each module. | ||
|
||
main(_) -> | ||
etap:plan(39), | ||
Modules = [ | ||
couch_batch_save, | ||
couch_batch_save_sup, | ||
couch_btree, | ||
couch_config, | ||
couch_config_writer, | ||
couch_db, | ||
couch_db_update_notifier, | ||
couch_db_update_notifier_sup, | ||
couch_db_updater, | ||
couch_doc, | ||
couch_event_sup, | ||
couch_external_manager, | ||
couch_external_server, | ||
couch_file, | ||
couch_httpd, | ||
couch_httpd_db, | ||
couch_httpd_external, | ||
couch_httpd_misc_handlers, | ||
couch_httpd_show, | ||
couch_httpd_stats_handlers, | ||
couch_httpd_view, | ||
couch_key_tree, | ||
couch_log, | ||
couch_os_process, | ||
couch_query_servers, | ||
couch_ref_counter, | ||
couch_rep, | ||
couch_rep_sup, | ||
couch_server, | ||
couch_server_sup, | ||
couch_stats_aggregator, | ||
couch_stats_collector, | ||
couch_stream, | ||
couch_task_status, | ||
couch_util, | ||
couch_view, | ||
couch_view_compactor, | ||
couch_view_group, | ||
couch_view_updater | ||
], | ||
|
||
lists:foreach( | ||
fun(Module) -> | ||
etap_can:loaded_ok( | ||
Module, | ||
lists:concat(["Loaded: ", Module]) | ||
) | ||
end, Modules), | ||
etap:end_tests(). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
#!/usr/bin/env escript | ||
%% -*- erlang -*- | ||
%%! -pa ./src/couchdb -sasl errlog_type error -boot start_sasl -noshell | ||
|
||
-define(FILE_NAME, "./t/temp.010"). | ||
|
||
main(_) -> | ||
etap:plan(16), | ||
case (catch test()) of | ||
ok -> | ||
etap:end_tests(); | ||
Other -> | ||
etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), | ||
etap:bail() | ||
end, | ||
ok. | ||
|
||
test() -> | ||
etap:is({error, enoent}, couch_file:open("not a real file"), | ||
"Opening a non-existant file should return an enoent error."), | ||
|
||
etap:fun_is( | ||
fun({ok, _}) -> true; (_) -> false end, | ||
couch_file:open(?FILE_NAME ++ ".1", [create, invalid_option]), | ||
"Invalid flags to open are ignored." | ||
), | ||
|
||
{ok, Fd} = couch_file:open(?FILE_NAME ++ ".0", [create, overwrite]), | ||
etap:ok(is_pid(Fd), | ||
"Returned file descriptor is a Pid"), | ||
|
||
etap:is({ok, 0}, couch_file:bytes(Fd), | ||
"Newly created files have 0 bytes."), | ||
|
||
etap:is({ok, 0}, couch_file:append_term(Fd, foo), | ||
"Appending a term returns the previous end of file position."), | ||
|
||
{ok, Size} = couch_file:bytes(Fd), | ||
etap:is_greater(Size, 0, | ||
"Writing a term increased the file size."), | ||
|
||
etap:is({ok, Size}, couch_file:append_binary(Fd, <<"fancy!">>), | ||
"Appending a binary returns the current file size."), | ||
|
||
etap:is({ok, foo}, couch_file:pread_term(Fd, 0), | ||
"Reading the first term returns what we wrote: foo"), | ||
|
||
etap:is({ok, <<"fancy!">>}, couch_file:pread_binary(Fd, Size), | ||
"Reading back the binary returns what we wrote: <<\"fancy\">>."), | ||
|
||
etap:is({ok, <<131, 100, 0, 3, 102, 111, 111>>}, | ||
couch_file:pread_binary(Fd, 0), | ||
"Reading a binary at a term position returns the term as binary." | ||
), | ||
|
||
{ok, BinPos} = couch_file:append_binary(Fd, <<131,100,0,3,102,111,111>>), | ||
etap:is({ok, foo}, couch_file:pread_term(Fd, BinPos), | ||
"Reading a term from a written binary term representation succeeds."), | ||
|
||
% append_binary == append_iolist? | ||
% Possible bug in pread_iolist or iolist() -> append_binary | ||
{ok, IOLPos} = couch_file:append_binary(Fd, ["foo", $m, <<"bam">>]), | ||
etap:is({ok, [<<"foombam">>]}, couch_file:pread_iolist(Fd, IOLPos), | ||
"Reading an results in a binary form of the written iolist()"), | ||
|
||
% XXX: How does on test fsync? | ||
etap:is(ok, couch_file:sync(Fd), | ||
"Syncing does not cause an error."), | ||
|
||
etap:is(ok, couch_file:truncate(Fd, Size), | ||
"Truncating a file succeeds."), | ||
|
||
%etap:is(eof, (catch couch_file:pread_binary(Fd, Size)), | ||
% "Reading data that was truncated fails.") | ||
etap:skip(fun() -> ok end, | ||
"No idea how to test reading beyond EOF"), | ||
|
||
etap:is({ok, foo}, couch_file:pread_term(Fd, 0), | ||
"Truncating does not affect data located before the truncation mark."), | ||
|
||
etap:is(ok, couch_file:close(Fd), | ||
"Files close properly."), | ||
ok. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
#!/usr/bin/env escript | ||
%% -*- erlang -*- | ||
%%! -pa ./src/couchdb -sasl errlog_type error -boot start_sasl -noshell | ||
|
||
-define(FILE_NAME, "./t/temp.011"). | ||
-define(SIZE_BLOCK, 4096). % Need to keep this in sync with couch_file.erl | ||
|
||
main(_) -> | ||
{S1, S2, S3} = now(), | ||
random:seed(S1, S2, S3), | ||
|
||
etap:plan(17), | ||
case (catch test()) of | ||
ok -> | ||
etap:end_tests(); | ||
Other -> | ||
etap:diag(io_lib:format("Test died abnormally: ~p", [Other])), | ||
etap:bail() | ||
end, | ||
ok. | ||
|
||
test() -> | ||
{ok, Fd} = couch_file:open(?FILE_NAME, [create,overwrite]), | ||
|
||
etap:is({ok, 0}, couch_file:bytes(Fd), | ||
"File should be initialized to contain zero bytes."), | ||
|
||
etap:is(ok, couch_file:write_header(Fd, {<<"some_data">>, 32}), | ||
"Writing a header succeeds."), | ||
|
||
{ok, Size1} = couch_file:bytes(Fd), | ||
etap:is_greater(Size1, 0, | ||
"Writing a header allocates space in the file."), | ||
|
||
etap:is({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd), | ||
"Reading the header returns what we wrote."), | ||
|
||
etap:is(ok, couch_file:write_header(Fd, [foo, <<"more">>]), | ||
"Writing a second header succeeds."), | ||
|
||
{ok, Size2} = couch_file:bytes(Fd), | ||
etap:is_greater(Size2, Size1, | ||
"Writing a second header allocates more space."), | ||
|
||
etap:is({ok, [foo, <<"more">>]}, couch_file:read_header(Fd), | ||
"Reading the second header does not return the first header."), | ||
|
||
% Delete the second header. | ||
ok = couch_file:truncate(Fd, Size1), | ||
|
||
etap:is({ok, {<<"some_data">>, 32}}, couch_file:read_header(Fd), | ||
"Reading the header after a truncation returns a previous header."), | ||
|
||
couch_file:write_header(Fd, [foo, <<"more">>]), | ||
etap:is({ok, Size2}, couch_file:bytes(Fd), | ||
"Rewriting the same second header returns the same second size."), | ||
|
||
ok = couch_file:close(Fd), | ||
|
||
% Now for the fun stuff. Try corrupting the second header and see | ||
% if we recover properly. | ||
|
||
% Destroy the 0x1 byte that marks a header | ||
check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> | ||
etap:isnt(Expect, couch_file:read_header(CouchFd), | ||
"Should return a different header before corruption."), | ||
file:pwrite(RawFd, HeaderPos, <<0>>), | ||
etap:is(Expect, couch_file:read_header(CouchFd), | ||
"Corrupting the byte marker should read the previous header.") | ||
end), | ||
|
||
% Corrupt the size. | ||
check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> | ||
etap:isnt(Expect, couch_file:read_header(CouchFd), | ||
"Should return a different header before corruption."), | ||
% +1 for 0x1 byte marker | ||
file:pwrite(RawFd, HeaderPos+1, <<10/integer>>), | ||
etap:is(Expect, couch_file:read_header(CouchFd), | ||
"Corrupting the size should read the previous header.") | ||
end), | ||
|
||
% Corrupt the MD5 signature | ||
check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> | ||
etap:isnt(Expect, couch_file:read_header(CouchFd), | ||
"Should return a different header before corruption."), | ||
% +5 = +1 for 0x1 byte and +4 for term size. | ||
file:pwrite(RawFd, HeaderPos+5, <<"F01034F88D320B22">>), | ||
etap:is(Expect, couch_file:read_header(CouchFd), | ||
"Corrupting the MD5 signature should read the previous header.") | ||
end), | ||
|
||
% Corrupt the data | ||
check_header_recovery(fun(CouchFd, RawFd, Expect, HeaderPos) -> | ||
etap:isnt(Expect, couch_file:read_header(CouchFd), | ||
"Should return a different header before corruption."), | ||
% +21 = +1 for 0x1 byte, +4 for term size and +16 for MD5 sig | ||
file:pwrite(RawFd, HeaderPos+21, <<"some data goes here!">>), | ||
etap:is(Expect, couch_file:read_header(CouchFd), | ||
"Corrupting the header data should read the previous header.") | ||
end), | ||
|
||
ok. | ||
|
||
check_header_recovery(CheckFun) -> | ||
{ok, Fd} = couch_file:open(?FILE_NAME, [create,overwrite]), | ||
{ok, RawFd} = file:open(?FILE_NAME, [read, write, raw, binary]), | ||
|
||
{ok, _} = write_random_data(Fd), | ||
ExpectHeader = {some_atom, <<"a binary">>, 756}, | ||
ok = couch_file:write_header(Fd, ExpectHeader), | ||
|
||
{ok, HeaderPos} = write_random_data(Fd), | ||
ok = couch_file:write_header(Fd, {2342, <<"corruption! greed!">>}), | ||
|
||
CheckFun(Fd, RawFd, {ok, ExpectHeader}, HeaderPos), | ||
|
||
ok = file:close(RawFd), | ||
ok = couch_file:close(Fd), | ||
ok. | ||
|
||
write_random_data(Fd) -> | ||
write_random_data(Fd, 100 + random:uniform(1000)). | ||
|
||
write_random_data(Fd, 0) -> | ||
{ok, Bytes} = couch_file:bytes(Fd), | ||
{ok, (1 + Bytes div ?SIZE_BLOCK) * ?SIZE_BLOCK}; | ||
write_random_data(Fd, N) -> | ||
Choices = [foo, bar, <<"bizzingle">>, "bank", ["rough", stuff]], | ||
Term = lists:nth(random:uniform(4) + 1, Choices), | ||
{ok, _} = couch_file:append_term(Fd, Term), | ||
write_random_data(Fd, N-1). | ||
|
||
|
Oops, something went wrong.