summaryrefslogtreecommitdiff
path: root/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/couch/test/eunit/couchdb_update_conflicts_tests.erl')
-rw-r--r--src/couch/test/eunit/couchdb_update_conflicts_tests.erl280
1 files changed, 0 insertions, 280 deletions
diff --git a/src/couch/test/eunit/couchdb_update_conflicts_tests.erl b/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
deleted file mode 100644
index 1329aba27..000000000
--- a/src/couch/test/eunit/couchdb_update_conflicts_tests.erl
+++ /dev/null
@@ -1,280 +0,0 @@
-% 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(couchdb_update_conflicts_tests).
-
--include_lib("couch/include/couch_eunit.hrl").
--include_lib("couch/include/couch_db.hrl").
-
--define(i2l(I), integer_to_list(I)).
--define(DOC_ID, <<"foobar">>).
--define(LOCAL_DOC_ID, <<"_local/foobar">>).
--define(NUM_CLIENTS, [100, 500, 1000, 2000, 5000, 10000]).
--define(TIMEOUT, 20000).
-
-start() ->
- test_util:start_couch().
-
-
-setup() ->
- DbName = ?tempdb(),
- {ok, Db} = couch_db:create(DbName, [?ADMIN_CTX, overwrite]),
- Doc = couch_doc:from_json_obj({[{<<"_id">>, ?DOC_ID},
- {<<"value">>, 0}]}),
- {ok, Rev} = couch_db:update_doc(Db, Doc, []),
- ok = couch_db:close(Db),
- RevStr = couch_doc:rev_to_str(Rev),
- {DbName, RevStr}.
-setup(_) ->
- setup().
-
-teardown({DbName, _}) ->
- ok = couch_server:delete(DbName, []),
- ok.
-teardown(_, {DbName, _RevStr}) ->
- teardown({DbName, _RevStr}).
-
-
-view_indexes_cleanup_test_() ->
- {
- "Update conflicts",
- {
- setup,
- fun start/0, fun test_util:stop_couch/1,
- [
- concurrent_updates(),
- bulk_docs_updates()
- ]
- }
- }.
-
-concurrent_updates()->
- {
- "Concurrent updates",
- {
- foreachx,
- fun setup/1, fun teardown/2,
- [{NumClients, fun should_concurrently_update_doc/2}
- || NumClients <- ?NUM_CLIENTS]
- }
- }.
-
-bulk_docs_updates()->
- {
- "Bulk docs updates",
- {
- foreach,
- fun setup/0, fun teardown/1,
- [
- fun should_bulk_create_delete_doc/1,
- fun should_bulk_create_local_doc/1,
- fun should_ignore_invalid_local_doc/1
- ]
- }
- }.
-
-
-should_concurrently_update_doc(NumClients, {DbName, InitRev})->
- {?i2l(NumClients) ++ " clients",
- {inorder,
- [{"update doc",
- {timeout, ?TIMEOUT div 1000,
- ?_test(concurrent_doc_update(NumClients, DbName, InitRev))}},
- {"ensure in single leaf",
- ?_test(ensure_in_single_revision_leaf(DbName))}]}}.
-
-should_bulk_create_delete_doc({DbName, InitRev})->
- ?_test(bulk_delete_create(DbName, InitRev)).
-
-should_bulk_create_local_doc({DbName, _})->
- ?_test(bulk_create_local_doc(DbName)).
-
-should_ignore_invalid_local_doc({DbName, _})->
- ?_test(ignore_invalid_local_doc(DbName)).
-
-
-concurrent_doc_update(NumClients, DbName, InitRev) ->
- Clients = lists:map(
- fun(Value) ->
- ClientDoc = couch_doc:from_json_obj({[
- {<<"_id">>, ?DOC_ID},
- {<<"_rev">>, InitRev},
- {<<"value">>, Value}
- ]}),
- Pid = spawn_client(DbName, ClientDoc),
- {Value, Pid, erlang:monitor(process, Pid)}
- end,
- lists:seq(1, NumClients)),
-
- lists:foreach(fun({_, Pid, _}) -> Pid ! go end, Clients),
-
- {NumConflicts, SavedValue} = lists:foldl(
- fun({Value, Pid, MonRef}, {AccConflicts, AccValue}) ->
- receive
- {'DOWN', MonRef, process, Pid, {ok, _NewRev}} ->
- {AccConflicts, Value};
- {'DOWN', MonRef, process, Pid, conflict} ->
- {AccConflicts + 1, AccValue};
- {'DOWN', MonRef, process, Pid, Error} ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, "Client " ++ ?i2l(Value)
- ++ " got update error: "
- ++ couch_util:to_list(Error)}]})
- after ?TIMEOUT div 2 ->
- erlang:error({assertion_failed,
- [{module, ?MODULE},
- {line, ?LINE},
- {reason, "Timeout waiting for client "
- ++ ?i2l(Value) ++ " to die"}]})
- end
- end, {0, nil}, Clients),
- ?assertEqual(NumClients - 1, NumConflicts),
-
- {ok, Db} = couch_db:open_int(DbName, []),
- {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
- ok = couch_db:close(Db),
- ?assertEqual(1, length(Leaves)),
-
- [{ok, Doc2}] = Leaves,
- {JsonDoc} = couch_doc:to_json_obj(Doc2, []),
- ?assertEqual(SavedValue, couch_util:get_value(<<"value">>, JsonDoc)).
-
-ensure_in_single_revision_leaf(DbName) ->
- {ok, Db} = couch_db:open_int(DbName, []),
- {ok, Leaves} = couch_db:open_doc_revs(Db, ?DOC_ID, all, []),
- ok = couch_db:close(Db),
- [{ok, Doc}] = Leaves,
-
- %% FIXME: server restart won't work from test side
- %% stop(ok),
- %% start(),
-
- {ok, Db2} = couch_db:open_int(DbName, []),
- {ok, Leaves2} = couch_db:open_doc_revs(Db2, ?DOC_ID, all, []),
- ok = couch_db:close(Db2),
- ?assertEqual(1, length(Leaves2)),
-
- [{ok, Doc2}] = Leaves,
- ?assertEqual(Doc, Doc2).
-
-bulk_delete_create(DbName, InitRev) ->
- {ok, Db} = couch_db:open_int(DbName, []),
-
- DeletedDoc = couch_doc:from_json_obj({[
- {<<"_id">>, ?DOC_ID},
- {<<"_rev">>, InitRev},
- {<<"_deleted">>, true}
- ]}),
- NewDoc = couch_doc:from_json_obj({[
- {<<"_id">>, ?DOC_ID},
- {<<"value">>, 666}
- ]}),
-
- {ok, Results} = couch_db:update_docs(Db, [DeletedDoc, NewDoc], []),
- ok = couch_db:close(Db),
-
- ?assertEqual(2, length([ok || {ok, _} <- Results])),
- [{ok, Rev1}, {ok, Rev2}] = Results,
-
- {ok, Db2} = couch_db:open_int(DbName, []),
- {ok, [{ok, Doc1}]} = couch_db:open_doc_revs(
- Db2, ?DOC_ID, [Rev1], [conflicts, deleted_conflicts]),
- {ok, [{ok, Doc2}]} = couch_db:open_doc_revs(
- Db2, ?DOC_ID, [Rev2], [conflicts, deleted_conflicts]),
- ok = couch_db:close(Db2),
-
- {Doc1Props} = couch_doc:to_json_obj(Doc1, []),
- {Doc2Props} = couch_doc:to_json_obj(Doc2, []),
-
- %% Document was deleted
- ?assert(couch_util:get_value(<<"_deleted">>, Doc1Props)),
- %% New document not flagged as deleted
- ?assertEqual(undefined, couch_util:get_value(<<"_deleted">>,
- Doc2Props)),
- %% New leaf revision has the right value
- ?assertEqual(666, couch_util:get_value(<<"value">>,
- Doc2Props)),
- %% Deleted document has no conflicts
- ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
- Doc1Props)),
- %% Deleted document has no deleted conflicts
- ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
- Doc1Props)),
- %% New leaf revision doesn't have conflicts
- ?assertEqual(undefined, couch_util:get_value(<<"_conflicts">>,
- Doc1Props)),
- %% New leaf revision doesn't have deleted conflicts
- ?assertEqual(undefined, couch_util:get_value(<<"_deleted_conflicts">>,
- Doc1Props)),
-
- %% Deleted revision has position 2
- ?assertEqual(2, element(1, Rev1)),
- %% New leaf revision has position 3
- ?assertEqual(3, element(1, Rev2)).
-
-
-bulk_create_local_doc(DbName) ->
- {ok, Db} = couch_db:open_int(DbName, []),
-
- LocalDoc = couch_doc:from_json_obj({[
- {<<"_id">>, ?LOCAL_DOC_ID},
- {<<"_rev">>, <<"0-1">>}
- ]}),
-
- {ok, Results} = couch_db:update_docs(Db, [LocalDoc],
- [], replicated_changes),
- ok = couch_db:close(Db),
- ?assertEqual([], Results),
-
- {ok, Db2} = couch_db:open_int(DbName, []),
- {ok, LocalDoc1} = couch_db:open_doc_int(Db2, ?LOCAL_DOC_ID, []),
- ok = couch_db:close(Db2),
- ?assertEqual(?LOCAL_DOC_ID, LocalDoc1#doc.id),
- ?assertEqual({0, [<<"2">>]}, LocalDoc1#doc.revs).
-
-
-ignore_invalid_local_doc(DbName) ->
- {ok, Db} = couch_db:open_int(DbName, []),
-
- LocalDoc = couch_doc:from_json_obj({[
- {<<"_id">>, ?LOCAL_DOC_ID},
- {<<"_rev">>, <<"0-abcdef">>}
- ]}),
-
- {ok, Results} = couch_db:update_docs(Db, [LocalDoc],
- [], replicated_changes),
- ok = couch_db:close(Db),
- ?assertEqual([], Results),
-
- {ok, Db2} = couch_db:open_int(DbName, []),
- Result2 = couch_db:open_doc_int(Db2, ?LOCAL_DOC_ID, []),
- ok = couch_db:close(Db2),
- ?assertEqual({not_found, missing}, Result2).
-
-
-spawn_client(DbName, Doc) ->
- spawn(fun() ->
- {ok, Db} = couch_db:open_int(DbName, []),
- receive
- go -> ok
- end,
- erlang:yield(),
- Result = try
- couch_db:update_doc(Db, Doc, [])
- catch _:Error ->
- Error
- end,
- ok = couch_db:close(Db),
- exit(Result)
- end).