blob: b113c53924fd578e8eb1ddadda571fcc13597ad4 [file] [log] [blame]
-module(couch_replicator_small_max_request_size_target).
-include_lib("couch/include/couch_eunit.hrl").
-include_lib("couch/include/couch_db.hrl").
-include_lib("fabric/test/fabric2_test.hrl").
reduce_max_request_size_test_() ->
{
"Replicate docs when target has a small max_http_request_size",
{
setup,
fun couch_replicator_test_helper:start_couch/0,
fun couch_replicator_test_helper:stop_couch/1,
{
foreach,
fun setup/0,
fun teardown/1,
[
?TDEF_FE(should_replicate_all_docs, 120),
?TDEF_FE(should_replicate_one, 120),
?TDEF_FE(should_replicate_one_with_attachment, 120)
]
}
}
}.
setup() ->
Source = couch_replicator_test_helper:create_db(),
Target = couch_replicator_test_helper:create_db(),
config:set("httpd", "max_http_request_size", "10000", false),
{Source, Target}.
teardown({Source, Target}) ->
config:delete("httpd", "max_http_request_size", false),
couch_replicator_test_helper:delete_db(Source),
couch_replicator_test_helper:delete_db(Target).
% Test documents which are below max_http_request_size but when batched, batch
% size will be greater than max_http_request_size. Replicator could
% automatically split the batch into smaller batches and POST those separately.
should_replicate_all_docs({Source, Target}) ->
?assertEqual(ok, add_docs(Source, 5, 3000, 0)),
replicate(Source, Target),
compare_dbs(Source, Target, []).
% If a document is too large to post as a single request, that document is
% skipped but replication overall will make progress and not crash.
should_replicate_one({Source, Target}) ->
?assertEqual(ok, one_large_one_small(Source, 12000, 3000)),
replicate(Source, Target),
compare_dbs(Source, Target, [<<"doc0">>]).
% If a document has an attachment > 64 * 1024 bytes, replicator will switch to
% POST-ing individual documents directly and skip bulk_docs. Test that case
% separately See note in main test function why this was disabled.
should_replicate_one_with_attachment({Source, Target}) ->
?assertEqual(ok, one_large_attachment(Source, 70000, 70000)),
?assertEqual(ok, add_docs(Source, 5, 3000, 0)),
replicate(Source, Target),
compare_dbs(Source, Target, [<<"doc0">>]).
binary_chunk(Size) when is_integer(Size), Size > 0 ->
<< <<"x">> || _ <- lists:seq(1, Size) >>.
add_docs(DbName, DocCount, DocSize, AttSize) ->
[begin
DocId = iolist_to_binary(["doc", integer_to_list(Id)]),
add_doc(DbName, DocId, DocSize, AttSize)
end || Id <- lists:seq(1, DocCount)],
ok.
one_large_one_small(DbName, Large, Small) ->
add_doc(DbName, <<"doc0">>, Large, 0),
add_doc(DbName, <<"doc1">>, Small, 0),
ok.
one_large_attachment(DbName, Size, AttSize) ->
add_doc(DbName, <<"doc0">>, Size, AttSize),
ok.
add_doc(DbName, DocId, Size, AttSize) when is_binary(DocId) ->
{ok, Db} = fabric2_db:open(DbName, [?ADMIN_CTX]),
Doc0 = #doc{id = DocId, body = {[{<<"x">>, binary_chunk(Size)}]}},
Doc = Doc0#doc{atts = atts(AttSize)},
{ok, _} = fabric2_db:update_doc(Db, Doc, []),
ok.
atts(0) ->
[];
atts(Size) ->
[couch_att:new([
{name, <<"att1">>},
{type, <<"app/binary">>},
{att_len, Size},
{data, fun(Bytes) -> binary_chunk(Bytes) end}
])].
replicate(Source, Target) ->
?assertMatch({ok, _}, couch_replicator_test_helper:replicate(#{
<<"source">> => Source,
<<"target">> => Target,
<<"worker_processes">> => 1 % This make batch_size predictable
})).
compare_dbs(Source, Target, ExceptIds) ->
?assertEqual(ok, couch_replicator_test_helper:compare_dbs(Source, Target,
ExceptIds)).