summaryrefslogtreecommitdiff
path: root/src/couch/test/eunit/couch_file_tests.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch/test/eunit/couch_file_tests.erl')
-rw-r--r--src/couch/test/eunit/couch_file_tests.erl137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/couch/test/eunit/couch_file_tests.erl b/src/couch/test/eunit/couch_file_tests.erl
index 1b54cd70e..fbe23ded7 100644
--- a/src/couch/test/eunit/couch_file_tests.erl
+++ b/src/couch/test/eunit/couch_file_tests.erl
@@ -551,3 +551,140 @@ fake_fsync_fd() ->
{'$gen_call', From, sync} ->
gen:reply(From, {error, eio})
end.
+
+checksum_test_() ->
+ {
+ foreach,
+ fun setup_checksum/0,
+ fun teardown_checksum/1,
+ [
+ ?TDEF_FE(t_write_read_xxhash_checksums),
+ ?TDEF_FE(t_downgrade_xxhash_checksums),
+ ?TDEF_FE(t_read_legacy_checksums_after_upgrade)
+ ]
+ }.
+
+setup_checksum() ->
+ Path = ?tempfile(),
+ Ctx = test_util:start_couch(),
+ config:set("couchdb", "write_xxhash_checksums", "false", _Persist = false),
+ {Ctx, Path}.
+
+teardown_checksum({Ctx, Path}) ->
+ file:delete(Path),
+ meck:unload(),
+ test_util:stop_couch(Ctx),
+ couch_file:reset_checksum_persistent_term_config().
+
+t_write_read_xxhash_checksums({_Ctx, Path}) ->
+ enable_xxhash(),
+
+ {ok, Fd} = couch_file:open(Path, [create]),
+ Header = header,
+ ok = couch_file:write_header(Fd, Header),
+ Bin = <<"bin">>,
+ Chunk = couch_file:assemble_file_chunk_and_checksum(Bin),
+ {ok, Pos, _} = couch_file:append_raw_chunk(Fd, Chunk),
+ couch_file:close(Fd),
+
+ {ok, Fd1} = couch_file:open(Path, []),
+ {ok, Header1} = couch_file:read_header(Fd1),
+ ?assertEqual(Header, Header1),
+ {ok, Bin1} = couch_file:pread_binary(Fd1, Pos),
+ ?assertEqual(Bin, Bin1),
+ ?assertEqual(0, legacy_stats()),
+ couch_file:close(Fd1).
+
+t_downgrade_xxhash_checksums({_Ctx, Path}) ->
+ % We're in the future and writting xxhash checkums by default
+ enable_xxhash(),
+ {ok, Fd} = couch_file:open(Path, [create]),
+ Header = header,
+ ok = couch_file:write_header(Fd, Header),
+ Bin = <<"bin">>,
+ Chunk = couch_file:assemble_file_chunk_and_checksum(Bin),
+ {ok, Pos, _} = couch_file:append_raw_chunk(Fd, Chunk),
+ couch_file:close(Fd),
+
+ % The future was broken, we travel back, but still know how to
+ % interpret future checksums without crashing
+ disable_xxhash(),
+ {ok, Fd1} = couch_file:open(Path, []),
+ {ok, Header1} = couch_file:read_header(Fd1),
+ ?assertEqual(Header, Header1),
+ {ok, Bin1} = couch_file:pread_binary(Fd1, Pos),
+ ?assertEqual(Bin, Bin1),
+
+ % We'll write some legacy checksums to the file and then ensure
+ % we can read both legacy and the new ones
+ OtherBin = <<"otherbin">>,
+ OtherChunk = couch_file:assemble_file_chunk_and_checksum(OtherBin),
+ {ok, OtherPos, _} = couch_file:append_raw_chunk(Fd1, OtherChunk),
+ couch_file:close(Fd1),
+
+ {ok, Fd2} = couch_file:open(Path, []),
+ {ok, Header2} = couch_file:read_header(Fd2),
+ ?assertEqual(Header, Header2),
+ {ok, Bin2} = couch_file:pread_binary(Fd2, Pos),
+ {ok, OtherBin1} = couch_file:pread_binary(Fd2, OtherPos),
+ ?assertEqual(Bin, Bin2),
+ ?assertEqual(OtherBin, OtherBin1),
+ couch_file:close(Fd2).
+
+t_read_legacy_checksums_after_upgrade({_Ctx, Path}) ->
+ % We're in the past and writting legacy checkums by default
+ disable_xxhash(),
+ {ok, Fd} = couch_file:open(Path, [create]),
+ Header = header,
+ ok = couch_file:write_header(Fd, Header),
+ Bin = <<"bin">>,
+ Chunk = couch_file:assemble_file_chunk_and_checksum(Bin),
+ {ok, Pos, _} = couch_file:append_raw_chunk(Fd, Chunk),
+ couch_file:close(Fd),
+
+ % We upgrade and xxhash checksums are not the default, but we can
+ % still read legacy checksums.
+ enable_xxhash(),
+ {ok, Fd1} = couch_file:open(Path, []),
+ {ok, Header1} = couch_file:read_header(Fd1),
+ ?assertEqual(Header, Header1),
+ {ok, Bin1} = couch_file:pread_binary(Fd1, Pos),
+ ?assertEqual(Bin, Bin1),
+ % one header, one chunk
+ ?assertEqual(2, legacy_stats()),
+
+ % We'll write some new checksums to the file and then ensure
+ % we can read both legacy and the new ones
+ OtherBin = <<"otherbin">>,
+ OtherChunk = couch_file:assemble_file_chunk_and_checksum(OtherBin),
+ {ok, OtherPos, _} = couch_file:append_raw_chunk(Fd1, OtherChunk),
+ couch_file:close(Fd1),
+
+ couch_stats:decrement_counter([couchdb, legacy_checksums], legacy_stats()),
+ {ok, Fd2} = couch_file:open(Path, []),
+ {ok, Header2} = couch_file:read_header(Fd2),
+ ?assertEqual(Header, Header2),
+ {ok, Bin2} = couch_file:pread_binary(Fd2, Pos),
+ {ok, OtherBin1} = couch_file:pread_binary(Fd2, OtherPos),
+ ?assertEqual(Bin, Bin2),
+ ?assertEqual(OtherBin, OtherBin1),
+ % one header, legacy chunk, not counting new chunk
+ ?assertEqual(2, legacy_stats()),
+ couch_file:close(Fd2).
+
+enable_xxhash() ->
+ couch_file:reset_checksum_persistent_term_config(),
+ reset_legacy_checksum_stats(),
+ config:set("couchdb", "write_xxhash_checksums", "true", _Persist = false).
+
+disable_xxhash() ->
+ couch_file:reset_checksum_persistent_term_config(),
+ reset_legacy_checksum_stats(),
+ config:set("couchdb", "write_xxhash_checksums", "false", _Persist = false).
+
+legacy_stats() ->
+ couch_stats:sample([couchdb, legacy_checksums]).
+
+reset_legacy_checksum_stats() ->
+ Counter = couch_stats:sample([couchdb, legacy_checksums]),
+ couch_stats:decrement_counter([couchdb, legacy_checksums], Counter).