This is an automated email from the ASF dual-hosted git repository.

jiahuili430 pushed a commit to branch refactor-couch-changes-tests
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 69c25e780dc7e11a766aabca846dd82640b4feab
Author: Jiahui Li <lijiahui...@gmail.com>
AuthorDate: Tue Dec 5 21:00:44 2023 -0600

    Simplify `couch_changes_tests.erl` using macro `?TDEF_FE`
---
 src/couch/test/eunit/couch_changes_tests.erl | 1268 ++++++++++++--------------
 1 file changed, 565 insertions(+), 703 deletions(-)

diff --git a/src/couch/test/eunit/couch_changes_tests.erl 
b/src/couch/test/eunit/couch_changes_tests.erl
index 02b69f132..b7fa3b2f2 100644
--- a/src/couch/test/eunit/couch_changes_tests.erl
+++ b/src/couch/test/eunit/couch_changes_tests.erl
@@ -16,7 +16,7 @@
 -include_lib("couch/include/couch_db.hrl").
 
 -define(TIMEOUT, 6000).
--define(TEST_TIMEOUT, 10000).
+%%-define(TEST_TIMEOUT, 10000).
 
 -record(row, {
     id,
@@ -25,126 +25,107 @@
     doc = nil
 }).
 
-setup() ->
-    DbName = ?tempdb(),
-    {ok, Db} = create_db(DbName),
-    Revs = [
-        R
-     || {ok, R} <- [
-            save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
-            save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
-            save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
-            save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
-            save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
-        ]
-    ],
-    Rev = lists:nth(3, Revs),
-    {ok, Db1} = couch_db:reopen(Db),
-
-    {ok, Rev1} = save_doc(Db1, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
-    Revs1 = Revs ++ [Rev1],
-    Revs2 =
-        Revs1 ++
-            [
-                R
-             || {ok, R} <- [
-                    save_doc(Db1, {[{<<"_id">>, <<"doc6">>}]}),
-                    save_doc(Db1, {[{<<"_id">>, <<"_design/foo">>}]}),
-                    save_doc(Db1, {[{<<"_id">>, <<"doc7">>}]}),
-                    save_doc(Db1, {[{<<"_id">>, <<"doc8">>}]})
-                ]
-            ],
-    config:set(
-        "native_query_servers", "erlang", "{couch_native_process, start_link, 
[]}", _Persist = false
-    ),
-    {DbName, list_to_tuple(Revs2)}.
-
-teardown({DbName, _}) ->
-    config:delete("native_query_servers", "erlang", _Persist = false),
-    delete_db(DbName),
-    ok.
-
-changes_test_() ->
+changes_feed_test_() ->
     {
         "Changes feed",
+        {
+            setup,
+            fun test_util:start_couch/0,
+            fun test_util:stop_couch/1,
+            {
+                "Continuous Feed",
+                {
+                    foreach,
+                    fun setup/0,
+                    fun teardown/1,
+                    [
+                        ?TDEF_FE(t_filter_continuous_feed_by_specific_doc_ids),
+                        ?TDEF_FE(t_end_changes_when_db_deleted)
+                    ]
+                }
+            }
+        }
+    }.
+
+changes_filter_test_() ->
+    {
+        "Changes filter",
         {
             setup,
             fun test_util:start_couch/0,
             fun test_util:stop_couch/1,
             [
-                filter_by_selector(),
-                filter_by_doc_id(),
+                %%filter_by_custom_function(),
                 filter_by_design(),
-                continuous_feed(),
-                %%filter_by_custom_function()
+                filter_by_doc_id(),
                 filter_by_filter_function(),
+                filter_by_selector(),
                 filter_by_view()
             ]
         }
     }.
 
-filter_by_doc_id() ->
+changes_style_test_() ->
     {
-        "Filter _doc_id",
+        "Changes style",
         {
-            foreach,
-            fun setup/0,
-            fun teardown/1,
-            [
-                fun should_filter_by_specific_doc_ids/1,
-                fun should_filter_by_specific_doc_ids_descending/1,
-                fun should_filter_by_specific_doc_ids_with_since/1,
-                fun should_filter_by_specific_doc_ids_no_result/1,
-                fun should_handle_deleted_docs/1
-            ]
+            setup,
+            fun test_util:start_couch/0,
+            fun test_util:stop_couch/1,
+            {
+                foreach,
+                fun setup/0,
+                fun teardown/1,
+                [
+                    ?TDEF_FE(t_style_main_only),
+                    ?TDEF_FE(t_style_main_only_with_include_docs),
+                    ?TDEF_FE(t_style_all_docs),
+                    ?TDEF_FE(t_style_all_docs_with_include_docs)
+                ]
+            }
         }
     }.
 
-filter_by_selector() ->
+%% filter_by_custom_function() ->
+%%     {
+%%         "Filter function",
+%%         {
+%%             foreach,
+%%             fun setup/0, fun teardown/1,
+%%             [
+%%                 fun should_receive_heartbeats/1
+%%             ]
+%%         }
+%%     }.
+
+filter_by_design() ->
     {
-        "Filter _selector",
+        "Filter _design",
         {
             foreach,
             fun setup/0,
             fun teardown/1,
-            [
-                fun should_select_basic/1,
-                fun should_select_with_since/1,
-                fun should_select_when_no_result/1,
-                fun should_select_with_deleted_docs/1,
-                fun should_select_with_continuous/1,
-                fun should_stop_selector_when_db_deleted/1,
-                fun should_select_with_empty_fields/1,
-                fun should_select_with_fields/1
-            ]
+            [?TDEF_FE(t_emit_only_design_documents)]
         }
     }.
 
-filter_by_design() ->
+filter_by_doc_id() ->
     {
-        "Filter _design",
+        "Filter _doc_id",
         {
             foreach,
             fun setup/0,
             fun teardown/1,
             [
-                fun should_emit_only_design_documents/1
+                ?TDEF_FE(t_filter_by_specific_doc_ids),
+                ?TDEF_FE(t_filter_by_specific_doc_ids_descending),
+                ?TDEF_FE(t_filter_by_specific_doc_ids_no_result),
+                ?TDEF_FE(t_filter_by_specific_doc_ids_with_since),
+                ?TDEF_FE(t_handle_deleted_docs)
             ]
         }
     }.
 
-%% filter_by_custom_function() ->
-%%     {
-%%         "Filter function",
-%%         {
-%%             foreach,
-%%             fun setup/0, fun teardown/1,
-%%             [
-%%                 fun should_receive_heartbeats/1
-%%             ]
-%%         }
-%%     }.
-
 filter_by_filter_function() ->
     {
         "Filter by filters",
@@ -153,476 +134,108 @@ filter_by_filter_function() ->
             fun setup/0,
             fun teardown/1,
             [
-                fun should_filter_by_doc_attribute/1,
-                fun should_filter_by_user_ctx/1
+                ?TDEF_FE(t_filter_by_doc_attribute),
+                ?TDEF_FE(t_filter_by_user_ctx)
             ]
         }
     }.
 
-filter_by_view() ->
+filter_by_selector() ->
     {
-        "Filter _view",
+        "Filter _selector",
         {
             foreach,
             fun setup/0,
             fun teardown/1,
             [
-                fun should_filter_by_view/1,
-                fun should_filter_by_erlang_view/1
+                ?TDEF_FE(t_select_basic),
+                ?TDEF_FE(t_select_with_since),
+                ?TDEF_FE(t_select_when_no_result),
+                ?TDEF_FE(t_select_with_deleted_docs),
+                ?TDEF_FE(t_select_with_continuous),
+                ?TDEF_FE(t_stop_selector_when_db_deleted),
+                ?TDEF_FE(t_select_with_empty_fields),
+                ?TDEF_FE(t_select_with_fields)
             ]
         }
     }.
 
-continuous_feed() ->
+filter_by_view() ->
     {
-        "Continuous Feed",
+        "Filter _view",
         {
             foreach,
             fun setup/0,
             fun teardown/1,
             [
-                fun should_filter_continuous_feed_by_specific_doc_ids/1,
-                fun should_end_changes_when_db_deleted/1
+                ?TDEF_FE(t_filter_by_view),
+                ?TDEF_FE(t_filter_by_erlang_view)
             ]
         }
     }.
 
-should_filter_by_specific_doc_ids({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{
-                filter = "_doc_ids"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_filter_by_specific_doc_ids_descending({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{
-                filter = "_doc_ids",
-                dir = rev
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(<<"doc4">>, Id2),
-            ?assertEqual(4, Seq2),
-            ?assertEqual(4, LastSeq)
-        end
-    ).
-
-should_filter_by_specific_doc_ids_with_since({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 5
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq1, id = Id1}] = Rows,
-            ?assertEqual(<<"doc3">>, Id1),
-            ?assertEqual(6, Seq1),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_filter_by_specific_doc_ids_no_result({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 6
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(0, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_handle_deleted_docs({DbName, Revs}) ->
-    ?_test(
-        begin
-            Rev3_2 = element(6, Revs),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc3">>},
-                    {<<"_deleted">>, true},
-                    {<<"_rev">>, Rev3_2}
-                ]}
-            ),
-
-            ChArgs = #changes_args{
-                filter = "_doc_ids",
-                since = 9
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertMatch(
-                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
-                Rows
-            ),
-            ?assertEqual(11, LastSeq)
-        end
-    ).
-
-should_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
-    ?_test(
-        begin
-            {ok, Db} = couch_db:open_int(DbName, []),
-            ChangesArgs = #changes_args{
-                filter = "_doc_ids",
-                feed = "continuous"
-            },
-            DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-            Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-            reset_row_notifications(),
-            Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-            ?assertEqual(ok, wait_row_notifications(2)),
-            ok = pause(Consumer),
-
-            Rows = get_rows(Consumer),
-            ?assertEqual(2, length(Rows)),
-            [#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
-            ?assertEqual(<<"doc4">>, Id1),
-            ?assertEqual(4, Seq1),
-            ?assertEqual(<<"doc3">>, Id2),
-            ?assertEqual(6, Seq2),
-
-            clear_rows(Consumer),
-            {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
-            {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
-            ok = unpause(Consumer),
-            timer:sleep(100),
-            ok = pause(Consumer),
-            ?assertEqual([], get_rows(Consumer)),
-
-            Rev4 = element(4, Revs),
-            Rev3_2 = element(6, Revs),
-            {ok, Rev4_2} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc4">>},
-                    {<<"_rev">>, Rev4}
-                ]}
-            ),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc4">>},
-                    {<<"_rev">>, Rev4_2}
-                ]}
-            ),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
-            {ok, Rev3_3} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc3">>},
-                    {<<"_rev">>, Rev3_2}
-                ]}
-            ),
-            reset_row_notifications(),
-            ok = unpause(Consumer),
-            ?assertEqual(ok, wait_row_notifications(2)),
-            ok = pause(Consumer),
-
-            NewRows = get_rows(Consumer),
-            ?assertEqual(2, length(NewRows)),
-            [Row14, Row16] = NewRows,
-            ?assertEqual(<<"doc4">>, Row14#row.id),
-            ?assertEqual(15, Row14#row.seq),
-            ?assertEqual(<<"doc3">>, Row16#row.id),
-            ?assertEqual(17, Row16#row.seq),
-
-            clear_rows(Consumer),
-            {ok, _Rev3_4} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc3">>},
-                    {<<"_rev">>, Rev3_3}
-                ]}
-            ),
-            reset_row_notifications(),
-            ok = unpause(Consumer),
-            ?assertEqual(ok, wait_row_notifications(1)),
-            ok = pause(Consumer),
-
-            FinalRows = get_rows(Consumer),
-
-            ok = unpause(Consumer),
-            stop_consumer(Consumer),
-
-            ?assertMatch([#row{seq = 18, id = <<"doc3">>}], FinalRows)
-        end
-    ).
-
-should_end_changes_when_db_deleted({DbName, _Revs}) ->
-    ?_test(begin
-        {ok, _Db} = couch_db:open_int(DbName, []),
-        ChangesArgs = #changes_args{
-            filter = "_doc_ids",
-            feed = "continuous"
-        },
-        DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
-        Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
-        Consumer = spawn_consumer(DbName, ChangesArgs, Req),
-        ok = pause(Consumer),
-        ok = couch_server:delete(DbName, [?ADMIN_CTX]),
-        ok = unpause(Consumer),
-        {_Rows, _LastSeq} = wait_finished(Consumer),
-        stop_consumer(Consumer),
-        ok
-    end).
-
-should_select_basic({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{filter = "_selector"},
-            Selector = {[{<<"_id">>, <<"doc3">>}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_select_with_since({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{filter = "_selector", since = 9},
-            GteDoc2 = {[{<<"$gte">>, <<"doc1">>}]},
-            Selector = {[{<<"_id">>, GteDoc2}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc8">>, Id),
-            ?assertEqual(10, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_select_when_no_result({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{filter = "_selector"},
-            Selector = {[{<<"_id">>, <<"nopers">>}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(0, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_select_with_deleted_docs({DbName, Revs}) ->
-    ?_test(
-        begin
-            Rev3_2 = element(6, Revs),
-            {ok, Db} = couch_db:open_int(DbName, []),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc3">>},
-                    {<<"_deleted">>, true},
-                    {<<"_rev">>, Rev3_2}
-                ]}
-            ),
-            ChArgs = #changes_args{filter = "_selector"},
-            Selector = {[{<<"_id">>, <<"doc3">>}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
-            ?assertMatch(
-                [#row{seq = LastSeq, id = <<"doc3">>, deleted = true}],
-                Rows
-            ),
-            ?assertEqual(11, LastSeq)
-        end
-    ).
-
-should_select_with_continuous({DbName, Revs}) ->
-    ?_test(
-        begin
-            {ok, Db} = couch_db:open_int(DbName, []),
-            ChArgs = #changes_args{filter = "_selector", feed = "continuous"},
-            GteDoc8 = {[{<<"$gte">>, <<"doc8">>}]},
-            Selector = {[{<<"_id">>, GteDoc8}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            reset_row_notifications(),
-            Consumer = spawn_consumer(DbName, ChArgs, Req),
-            ?assertEqual(ok, wait_row_notifications(1)),
-            ok = pause(Consumer),
-            Rows = get_rows(Consumer),
-            ?assertMatch(
-                [#row{seq = 10, id = <<"doc8">>, deleted = false}],
-                Rows
-            ),
-            clear_rows(Consumer),
-            {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc01">>}]}),
-            ok = unpause(Consumer),
-            timer:sleep(100),
-            ok = pause(Consumer),
-            ?assertEqual([], get_rows(Consumer)),
-            Rev4 = element(4, Revs),
-            Rev8 = element(10, Revs),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc8">>},
-                    {<<"_rev">>, Rev8}
-                ]}
-            ),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"doc4">>},
-                    {<<"_rev">>, Rev4}
-                ]}
-            ),
-            reset_row_notifications(),
-            ok = unpause(Consumer),
-            ?assertEqual(ok, wait_row_notifications(1)),
-            ok = pause(Consumer),
-            NewRows = get_rows(Consumer),
-            ?assertMatch(
-                [#row{seq = _, id = <<"doc8">>, deleted = false}],
-                NewRows
-            )
-        end
-    ).
-
-should_stop_selector_when_db_deleted({DbName, _Revs}) ->
-    ?_test(
-        begin
-            {ok, _Db} = couch_db:open_int(DbName, []),
-            ChArgs = #changes_args{filter = "_selector", feed = "continuous"},
-            Selector = {[{<<"_id">>, <<"doc3">>}]},
-            Req = {json_req, {[{<<"selector">>, Selector}]}},
-            Consumer = spawn_consumer(DbName, ChArgs, Req),
-            ok = pause(Consumer),
-            ok = couch_server:delete(DbName, [?ADMIN_CTX]),
-            ok = unpause(Consumer),
-            {_Rows, _LastSeq} = wait_finished(Consumer),
-            stop_consumer(Consumer),
-            ok
-        end
-    ).
-
-should_select_with_empty_fields({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{filter = "_selector", include_docs = true},
-            Selector = {[{<<"_id">>, <<"doc3">>}]},
-            Req =
-                {json_req,
-                    {[
-                        {<<"selector">>, Selector},
-                        {<<"fields">>, []}
-                    ]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id, doc = Doc}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq),
-            ?assertMatch({[{_K1, _V1}, {_K2, _V2}]}, Doc)
-        end
-    ).
-
-should_select_with_fields({DbName, _}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{filter = "_selector", include_docs = true},
-            Selector = {[{<<"_id">>, <<"doc3">>}]},
-            Req =
-                {json_req,
-                    {[
-                        {<<"selector">>, Selector},
-                        {<<"fields">>, [<<"_id">>, <<"nope">>]}
-                    ]}},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id, doc = Doc}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq),
-            ?assertMatch(Doc, {[{<<"_id">>, <<"doc3">>}]})
-        end
-    ).
-
-should_emit_only_design_documents({DbName, Revs}) ->
-    ?_test(
-        begin
-            ChArgs = #changes_args{
-                filter = "_design"
-            },
-            Req = {json_req, null},
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-
-            ?assertEqual(1, length(Rows)),
-            ?assertEqual(UpSeq, LastSeq),
-            ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
-
-            {ok, Db} = couch_db:open_int(DbName, [?ADMIN_CTX]),
-            {ok, _} = save_doc(
-                Db,
-                {[
-                    {<<"_id">>, <<"_design/foo">>},
-                    {<<"_rev">>, element(8, Revs)},
-                    {<<"_deleted">>, true}
-                ]}
-            ),
-
-            couch_db:close(Db),
-            {Rows2, LastSeq2, _} = run_changes_query(DbName, ChArgs, Req),
-
-            UpSeq2 = UpSeq + 1,
-
-            ?assertEqual(1, length(Rows2)),
-            ?assertEqual(UpSeq2, LastSeq2),
-            ?assertEqual(
-                [
-                    #row{
-                        seq = 11,
-                        id = <<"_design/foo">>,
-                        deleted = true
-                    }
-                ],
-                Rows2
-            )
-        end
-    ).
+t_filter_continuous_feed_by_specific_doc_ids({DbName, Revs}) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    ChArgs = #changes_args{feed = "continuous", filter = "_doc_ids"},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    reset_row_notifications(),
+    Consumer = spawn_consumer(DbName, ChArgs, Req),
+    ?assertEqual(ok, wait_row_notifications(2)),
+    ok = pause(Consumer),
+
+    Rows = get_rows(Consumer),
+    ?assertEqual(2, length(Rows)),
+    ?assertEqual([#row{seq = 4, id = <<"doc4">>}, #row{seq = 6, id = 
<<"doc3">>}], Rows),
+
+    clear_rows(Consumer),
+    {ok, _Rev9} = save_doc(Db, {[{<<"_id">>, <<"doc9">>}]}),
+    {ok, _Rev10} = save_doc(Db, {[{<<"_id">>, <<"doc10">>}]}),
+    ok = unpause(Consumer),
+    timer:sleep(100),
+    ok = pause(Consumer),
+    ?assertEqual([], get_rows(Consumer)),
+
+    Rev4 = element(4, Revs),
+    Rev3_2 = element(6, Revs),
+    {ok, Rev4_2} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}, {<<"_rev">>, 
Rev4}]}),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc11">>}]}),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}, {<<"_rev">>, Rev4_2}]}),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc12">>}]}),
+    {ok, Rev3_3} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, 
Rev3_2}]}),
+    reset_row_notifications(),
+    ok = unpause(Consumer),
+    ?assertEqual(ok, wait_row_notifications(2)),
+    ok = pause(Consumer),
+
+    NewRows = get_rows(Consumer),
+    ?assertEqual(2, length(NewRows)),
+    ?assertEqual([#row{seq = 15, id = <<"doc4">>}, #row{seq = 17, id = 
<<"doc3">>}], NewRows),
+
+    clear_rows(Consumer),
+    {ok, _Rev3_4} = save_doc(Db, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, 
Rev3_3}]}),
+    reset_row_notifications(),
+    ok = unpause(Consumer),
+    ?assertEqual(ok, wait_row_notifications(1)),
+    ok = pause(Consumer),
+
+    FinalRows = get_rows(Consumer),
+    ok = unpause(Consumer),
+    stop_consumer(Consumer),
+    couch_db:close(Db),
+    ?assertEqual([#row{seq = 18, id = <<"doc3">>}], FinalRows).
+
+t_end_changes_when_db_deleted({DbName, _Revs}) ->
+    {ok, _Db} = couch_db:open_int(DbName, []),
+    ChArgs = #changes_args{feed = "continuous", filter = "_doc_ids"},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    Consumer = spawn_consumer(DbName, ChArgs, Req),
+    ok = pause(Consumer),
+    ok = delete_db(DbName),
+    ok = unpause(Consumer),
+    {_Rows, _LastSeq} = wait_finished(Consumer),
+    ok = stop_consumer(Consumer).
 
 %% should_receive_heartbeats(_) ->
 %%     {timeout, ?TEST_TIMEOUT div 1000,
@@ -691,164 +304,411 @@ should_emit_only_design_documents({DbName, Revs}) ->
 %%              ?assert(Heartbeats3 > Heartbeats2)
 %%         end)}.
 
-should_filter_by_doc_attribute({DbName, _}) ->
-    ?_test(
-        begin
-            DDocId = <<"_design/app">>,
-            DDoc = couch_doc:from_json_obj(
+t_emit_only_design_documents({DbName, Revs}) ->
+    ChArgs = #changes_args{filter = "_design"},
+    Req = {json_req, null},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq),
+    ?assertEqual([#row{seq = 8, id = <<"_design/foo">>}], Rows),
+
+    {ok, Db} = couch_db:open_int(DbName, [?ADMIN_CTX]),
+    {ok, _} = save_doc(
+        Db,
+        {[
+            {<<"_id">>, <<"_design/foo">>},
+            {<<"_rev">>, element(8, Revs)},
+            {<<"_deleted">>, true}
+        ]}
+    ),
+    couch_db:close(Db),
+    {Rows2, LastSeq2, UpSeq2} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows2)),
+    ?assertEqual(UpSeq2, LastSeq2),
+    ?assertEqual([#row{seq = 11, id = <<"_design/foo">>, deleted = true}], 
Rows2).
+
+t_filter_by_specific_doc_ids({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_doc_ids"},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(2, length(Rows)),
+    ?assertEqual([#row{seq = 4, id = <<"doc4">>}, #row{seq = 6, id = 
<<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_filter_by_specific_doc_ids_descending({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_doc_ids", dir = rev},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(2, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}, #row{seq = 4, id = 
<<"doc4">>}], Rows),
+    ?assertEqual(4, LastSeq).
+
+t_filter_by_specific_doc_ids_no_result({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_doc_ids", since = 6},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(0, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_filter_by_specific_doc_ids_with_since({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_doc_ids", since = 5},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_handle_deleted_docs({DbName, Revs}) ->
+    Rev3_2 = element(6, Revs),
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, _} = save_doc(
+        Db,
+        {[
+            {<<"_id">>, <<"doc3">>},
+            {<<"_rev">>, Rev3_2},
+            {<<"_deleted">>, true}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "_doc_ids", since = 9},
+    DocIds = [<<"doc3">>, <<"doc4">>, <<"doc9999">>],
+    Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
+    {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = LastSeq, id = <<"doc3">>, deleted = true}], Rows),
+    ?assertEqual(11, LastSeq).
+
+t_filter_by_doc_attribute({DbName, _}) ->
+    DDocId = <<"_design/app">>,
+    DDoc = couch_doc:from_json_obj(
+        {[
+            {<<"_id">>, DDocId},
+            {<<"language">>, <<"javascript">>},
+            {<<"filters">>,
+                {[
+                    {<<"valid">>, <<
+                        "function(doc, req) {"
+                        " if (doc._id == 'doc3') {"
+                        " return true; "
+                        "} }"
+                    >>}
+                ]}}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "app/valid"},
+    Req = {json_req, null},
+    ok = update_ddoc(DbName, DDoc),
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_filter_by_user_ctx({DbName, _}) ->
+    DDocId = <<"_design/app">>,
+    DDoc = couch_doc:from_json_obj(
+        {[
+            {<<"_id">>, DDocId},
+            {<<"language">>, <<"javascript">>},
+            {<<"filters">>,
                 {[
-                    {<<"_id">>, DDocId},
-                    {<<"language">>, <<"javascript">>},
-                    {<<"filters">>,
+                    {<<"valid">>, <<
+                        "function(doc, req) {"
+                        " if (req.userCtx.name == doc._id) {"
+                        " return true; "
+                        "} }"
+                    >>}
+                ]}}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "app/valid"},
+    UserCtx = #user_ctx{name = <<"doc3">>, roles = []},
+    {ok, DbRec} = couch_db:clustered_db(DbName, UserCtx),
+    Req = {json_req, {[{<<"userCtx">>, couch_util:json_user_ctx(DbRec)}]}},
+    ok = update_ddoc(DbName, DDoc),
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_select_basic({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_selector"},
+    Selector = {[{<<"_id">>, <<"doc3">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_select_with_since({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_selector", since = 9},
+    GteDoc2 = {[{<<"$gte">>, <<"doc1">>}]},
+    Selector = {[{<<"_id">>, GteDoc2}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 10, id = <<"doc8">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_select_when_no_result({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_selector"},
+    Selector = {[{<<"_id">>, <<"nopers">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(0, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_select_with_deleted_docs({DbName, Revs}) ->
+    Rev3_2 = element(6, Revs),
+    {ok, Db} = couch_db:open_int(DbName, []),
+    {ok, _} = save_doc(
+        Db,
+        {[
+            {<<"_id">>, <<"doc3">>},
+            {<<"_deleted">>, true},
+            {<<"_rev">>, Rev3_2}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "_selector"},
+    Selector = {[{<<"_id">>, <<"doc3">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    {Rows, LastSeq, _} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual([#row{seq = LastSeq, id = <<"doc3">>, deleted = true}], Rows),
+    ?assertEqual(11, LastSeq).
+
+t_select_with_continuous({DbName, Revs}) ->
+    {ok, Db} = couch_db:open_int(DbName, []),
+    ChArgs = #changes_args{filter = "_selector", feed = "continuous"},
+    GteDoc8 = {[{<<"$gte">>, <<"doc8">>}]},
+    Selector = {[{<<"_id">>, GteDoc8}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    reset_row_notifications(),
+    Consumer = spawn_consumer(DbName, ChArgs, Req),
+    ?assertEqual(ok, wait_row_notifications(1)),
+    ok = pause(Consumer),
+    Rows = get_rows(Consumer),
+    ?assertEqual([#row{seq = 10, id = <<"doc8">>, deleted = false}], Rows),
+    clear_rows(Consumer),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc01">>}]}),
+    ok = unpause(Consumer),
+    timer:sleep(100),
+    ok = pause(Consumer),
+    ?assertEqual([], get_rows(Consumer)),
+    Rev4 = element(4, Revs),
+    Rev8 = element(10, Revs),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}, {<<"_rev">>, Rev8}]}),
+    {ok, _} = save_doc(Db, {[{<<"_id">>, <<"doc4">>}, {<<"_rev">>, Rev4}]}),
+    reset_row_notifications(),
+    ok = unpause(Consumer),
+    ?assertEqual(ok, wait_row_notifications(1)),
+    ok = pause(Consumer),
+    NewRows = get_rows(Consumer),
+    ?assertMatch([#row{seq = _, id = <<"doc8">>, deleted = false}], NewRows),
+    ?assertEqual([#row{seq = 12, id = <<"doc8">>, deleted = false}], NewRows).
+
+t_stop_selector_when_db_deleted({DbName, _Revs}) ->
+    {ok, _Db} = couch_db:open_int(DbName, []),
+    ChArgs = #changes_args{filter = "_selector", feed = "continuous"},
+    Selector = {[{<<"_id">>, <<"doc3">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}]}},
+    Consumer = spawn_consumer(DbName, ChArgs, Req),
+    ok = pause(Consumer),
+    ok = delete_db(DbName),
+    ok = unpause(Consumer),
+    {_Rows, _LastSeq} = wait_finished(Consumer),
+    ok = stop_consumer(Consumer).
+
+t_select_with_empty_fields({DbName, Revs}) ->
+    ChArgs = #changes_args{filter = "_selector", include_docs = true},
+    Selector = {[{<<"_id">>, <<"doc3">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}, {<<"fields">>, []}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    Rev3_2 = element(6, Revs),
+    Doc = {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev3_2}]},
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>, doc = Doc}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_select_with_fields({DbName, _}) ->
+    ChArgs = #changes_args{filter = "_selector", include_docs = true},
+    Selector = {[{<<"_id">>, <<"doc3">>}]},
+    Req = {json_req, {[{<<"selector">>, Selector}, {<<"fields">>, [<<"_id">>, 
<<"nope">>]}]}},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>, doc = {[{<<"_id">>, 
<<"doc3">>}]}}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_filter_by_view({DbName, _}) ->
+    DDocId = <<"_design/app">>,
+    DDoc = couch_doc:from_json_obj(
+        {[
+            {<<"_id">>, DDocId},
+            {<<"language">>, <<"javascript">>},
+            {<<"views">>,
+                {[
+                    {<<"valid">>,
                         {[
-                            {<<"valid">>, <<
-                                "function(doc, req) {"
+                            {<<"map">>, <<
+                                "function(doc) {"
                                 " if (doc._id == 'doc3') {"
-                                " return true; "
+                                " emit(doc); "
                                 "} }"
                             >>}
                         ]}}
-                ]}
-            ),
-            ChArgs = #changes_args{filter = "app/valid"},
-            Req = {json_req, null},
-            ok = update_ddoc(DbName, DDoc),
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
-    ).
-
-should_filter_by_user_ctx({DbName, _}) ->
-    ?_test(
-        begin
-            DDocId = <<"_design/app">>,
-            DDoc = couch_doc:from_json_obj(
+                ]}}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "_view"},
+    Req = {json_req, {[{<<"query">>, {[{<<"view">>, <<"app/valid">>}]}}]}},
+    ok = update_ddoc(DbName, DDoc),
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_filter_by_erlang_view({DbName, _}) ->
+    DDocId = <<"_design/app">>,
+    DDoc = couch_doc:from_json_obj(
+        {[
+            {<<"_id">>, DDocId},
+            {<<"language">>, <<"erlang">>},
+            {<<"views">>,
                 {[
-                    {<<"_id">>, DDocId},
-                    {<<"language">>, <<"javascript">>},
-                    {<<"filters">>,
+                    {<<"valid">>,
                         {[
-                            {<<"valid">>, <<
-                                "function(doc, req) {"
-                                " if (req.userCtx.name == doc._id) {"
-                                " return true; "
-                                "} }"
+                            {<<"map">>, <<
+                                "fun({Doc}) ->"
+                                " case lists:keyfind(<<\"_id\">>, 1, Doc) of"
+                                "   {<<\"_id\">>, <<\"doc3\">>} ->  Emit(Doc, 
null);"
+                                "   false -> ok"
+                                " end "
+                                "end."
                             >>}
                         ]}}
-                ]}
-            ),
-            ChArgs = #changes_args{filter = "app/valid"},
-            UserCtx = #user_ctx{name = <<"doc3">>, roles = []},
-            {ok, DbRec} = couch_db:clustered_db(DbName, UserCtx),
-            Req =
-                {json_req,
-                    {[
-                        {
-                            <<"userCtx">>, couch_util:json_user_ctx(DbRec)
-                        }
-                    ]}},
-            ok = update_ddoc(DbName, DDoc),
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
+                ]}}
+        ]}
+    ),
+    ChArgs = #changes_args{filter = "_view"},
+    Req = {json_req, {[{<<"query">>, {[{<<"view">>, <<"app/valid">>}]}}]}},
+    ok = update_ddoc(DbName, DDoc),
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(1, length(Rows)),
+    ?assertEqual([#row{seq = 6, id = <<"doc3">>}], Rows),
+    ?assertEqual(UpSeq, LastSeq).
+
+t_style_main_only({DbName, _}) ->
+    ChArgs = #changes_args{style = main_only},
+    Req = {json_req, null},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(9, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq),
+    ?assertEqual(
+        [
+            #row{seq = 1, id = <<"doc1">>},
+            #row{seq = 2, id = <<"doc2">>},
+            #row{seq = 4, id = <<"doc4">>},
+            #row{seq = 5, id = <<"doc5">>},
+            #row{seq = 6, id = <<"doc3">>},
+            #row{seq = 7, id = <<"doc6">>},
+            #row{seq = 8, id = <<"_design/foo">>},
+            #row{seq = 9, id = <<"doc7">>},
+            #row{seq = 10, id = <<"doc8">>}
+        ],
+        Rows
     ).
 
-should_filter_by_view({DbName, _}) ->
-    ?_test(
-        begin
-            DDocId = <<"_design/app">>,
-            DDoc = couch_doc:from_json_obj(
-                {[
-                    {<<"_id">>, DDocId},
-                    {<<"language">>, <<"javascript">>},
-                    {<<"views">>,
-                        {[
-                            {<<"valid">>,
-                                {[
-                                    {<<"map">>, <<
-                                        "function(doc) {"
-                                        " if (doc._id == 'doc3') {"
-                                        " emit(doc); "
-                                        "} }"
-                                    >>}
-                                ]}}
-                        ]}}
-                ]}
-            ),
-            ChArgs = #changes_args{filter = "_view"},
-            Req =
-                {json_req,
-                    {[
-                        {
-                            <<"query">>,
-                            {[
-                                {<<"view">>, <<"app/valid">>}
-                            ]}
-                        }
-                    ]}},
-            ok = update_ddoc(DbName, DDoc),
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
+t_style_main_only_with_include_docs({DbName, Revs}) ->
+    ChArgs = #changes_args{style = main_only, include_docs = true},
+    Req = {json_req, null},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(9, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq),
+    ?assertEqual(
+        #row{
+            seq = 1,
+            id = <<"doc1">>,
+            doc = {[{<<"_id">>, <<"doc1">>}, {<<"_rev">>, element(1, Revs)}]}
+        },
+        hd(Rows)
     ).
 
-should_filter_by_erlang_view({DbName, _}) ->
-    ?_test(
-        begin
-            DDocId = <<"_design/app">>,
-            DDoc = couch_doc:from_json_obj(
-                {[
-                    {<<"_id">>, DDocId},
-                    {<<"language">>, <<"erlang">>},
-                    {<<"views">>,
-                        {[
-                            {<<"valid">>,
-                                {[
-                                    {<<"map">>, <<
-                                        "fun({Doc}) ->"
-                                        " case lists:keyfind(<<\"_id\">>, 1, 
Doc) of"
-                                        " {<<\"_id\">>, <<\"doc3\">>} ->  
Emit(Doc, null); "
-                                        " false -> ok"
-                                        " end "
-                                        "end."
-                                    >>}
-                                ]}}
-                        ]}}
-                ]}
-            ),
-            ChArgs = #changes_args{filter = "_view"},
-            Req =
-                {json_req,
-                    {[
-                        {
-                            <<"query">>,
-                            {[
-                                {<<"view">>, <<"app/valid">>}
-                            ]}
-                        }
-                    ]}},
-            ok = update_ddoc(DbName, DDoc),
-            {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
-            ?assertEqual(1, length(Rows)),
-            [#row{seq = Seq, id = Id}] = Rows,
-            ?assertEqual(<<"doc3">>, Id),
-            ?assertEqual(6, Seq),
-            ?assertEqual(UpSeq, LastSeq)
-        end
+t_style_all_docs({DbName, _}) ->
+    ChArgs = #changes_args{style = all_docs},
+    Req = {json_req, null},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(9, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq),
+    ?assertEqual(
+        [
+            #row{seq = 1, id = <<"doc1">>},
+            #row{seq = 2, id = <<"doc2">>},
+            #row{seq = 4, id = <<"doc4">>},
+            #row{seq = 5, id = <<"doc5">>},
+            #row{seq = 6, id = <<"doc3">>},
+            #row{seq = 7, id = <<"doc6">>},
+            #row{seq = 8, id = <<"_design/foo">>},
+            #row{seq = 9, id = <<"doc7">>},
+            #row{seq = 10, id = <<"doc8">>}
+        ],
+        Rows
     ).
 
+t_style_all_docs_with_include_docs({DbName, Revs}) ->
+    ChArgs = #changes_args{style = all_docs, include_docs = true},
+    Req = {json_req, null},
+    {Rows, LastSeq, UpSeq} = run_changes_query(DbName, ChArgs, Req),
+    ?assertEqual(9, length(Rows)),
+    ?assertEqual(UpSeq, LastSeq),
+    ?assertEqual(
+        #row{
+            seq = 1,
+            id = <<"doc1">>,
+            doc = {[{<<"_id">>, <<"doc1">>}, {<<"_rev">>, element(1, Revs)}]}
+        },
+        hd(Rows)
+    ).
+
+%%%%%%%%%%%%%%%%%%%% Utility Functions %%%%%%%%%%%%%%%%%%%%
+setup() ->
+    DbName = ?tempdb(),
+    {ok, Db} = create_db(DbName),
+    Revs = [
+        R
+     || {ok, R} <- [
+            save_doc(Db, {[{<<"_id">>, <<"doc1">>}]}),
+            save_doc(Db, {[{<<"_id">>, <<"doc2">>}]}),
+            save_doc(Db, {[{<<"_id">>, <<"doc3">>}]}),
+            save_doc(Db, {[{<<"_id">>, <<"doc4">>}]}),
+            save_doc(Db, {[{<<"_id">>, <<"doc5">>}]})
+        ]
+    ],
+    Rev = lists:nth(3, Revs),
+    {ok, Db1} = couch_db:reopen(Db),
+    {ok, Rev1} = save_doc(Db1, {[{<<"_id">>, <<"doc3">>}, {<<"_rev">>, Rev}]}),
+    Revs1 = Revs ++ [Rev1],
+    Revs2 =
+        Revs1 ++
+            [
+                R
+             || {ok, R} <- [
+                    save_doc(Db1, {[{<<"_id">>, <<"doc6">>}]}),
+                    save_doc(Db1, {[{<<"_id">>, <<"_design/foo">>}]}),
+                    save_doc(Db1, {[{<<"_id">>, <<"doc7">>}]}),
+                    save_doc(Db1, {[{<<"_id">>, <<"doc8">>}]})
+                ]
+            ],
+    config:set(
+        "native_query_servers", "erlang", "{couch_native_process, start_link, 
[]}", _Persist = false
+    ),
+    {DbName, list_to_tuple(Revs2)}.
+
+teardown({DbName, _}) ->
+    config:delete("native_query_servers", "erlang", _Persist = false),
+    delete_db(DbName),
+    ok.
+
 update_ddoc(DbName, DDoc) ->
     {ok, Db} = couch_db:open_int(DbName, [?ADMIN_CTX]),
     {ok, _} = couch_db:update_doc(Db, DDoc, []),
@@ -868,6 +728,19 @@ save_doc(Db, Json) ->
     {ok, Rev} = couch_db:update_doc(Db, Doc, []),
     {ok, couch_doc:rev_to_str(Rev)}.
 
+%% get_heartbeats({Consumer, _}) ->
+%%     Ref = make_ref(),
+%%     Consumer ! {get_heartbeats, Ref},
+%%     Resp =
+%%         receive
+%%             {hearthbeats, Ref, HeartBeats} ->
+%%                 HeartBeats
+%%         after ?TIMEOUT ->
+%%             timeout
+%%         end,
+%%     ?assertNotEqual(timeout, Resp),
+%%     Resp.
+
 get_rows({Consumer, _}) ->
     Ref = make_ref(),
     Consumer ! {get_rows, Ref},
@@ -881,18 +754,6 @@ get_rows({Consumer, _}) ->
     ?assertNotEqual(timeout, Resp),
     Resp.
 
-%% get_heartbeats({Consumer, _}) ->
-%%     Ref = make_ref(),
-%%     Consumer ! {get_heartbeats, Ref},
-%%     Resp = receive
-%%         {hearthbeats, Ref, HeartBeats} ->
-%%             HeartBeats
-%%     after ?TIMEOUT ->
-%%         timeout
-%%     end,
-%%     ?assertNotEqual(timeout, Resp),
-%%     Resp.
-
 clear_rows({Consumer, _}) ->
     Ref = make_ref(),
     Consumer ! {reset, Ref},
@@ -991,28 +852,29 @@ spawn_consumer(DbName, ChangesArgs0, Req) ->
     Parent = self(),
     spawn_monitor(fun() ->
         put(heartbeat_count, 0),
-        Callback = fun
-            ({change, {Change}, _}, _, Acc) ->
-                Id = couch_util:get_value(<<"id">>, Change),
-                Seq = couch_util:get_value(<<"seq">>, Change),
-                Del = couch_util:get_value(<<"deleted">>, Change, false),
-                Doc = couch_util:get_value(doc, Change, nil),
-                Parent ! row,
-                [#row{id = Id, seq = Seq, deleted = Del, doc = Doc} | Acc];
-            ({stop, LastSeq}, _, Acc) ->
-                Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
-                stop_loop(Parent, Acc);
-            (timeout, _, Acc) ->
-                put(heartbeat_count, get(heartbeat_count) + 1),
-                maybe_pause(Parent, Acc);
-            (_, _, Acc) ->
-                maybe_pause(Parent, Acc)
-        end,
+        Callback =
+            fun
+                ({change, {Change}, _}, _, Acc) ->
+                    Id = couch_util:get_value(<<"id">>, Change),
+                    Seq = couch_util:get_value(<<"seq">>, Change),
+                    Del = couch_util:get_value(<<"deleted">>, Change, false),
+                    Doc = couch_util:get_value(doc, Change, nil),
+                    Parent ! row,
+                    [#row{id = Id, seq = Seq, deleted = Del, doc = Doc} | Acc];
+                ({stop, LastSeq}, _, Acc) ->
+                    Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
+                    stop_loop(Parent, Acc);
+                (timeout, _, Acc) ->
+                    put(heartbeat_count, get(heartbeat_count) + 1),
+                    maybe_pause(Parent, Acc);
+                (_, _, Acc) ->
+                    maybe_pause(Parent, Acc)
+            end,
         {ok, Db} = couch_db:open_int(DbName, []),
         ChangesArgs =
             case
-                (ChangesArgs0#changes_args.timeout =:= undefined) andalso
-                    (ChangesArgs0#changes_args.heartbeat =:= undefined)
+                ChangesArgs0#changes_args.timeout =:= undefined andalso
+                    ChangesArgs0#changes_args.heartbeat =:= undefined
             of
                 true ->
                     ChangesArgs0#changes_args{timeout = 1000, heartbeat = 100};

Reply via email to