| % 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(cpse_test_fold_purge_infos). |
| -compile(export_all). |
| -compile(nowarn_export_all). |
| |
| -include_lib("eunit/include/eunit.hrl"). |
| -include_lib("couch/include/couch_db.hrl"). |
| |
| -define(NUM_DOCS, 100). |
| |
| setup_each() -> |
| {ok, Db} = cpse_util:create_db(), |
| Db. |
| |
| teardown_each(Db) -> |
| ok = couch_server:delete(couch_db:name(Db), []). |
| |
| cpse_empty_purged_docs(Db) -> |
| ?assertEqual( |
| {ok, []}, |
| couch_db_engine:fold_purge_infos( |
| Db, 0, fun fold_fun/2, [], [] |
| ) |
| ). |
| |
| cpse_all_purged_docs(Db1) -> |
| {RActions, RIds} = lists:foldl( |
| fun(Id, {CActions, CIds}) -> |
| Id1 = docid(Id), |
| Action = {create, {Id1, {[{<<"int">>, Id}]}}}, |
| {[Action | CActions], [Id1 | CIds]} |
| end, |
| {[], []}, |
| lists:seq(1, ?NUM_DOCS) |
| ), |
| Actions = lists:reverse(RActions), |
| Ids = lists:reverse(RIds), |
| {ok, Db2} = cpse_util:apply_batch(Db1, Actions), |
| |
| FDIs = couch_db_engine:open_docs(Db2, Ids), |
| {RevActions2, RevIdRevs} = lists:foldl( |
| fun(FDI, {CActions, CIdRevs}) -> |
| Id = FDI#full_doc_info.id, |
| PrevRev = cpse_util:prev_rev(FDI), |
| Rev = PrevRev#rev_info.rev, |
| Action = {purge, {Id, Rev}}, |
| {[Action | CActions], [{Id, [Rev]} | CIdRevs]} |
| end, |
| {[], []}, |
| FDIs |
| ), |
| {Actions2, IdsRevs} = {lists:reverse(RevActions2), lists:reverse(RevIdRevs)}, |
| |
| {ok, Db3} = cpse_util:apply_batch(Db2, Actions2), |
| {ok, PurgedIdRevs} = couch_db_engine:fold_purge_infos( |
| Db3, 0, fun fold_fun/2, [], [] |
| ), |
| ?assertEqual(IdsRevs, lists:reverse(PurgedIdRevs)). |
| |
| cpse_start_seq(Db1) -> |
| Actions1 = [ |
| {create, {docid(1), {[{<<"int">>, 1}]}}}, |
| {create, {docid(2), {[{<<"int">>, 2}]}}}, |
| {create, {docid(3), {[{<<"int">>, 3}]}}}, |
| {create, {docid(4), {[{<<"int">>, 4}]}}}, |
| {create, {docid(5), {[{<<"int">>, 5}]}}} |
| ], |
| Ids = [docid(1), docid(2), docid(3), docid(4), docid(5)], |
| {ok, Db2} = cpse_util:apply_actions(Db1, Actions1), |
| |
| FDIs = couch_db_engine:open_docs(Db2, Ids), |
| {RActions2, RIdRevs} = lists:foldl( |
| fun(FDI, {CActions, CIdRevs}) -> |
| Id = FDI#full_doc_info.id, |
| PrevRev = cpse_util:prev_rev(FDI), |
| Rev = PrevRev#rev_info.rev, |
| Action = {purge, {Id, Rev}}, |
| {[Action | CActions], [{Id, [Rev]} | CIdRevs]} |
| end, |
| {[], []}, |
| FDIs |
| ), |
| {ok, Db3} = cpse_util:apply_actions(Db2, lists:reverse(RActions2)), |
| |
| StartSeq = 3, |
| StartSeqIdRevs = lists:nthtail(StartSeq, lists:reverse(RIdRevs)), |
| {ok, PurgedIdRevs} = couch_db_engine:fold_purge_infos( |
| Db3, StartSeq, fun fold_fun/2, [], [] |
| ), |
| ?assertEqual(StartSeqIdRevs, lists:reverse(PurgedIdRevs)). |
| |
| cpse_id_rev_repeated(Db1) -> |
| Actions1 = [ |
| {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}}, |
| {conflict, {<<"foo">>, {[{<<"vsn">>, 2}]}}} |
| ], |
| {ok, Db2} = cpse_util:apply_actions(Db1, Actions1), |
| |
| [FDI1] = couch_db_engine:open_docs(Db2, [<<"foo">>]), |
| PrevRev1 = cpse_util:prev_rev(FDI1), |
| Rev1 = PrevRev1#rev_info.rev, |
| Actions2 = [ |
| {purge, {<<"foo">>, Rev1}} |
| ], |
| |
| {ok, Db3} = cpse_util:apply_actions(Db2, Actions2), |
| {ok, PurgedIdRevs1} = couch_db_engine:fold_purge_infos( |
| Db3, 0, fun fold_fun/2, [], [] |
| ), |
| ExpectedPurgedIdRevs1 = [ |
| {<<"foo">>, [Rev1]} |
| ], |
| |
| ?assertEqual(ExpectedPurgedIdRevs1, lists:reverse(PurgedIdRevs1)), |
| ?assertEqual(1, couch_db_engine:get_purge_seq(Db3)), |
| |
| % purge the same Id,Rev when the doc still exists |
| {ok, Db4} = cpse_util:apply_actions(Db3, Actions2), |
| {ok, PurgedIdRevs2} = couch_db_engine:fold_purge_infos( |
| Db4, 0, fun fold_fun/2, [], [] |
| ), |
| ExpectedPurgedIdRevs2 = [ |
| {<<"foo">>, [Rev1]}, |
| {<<"foo">>, [Rev1]} |
| ], |
| ?assertEqual(ExpectedPurgedIdRevs2, lists:reverse(PurgedIdRevs2)), |
| ?assertEqual(2, couch_db_engine:get_purge_seq(Db4)), |
| |
| [FDI2] = couch_db_engine:open_docs(Db4, [<<"foo">>]), |
| PrevRev2 = cpse_util:prev_rev(FDI2), |
| Rev2 = PrevRev2#rev_info.rev, |
| Actions3 = [ |
| {purge, {<<"foo">>, Rev2}} |
| ], |
| {ok, Db5} = cpse_util:apply_actions(Db4, Actions3), |
| |
| {ok, PurgedIdRevs3} = couch_db_engine:fold_purge_infos( |
| Db5, 0, fun fold_fun/2, [], [] |
| ), |
| ExpectedPurgedIdRevs3 = [ |
| {<<"foo">>, [Rev1]}, |
| {<<"foo">>, [Rev1]}, |
| {<<"foo">>, [Rev2]} |
| ], |
| ?assertEqual(ExpectedPurgedIdRevs3, lists:reverse(PurgedIdRevs3)), |
| ?assertEqual(3, couch_db_engine:get_purge_seq(Db5)), |
| |
| % purge the same Id,Rev when the doc was completely purged |
| {ok, Db6} = cpse_util:apply_actions(Db5, Actions3), |
| |
| {ok, PurgedIdRevs4} = couch_db_engine:fold_purge_infos( |
| Db6, 0, fun fold_fun/2, [], [] |
| ), |
| ExpectedPurgedIdRevs4 = [ |
| {<<"foo">>, [Rev1]}, |
| {<<"foo">>, [Rev1]}, |
| {<<"foo">>, [Rev2]}, |
| {<<"foo">>, [Rev2]} |
| ], |
| ?assertEqual(ExpectedPurgedIdRevs4, lists:reverse(PurgedIdRevs4)), |
| ?assertEqual(4, couch_db_engine:get_purge_seq(Db6)). |
| |
| fold_fun({_PSeq, _UUID, Id, Revs}, Acc) -> |
| {ok, [{Id, Revs} | Acc]}. |
| |
| docid(I) -> |
| Str = io_lib:format("~4..0b", [I]), |
| iolist_to_binary(Str). |