You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ji...@apache.org on 2018/08/14 09:22:01 UTC

[couchdb] 01/07: Rewrite the PSE test suite to use couch_server

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

jiangphcn pushed a commit to branch COUCHDB-3326-clustered-purge-pr3-refactor-pse-tests
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e66ae51b6620105574e20e23182c2d11584e8513
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu Apr 26 11:41:01 2018 -0500

    Rewrite the PSE test suite to use couch_server
    
    It turns out that if any storage engine has to open itself during
    a callback it would end up violating the guarantee of a single writer.
    This change in the test suite changes things to use couch_server so that
    storage engines are now free to do as they want reopening themselves.
---
 src/couch/src/test_engine_attachments.erl       |  35 +--
 src/couch/src/test_engine_compaction.erl        | 154 +++++-----
 src/couch/src/test_engine_fold_changes.erl      | 134 +++++----
 src/couch/src/test_engine_fold_docs.erl         |  99 +++----
 src/couch/src/test_engine_get_set_props.erl     |  84 +++---
 src/couch/src/test_engine_open_close_delete.erl |  75 +++--
 src/couch/src/test_engine_purge_docs.erl        | 140 ++++-----
 src/couch/src/test_engine_read_write_docs.erl   | 300 ++++++++++---------
 src/couch/src/test_engine_ref_counting.erl      |  42 +--
 src/couch/src/test_engine_util.erl              | 370 ++++++++++--------------
 src/couch/test/couch_bt_engine_tests.erl        |   2 +-
 11 files changed, 713 insertions(+), 722 deletions(-)

diff --git a/src/couch/src/test_engine_attachments.erl b/src/couch/src/test_engine_attachments.erl
index 691d4bd..9763ef5 100644
--- a/src/couch/src/test_engine_attachments.erl
+++ b/src/couch/src/test_engine_attachments.erl
@@ -19,25 +19,26 @@
 
 
 cet_write_attachment() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
     AttBin = crypto:strong_rand_bytes(32768),
 
     try
-        [Att0] = test_engine_util:prep_atts(Engine, St1, [
+        [Att0] = test_engine_util:prep_atts(Db1, [
                 {<<"ohai.txt">>, AttBin}
             ]),
 
         {stream, Stream} = couch_att:fetch(data, Att0),
-        ?assertEqual(true, Engine:is_active_stream(St1, Stream)),
+        ?assertEqual(true, couch_db_engine:is_active_stream(Db1, Stream)),
 
-        Actions = [{create, {<<"first">>, [], [Att0]}}],
-        {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-        {ok, St3} = Engine:commit_data(St2),
-        Engine:terminate(normal, St3),
+        Actions = [{create, {<<"first">>, {[]}, [Att0]}}],
+        {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+        {ok, _} = couch_db:ensure_full_commit(Db2),
+        test_engine_util:shutdown_db(Db2),
 
-        {ok, St4} = Engine:init(DbPath, []),
-        [FDI] = Engine:open_docs(St4, [<<"first">>]),
+        {ok, Db3} = couch_db:reopen(Db2),
+
+        [FDI] = couch_db_engine:open_docs(Db3, [<<"first">>]),
 
         #rev_info{
             rev = {RevPos, PrevRevId},
@@ -52,12 +53,12 @@ cet_write_attachment() ->
             body = DocPtr
         },
 
-        Doc1 = Engine:read_doc_body(St4, Doc0),
+        Doc1 = couch_db_engine:read_doc_body(Db3, Doc0),
         Atts1 = if not is_binary(Doc1#doc.atts) -> Doc1#doc.atts; true ->
             couch_compress:decompress(Doc1#doc.atts)
         end,
 
-        StreamSrc = fun(Sp) -> Engine:open_read_stream(St4, Sp) end,
+        StreamSrc = fun(Sp) -> couch_db_engine:open_read_stream(Db3, Sp) end,
         [Att1] = [couch_att:from_disk_term(StreamSrc, T) || T <- Atts1],
         ReadBin = couch_att:to_binary(Att1),
         ?assertEqual(AttBin, ReadBin)
@@ -72,22 +73,22 @@ cet_write_attachment() ->
 % we ever have something that stores attachemnts in
 % an external object store)
 cet_inactive_stream() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
     AttBin = crypto:strong_rand_bytes(32768),
 
     try
-        [Att0] = test_engine_util:prep_atts(Engine, St1, [
+        [Att0] = test_engine_util:prep_atts(Db1, [
                 {<<"ohai.txt">>, AttBin}
             ]),
 
         {stream, Stream} = couch_att:fetch(data, Att0),
-        ?assertEqual(true, Engine:is_active_stream(St1, Stream)),
+        ?assertEqual(true, couch_db_engine:is_active_stream(Db1, Stream)),
 
-        Engine:terminate(normal, St1),
-        {ok, St2} = Engine:init(DbPath, []),
+        test_engine_util:shutdown_db(Db1),
+        {ok, Db2} = couch_db:reopen(Db1),
 
-        ?assertEqual(false, Engine:is_active_stream(St2, Stream))
+        ?assertEqual(false, couch_db_engine:is_active_stream(Db2, Stream))
     catch throw:not_supported ->
         ok
     end.
diff --git a/src/couch/src/test_engine_compaction.erl b/src/couch/src/test_engine_compaction.erl
index 09a1e4e..44c5357 100644
--- a/src/couch/src/test_engine_compaction.erl
+++ b/src/couch/src/test_engine_compaction.erl
@@ -19,66 +19,75 @@
 
 
 cet_compact_empty() ->
-    {ok, Engine, Path, St1} = test_engine_util:init_engine(dbpath),
-    Db1 = test_engine_util:db_as_term(Engine, St1),
-    {ok, St2, DbName, _, Term} = test_engine_util:compact(Engine, St1, Path),
-    {ok, St3, undefined} = Engine:finish_compaction(St2, DbName, [], Term),
-    Db2 = test_engine_util:db_as_term(Engine, St3),
-    Diff = test_engine_util:term_diff(Db1, Db2),
+    {ok, Db1} = test_engine_util:create_db(),
+    Term1 = test_engine_util:db_as_term(Db1),
+
+    test_engine_util:compact(Db1),
+
+    {ok, Db2} = couch_db:reopen(Db1),
+    Term2 = test_engine_util:db_as_term(Db2),
+
+    Diff = test_engine_util:term_diff(Term1, Term2),
     ?assertEqual(nodiff, Diff).
 
 
 cet_compact_doc() ->
-    {ok, Engine, Path, St1} = test_engine_util:init_engine(dbpath),
-    Actions = [{create, {<<"foo">>, []}}],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    Db1 = test_engine_util:db_as_term(Engine, St2),
-    {ok, St3, DbName, _, Term} = test_engine_util:compact(Engine, St2, Path),
-    {ok, St4, undefined} = Engine:finish_compaction(St3, DbName, [], Term),
-    Db2 = test_engine_util:db_as_term(Engine, St4),
-    Diff = test_engine_util:term_diff(Db1, Db2),
+    {ok, Db1} = test_engine_util:create_db(),
+    Actions = [{create, {<<"foo">>, {[]}}}],
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    Term1 = test_engine_util:db_as_term(Db2),
+
+    test_engine_util:compact(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
+    Term2 = test_engine_util:db_as_term(Db3),
+
+    Diff = test_engine_util:term_diff(Term1, Term2),
     ?assertEqual(nodiff, Diff).
 
 
 cet_compact_local_doc() ->
-    {ok, Engine, Path, St1} = test_engine_util:init_engine(dbpath),
-    Actions = [{create, {<<"_local/foo">>, []}}],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    Db1 = test_engine_util:db_as_term(Engine, St2),
-    {ok, St3, DbName, _, Term} = test_engine_util:compact(Engine, St2, Path),
-    {ok, St4, undefined} = Engine:finish_compaction(St3, DbName, [], Term),
-    Db2 = test_engine_util:db_as_term(Engine, St4),
-    Diff = test_engine_util:term_diff(Db1, Db2),
+    {ok, Db1} = test_engine_util:create_db(),
+    Actions = [{create, {<<"_local/foo">>, {[]}}}],
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    Term1 = test_engine_util:db_as_term(Db2),
+
+    test_engine_util:compact(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
+    Term2 = test_engine_util:db_as_term(Db3),
+
+    Diff = test_engine_util:term_diff(Term1, Term2),
     ?assertEqual(nodiff, Diff).
 
 
 cet_compact_with_everything() ->
-    {ok, Engine, Path, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
     % Add a whole bunch of docs
     DocActions = lists:map(fun(Seq) ->
-        {create, {docid(Seq), [{<<"int">>, Seq}]}}
+        {create, {docid(Seq), {[{<<"int">>, Seq}]}}}
     end, lists:seq(1, 1000)),
 
     LocalActions = lists:map(fun(I) ->
-        {create, {local_docid(I), [{<<"int">>, I}]}}
+        {create, {local_docid(I), {[{<<"int">>, I}]}}}
     end, lists:seq(1, 25)),
 
     Actions1 = DocActions ++ LocalActions,
 
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
-    {ok, St3} = Engine:set_security(St2, [{<<"readers">>, <<"ohai">>}]),
-    {ok, St4} = Engine:set_revs_limit(St3, 500),
+    {ok, Db2} = test_engine_util:apply_batch(Db1, Actions1),
+    ok = couch_db:set_security(Db1, {[{<<"foo">>, <<"bar">>}]}),
+    ok = couch_db:set_revs_limit(Db1, 500),
 
     Actions2 = [
-        {create, {<<"foo">>, []}},
-        {create, {<<"bar">>, [{<<"hooray">>, <<"purple">>}]}},
-        {conflict, {<<"bar">>, [{<<"booo">>, false}]}}
+        {create, {<<"foo">>, {[]}}},
+        {create, {<<"bar">>, {[{<<"hooray">>, <<"purple">>}]}}},
+        {conflict, {<<"bar">>, {[{<<"booo">>, false}]}}}
     ],
 
-    {ok, St5} = test_engine_util:apply_actions(Engine, St4, Actions2),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
 
-    [FooFDI, BarFDI] = Engine:open_docs(St5, [<<"foo">>, <<"bar">>]),
+    [FooFDI, BarFDI] = couch_db_engine:open_docs(Db3, [<<"foo">>, <<"bar">>]),
 
     FooRev = test_engine_util:prev_rev(FooFDI),
     BarRev = test_engine_util:prev_rev(BarFDI),
@@ -90,17 +99,20 @@ cet_compact_with_everything() ->
         ]}
     ],
 
-    {ok, St6} = test_engine_util:apply_actions(Engine, St5, Actions3),
+    {ok, Db4} = test_engine_util:apply_actions(Db3, Actions3),
 
     PurgedIdRevs = [
         {<<"bar">>, [BarRev#rev_info.rev]},
         {<<"foo">>, [FooRev#rev_info.rev]}
     ],
 
-    ?assertEqual(PurgedIdRevs, lists:sort(Engine:get_last_purged(St6))),
+    ?assertEqual(
+            PurgedIdRevs,
+            lists:sort(couch_db_engine:get_last_purged(Db4))
+        ),
 
-    {ok, St7} = try
-        [Att0, Att1, Att2, Att3, Att4] = test_engine_util:prep_atts(Engine, St6, [
+    {ok, Db5} = try
+        [Att0, Att1, Att2, Att3, Att4] = test_engine_util:prep_atts(Db4, [
                 {<<"ohai.txt">>, crypto:strong_rand_bytes(2048)},
                 {<<"stuff.py">>, crypto:strong_rand_bytes(32768)},
                 {<<"a.erl">>, crypto:strong_rand_bytes(29)},
@@ -109,69 +121,61 @@ cet_compact_with_everything() ->
             ]),
 
         Actions4 = [
-            {create, {<<"small_att">>, [], [Att0]}},
-            {create, {<<"large_att">>, [], [Att1]}},
-            {create, {<<"multi_att">>, [], [Att2, Att3, Att4]}}
+            {create, {<<"small_att">>, {[]}, [Att0]}},
+            {create, {<<"large_att">>, {[]}, [Att1]}},
+            {create, {<<"multi_att">>, {[]}, [Att2, Att3, Att4]}}
         ],
-        test_engine_util:apply_actions(Engine, St6, Actions4)
+        test_engine_util:apply_actions(Db4, Actions4)
     catch throw:not_supported ->
-        {ok, St6}
+        {ok, Db4}
     end,
-    {ok, St8} = Engine:commit_data(St7),
+    {ok, _} = couch_db:ensure_full_commit(Db5),
+    {ok, Db6} = couch_db:reopen(Db5),
 
-    Db1 = test_engine_util:db_as_term(Engine, St8),
+    Term1 = test_engine_util:db_as_term(Db6),
 
     Config = [
         {"database_compaction", "doc_buffer_size", "1024"},
         {"database_compaction", "checkpoint_after", "2048"}
     ],
 
-    {ok, St9, DbName, _, Term} = test_engine_util:with_config(Config, fun() ->
-        test_engine_util:compact(Engine, St8, Path)
+    test_engine_util:with_config(Config, fun() ->
+        test_engine_util:compact(Db6)
     end),
 
-    {ok, St10, undefined} = Engine:finish_compaction(St9, DbName, [], Term),
-    Db2 = test_engine_util:db_as_term(Engine, St10),
-    Diff = test_engine_util:term_diff(Db1, Db2),
+    {ok, Db7} = couch_db:reopen(Db6),
+    Term2 = test_engine_util:db_as_term(Db7),
+
+    Diff = test_engine_util:term_diff(Term1, Term2),
     ?assertEqual(nodiff, Diff).
 
 
 cet_recompact_updates() ->
-    {ok, Engine, Path, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    Actions1 = [
-        {create, {<<"foo">>, []}},
-        {create, {<<"bar">>, []}}
-    ],
+    Actions1 = lists:map(fun(Seq) ->
+        {create, {docid(Seq), {[{<<"int">>, Seq}]}}}
+    end, lists:seq(1, 1000)),
+    {ok, Db2} = test_engine_util:apply_batch(Db1, Actions1),
 
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
-    {ok, St3, DbName, _, Term} = test_engine_util:compact(Engine, St2, Path),
+    {ok, Compactor} = couch_db:start_compact(Db2),
+    catch erlang:suspend_process(Compactor),
 
     Actions2 = [
-        {update, {<<"foo">>, [{<<"updated">>, true}]}},
-        {create, {<<"baz">>, []}}
+        {update, {<<"0001">>, {[{<<"updated">>, true}]}}},
+        {create, {<<"boop">>, {[]}}}
     ],
 
-    {ok, St4} = test_engine_util:apply_actions(Engine, St3, Actions2),
-    Db1 = test_engine_util:db_as_term(Engine, St4),
-
-    {ok, St5, NewPid} = Engine:finish_compaction(St4, DbName, [], Term),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
+    Term1 = test_engine_util:db_as_term(Db3),
 
-    ?assertEqual(true, is_pid(NewPid)),
-    Ref = erlang:monitor(process, NewPid),
+    catch erlang:resume_process(Compactor),
+    test_engine_util:compact(Db3),
 
-    NewTerm = receive
-        {'$gen_cast', {compact_done, Engine, Term0}} ->
-            Term0;
-        {'DOWN', Ref, _, _, Reason} ->
-            erlang:error({compactor_died, Reason})
-        after 10000 ->
-            erlang:error(compactor_timed_out)
-    end,
+    {ok, Db4} = couch_db:reopen(Db3),
+    Term2 = test_engine_util:db_as_term(Db4),
 
-    {ok, St6, undefined} = Engine:finish_compaction(St5, DbName, [], NewTerm),
-    Db2 = test_engine_util:db_as_term(Engine, St6),
-    Diff = test_engine_util:term_diff(Db1, Db2),
+    Diff = test_engine_util:term_diff(Term1, Term2),
     ?assertEqual(nodiff, Diff).
 
 
diff --git a/src/couch/src/test_engine_fold_changes.erl b/src/couch/src/test_engine_fold_changes.erl
index 6e97fda..4ca09a8 100644
--- a/src/couch/src/test_engine_fold_changes.erl
+++ b/src/couch/src/test_engine_fold_changes.erl
@@ -18,147 +18,153 @@
 -include_lib("couch/include/couch_db.hrl").
 
 
--define(NUM_DOCS, 100).
+-define(NUM_DOCS, 25).
 
 
 cet_empty_changes() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
-
-    ?assertEqual(0, Engine:count_changes_since(St, 0)),
-    ?assertEqual({ok, []}, Engine:fold_changes(St, 0, fun fold_fun/2, [], [])).
+    {ok, Db} = test_engine_util:create_db(),
+    ?assertEqual(0, couch_db_engine:count_changes_since(Db, 0)),
+    ?assertEqual({ok, []},
+            couch_db_engine:fold_changes(Db, 0, fun fold_fun/2, [], [])).
 
 
 cet_single_change() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
-    Actions = [{create, {<<"a">>, []}}],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db1} = test_engine_util:create_db(),
+    Actions = [{create, {<<"a">>, {[]}}}],
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
-    ?assertEqual(1, Engine:count_changes_since(St2, 0)),
+    ?assertEqual(1, couch_db_engine:count_changes_since(Db2, 0)),
     ?assertEqual({ok, [{<<"a">>, 1}]},
-            Engine:fold_changes(St2, 0, fun fold_fun/2, [], [])).
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], [])).
 
 
 cet_two_changes() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions = [
-        {create, {<<"a">>, []}},
-        {create, {<<"b">>, []}}
+        {create, {<<"a">>, {[]}}},
+        {create, {<<"b">>, {[]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
-    ?assertEqual(2, Engine:count_changes_since(St2, 0)),
-    {ok, Changes} = Engine:fold_changes(St2, 0, fun fold_fun/2, [], []),
+    ?assertEqual(2, couch_db_engine:count_changes_since(Db2, 0)),
+    {ok, Changes} =
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], []),
     ?assertEqual([{<<"a">>, 1}, {<<"b">>, 2}], lists:reverse(Changes)).
 
 
 cet_two_changes_batch() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions1 = [
         {batch, [
-            {create, {<<"a">>, []}},
-            {create, {<<"b">>, []}}
+            {create, {<<"a">>, {[]}}},
+            {create, {<<"b">>, {[]}}}
         ]}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions1),
 
-    ?assertEqual(2, Engine:count_changes_since(St2, 0)),
-    {ok, Changes1} = Engine:fold_changes(St2, 0, fun fold_fun/2, [], []),
+    ?assertEqual(2, couch_db_engine:count_changes_since(Db2, 0)),
+    {ok, Changes1} =
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], []),
     ?assertEqual([{<<"a">>, 1}, {<<"b">>, 2}], lists:reverse(Changes1)),
 
-    {ok, Engine, St3} = test_engine_util:init_engine(),
+    {ok, Db3} = test_engine_util:create_db(),
     Actions2 = [
         {batch, [
-            {create, {<<"b">>, []}},
-            {create, {<<"a">>, []}}
+            {create, {<<"b">>, {[]}}},
+            {create, {<<"a">>, {[]}}}
         ]}
     ],
-    {ok, St4} = test_engine_util:apply_actions(Engine, St3, Actions2),
+    {ok, Db4} = test_engine_util:apply_actions(Db3, Actions2),
 
-    ?assertEqual(2, Engine:count_changes_since(St4, 0)),
-    {ok, Changes2} = Engine:fold_changes(St4, 0, fun fold_fun/2, [], []),
-    ?assertEqual([{<<"b">>, 1}, {<<"a">>, 2}], lists:reverse(Changes2)).
+    ?assertEqual(2, couch_db_engine:count_changes_since(Db4, 0)),
+    {ok, Changes2} =
+            couch_db_engine:fold_changes(Db4, 0, fun fold_fun/2, [], []),
+    ?assertEqual([{<<"a">>, 1}, {<<"b">>, 2}], lists:reverse(Changes2)).
 
 
 cet_update_one() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions = [
-        {create, {<<"a">>, []}},
-        {update, {<<"a">>, []}}
+        {create, {<<"a">>, {[]}}},
+        {update, {<<"a">>, {[]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
-    ?assertEqual(1, Engine:count_changes_since(St2, 0)),
+    ?assertEqual(1, couch_db_engine:count_changes_since(Db2, 0)),
     ?assertEqual({ok, [{<<"a">>, 2}]},
-            Engine:fold_changes(St2, 0, fun fold_fun/2, [], [])).
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], [])).
 
 
 cet_update_first_of_two() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions = [
-        {create, {<<"a">>, []}},
-        {create, {<<"b">>, []}},
-        {update, {<<"a">>, []}}
+        {create, {<<"a">>, {[]}}},
+        {create, {<<"b">>, {[]}}},
+        {update, {<<"a">>, {[]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
-    ?assertEqual(2, Engine:count_changes_since(St2, 0)),
-    {ok, Changes} = Engine:fold_changes(St2, 0, fun fold_fun/2, [], []),
+    ?assertEqual(2, couch_db_engine:count_changes_since(Db2, 0)),
+    {ok, Changes} =
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], []),
     ?assertEqual([{<<"b">>, 2}, {<<"a">>, 3}], lists:reverse(Changes)).
 
 
 cet_update_second_of_two() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions = [
-        {create, {<<"a">>, []}},
-        {create, {<<"b">>, []}},
-        {update, {<<"b">>, []}}
+        {create, {<<"a">>, {[]}}},
+        {create, {<<"b">>, {[]}}},
+        {update, {<<"b">>, {[]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
-    ?assertEqual(2, Engine:count_changes_since(St2, 0)),
-    {ok, Changes} = Engine:fold_changes(St2, 0, fun fold_fun/2, [], []),
+    ?assertEqual(2, couch_db_engine:count_changes_since(Db2, 0)),
+    {ok, Changes} =
+            couch_db_engine:fold_changes(Db2, 0, fun fold_fun/2, [], []),
     ?assertEqual([{<<"a">>, 1}, {<<"b">>, 3}], lists:reverse(Changes)).
 
 
 cet_check_mutation_ordering() ->
     Actions = shuffle(lists:map(fun(Seq) ->
-        {create, {docid(Seq), []}}
+        {create, {docid(Seq), {[]}}}
     end, lists:seq(1, ?NUM_DOCS))),
 
     DocIdOrder = [DocId || {_, {DocId, _}} <- Actions],
     DocSeqs = lists:zip(DocIdOrder, lists:seq(1, ?NUM_DOCS)),
 
-    {ok, Engine, St1} = test_engine_util:init_engine(),
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
+    {ok, Db1} = test_engine_util:create_db(),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
 
     % First lets see that we can get the correct
     % suffix/prefix starting at every update sequence
     lists:foreach(fun(Seq) ->
-        {ok, Suffix} = Engine:fold_changes(St2, Seq, fun fold_fun/2, [], []),
+        {ok, Suffix} =
+                couch_db_engine:fold_changes(Db2, Seq, fun fold_fun/2, [], []),
         ?assertEqual(lists:nthtail(Seq, DocSeqs), lists:reverse(Suffix)),
 
-        {ok, Prefix} = Engine:fold_changes(St2, Seq, fun fold_fun/2, [], [
-                {dir, rev}
-            ]),
+        {ok, Prefix} = couch_db_engine:fold_changes(
+                Db2, Seq, fun fold_fun/2, [], [{dir, rev}]),
         ?assertEqual(lists:sublist(DocSeqs, Seq + 1), Prefix)
     end, lists:seq(0, ?NUM_DOCS)),
 
-    ok = do_mutation_ordering(Engine, St2, ?NUM_DOCS + 1, DocSeqs, []).
+    ok = do_mutation_ordering(Db2, ?NUM_DOCS + 1, DocSeqs, []).
 
 
-do_mutation_ordering(Engine, St, _Seq, [], FinalDocSeqs) ->
-    {ok, RevOrder} = Engine:fold_changes(St, 0, fun fold_fun/2, [], []),
+do_mutation_ordering(Db, _Seq, [], FinalDocSeqs) ->
+    {ok, RevOrder} = couch_db_engine:fold_changes(Db, 0, fun fold_fun/2, [], []),
     ?assertEqual(FinalDocSeqs, lists:reverse(RevOrder)),
     ok;
 
-do_mutation_ordering(Engine, St, Seq, [{DocId, _OldSeq} | Rest], DocSeqAcc) ->
-    Actions = [{update, {DocId, []}}],
-    {ok, NewSt} = test_engine_util:apply_actions(Engine, St, Actions),
+do_mutation_ordering(Db, Seq, [{DocId, _OldSeq} | Rest], DocSeqAcc) ->
+    Actions = [{update, {DocId, {[]}}}],
+    {ok, NewDb} = test_engine_util:apply_actions(Db, Actions),
     NewAcc = DocSeqAcc ++ [{DocId, Seq}],
     Expected = Rest ++ NewAcc,
-    {ok, RevOrder} = Engine:fold_changes(NewSt, 0, fun fold_fun/2, [], []),
+    {ok, RevOrder} =
+            couch_db_engine:fold_changes(NewDb, 0, fun fold_fun/2, [], []),
     ?assertEqual(Expected, lists:reverse(RevOrder)),
-    do_mutation_ordering(Engine, NewSt, Seq + 1, Rest, NewAcc).
+    do_mutation_ordering(NewDb, Seq + 1, Rest, NewAcc).
 
 
 shuffle(List) ->
diff --git a/src/couch/src/test_engine_fold_docs.erl b/src/couch/src/test_engine_fold_docs.erl
index 458878d..3ed068f 100644
--- a/src/couch/src/test_engine_fold_docs.erl
+++ b/src/couch/src/test_engine_fold_docs.erl
@@ -62,39 +62,41 @@ cet_fold_range_local() ->
 
 
 cet_fold_stop() ->
-    fold_stop(fold_docs, fun docid/1).
+    fold_user_fun_stop(fold_docs, fun docid/1).
 
 
 cet_fold_stop_local() ->
-    fold_stop(fold_local_docs, fun local_docid/1).
+    fold_user_fun_stop(fold_local_docs, fun local_docid/1).
 
 
 % This is a loose test but we have to have this until
 % I figure out what to do about the total_rows/offset
 % meta data included in _all_docs
 cet_fold_include_reductions() ->
-    {ok, Engine, St} = init_st(fun docid/1),
+    {ok, Db} = init_st(fun docid/1),
     FoldFun = fun(_, _, nil) -> {ok, nil} end,
-    {ok, Count, nil} = Engine:fold_docs(St, FoldFun, nil, [include_reductions]),
+    Opts = [include_reductions],
+    {ok, Count, nil} = couch_db_engine:fold_docs(Db, FoldFun, nil, Opts),
     ?assert(is_integer(Count)),
     ?assert(Count >= 0).
 
 
 fold_all(FoldFun, DocIdFun) ->
     DocIds = [DocIdFun(I) || I <- lists:seq(1, ?NUM_DOCS)],
-    {ok, Engine, St} = init_st(DocIdFun),
+    {ok, Db} = init_st(DocIdFun),
 
-    {ok, DocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], []),
+    {ok, DocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], []),
     ?assertEqual(?NUM_DOCS, length(DocIdAccFwd)),
     ?assertEqual(DocIds, lists:reverse(DocIdAccFwd)),
 
-    {ok, DocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [{dir, rev}]),
+    Opts = [{dir, rev}],
+    {ok, DocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], Opts),
     ?assertEqual(?NUM_DOCS, length(DocIdAccRev)),
     ?assertEqual(DocIds, DocIdAccRev).
 
 
 fold_start_key(FoldFun, DocIdFun) ->
-    {ok, Engine, St} = init_st(DocIdFun),
+    {ok, Db} = init_st(DocIdFun),
 
     StartKeyNum = ?NUM_DOCS div 4,
     StartKey = DocIdFun(StartKeyNum),
@@ -103,35 +105,35 @@ fold_start_key(FoldFun, DocIdFun) ->
     DocIdsFwd = [DocIdFun(I) || I <- lists:seq(StartKeyNum, ?NUM_DOCS)],
     DocIdsRev = [DocIdFun(I) || I <- lists:seq(1, StartKeyNum)],
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, <<255>>}
         ])),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, <<"">>}
         ])),
 
-    {ok, AllDocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, <<"">>}
         ]),
     ?assertEqual(length(AllDocIds), length(AllDocIdAccFwd)),
     ?assertEqual(AllDocIds, lists:reverse(AllDocIdAccFwd)),
 
-    {ok, AllDocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, <<255>>}
         ]),
     ?assertEqual(length(AllDocIds), length(AllDocIdAccRev)),
     ?assertEqual(AllDocIds, AllDocIdAccRev),
 
-    {ok, DocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, StartKey}
         ]),
     ?assertEqual(length(DocIdsFwd), length(DocIdAccFwd)),
     ?assertEqual(DocIdsFwd, lists:reverse(DocIdAccFwd)),
 
-    {ok, DocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, StartKey}
         ]),
@@ -140,29 +142,29 @@ fold_start_key(FoldFun, DocIdFun) ->
 
 
 fold_end_key(FoldFun, DocIdFun) ->
-    {ok, Engine, St} = init_st(DocIdFun),
+    {ok, Db} = init_st(DocIdFun),
 
     EndKeyNum = ?NUM_DOCS div 4,
     EndKey = DocIdFun(EndKeyNum),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key, <<"">>}
         ])),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key, <<255>>}
         ])),
 
     AllDocIds = [DocIdFun(I) || I <- lists:seq(1, ?NUM_DOCS)],
 
-    {ok, AllDocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key, <<255>>}
         ]),
     ?assertEqual(length(AllDocIds), length(AllDocIdAccFwd)),
     ?assertEqual(AllDocIds, lists:reverse(AllDocIdAccFwd)),
 
-    {ok, AllDocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key, <<"">>}
         ]),
@@ -171,7 +173,7 @@ fold_end_key(FoldFun, DocIdFun) ->
 
     DocIdsFwd = [DocIdFun(I) || I <- lists:seq(1, EndKeyNum)],
 
-    {ok, DocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key, EndKey}
         ]),
     ?assertEqual(length(DocIdsFwd), length(DocIdAccFwd)),
@@ -179,7 +181,7 @@ fold_end_key(FoldFun, DocIdFun) ->
 
     DocIdsRev = [DocIdFun(I) || I <- lists:seq(EndKeyNum, ?NUM_DOCS)],
 
-    {ok, DocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key, EndKey}
         ]),
@@ -188,29 +190,29 @@ fold_end_key(FoldFun, DocIdFun) ->
 
 
 fold_end_key_gt(FoldFun, DocIdFun) ->
-    {ok, Engine, St} = init_st(DocIdFun),
+    {ok, Db} = init_st(DocIdFun),
 
     EndKeyNum = ?NUM_DOCS div 4,
     EndKey = DocIdFun(EndKeyNum),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key_gt, <<"">>}
         ])),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key_gt, <<255>>}
         ])),
 
     AllDocIds = [DocIdFun(I) || I <- lists:seq(1, ?NUM_DOCS)],
 
-    {ok, AllDocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key_gt, <<255>>}
         ]),
     ?assertEqual(length(AllDocIds), length(AllDocIdAccFwd)),
     ?assertEqual(AllDocIds, lists:reverse(AllDocIdAccFwd)),
 
-    {ok, AllDocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key_gt, <<"">>}
         ]),
@@ -219,7 +221,7 @@ fold_end_key_gt(FoldFun, DocIdFun) ->
 
     DocIdsFwd = [DocIdFun(I) || I <- lists:seq(1, EndKeyNum - 1)],
 
-    {ok, DocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {end_key_gt, EndKey}
         ]),
     ?assertEqual(length(DocIdsFwd), length(DocIdAccFwd)),
@@ -227,7 +229,7 @@ fold_end_key_gt(FoldFun, DocIdFun) ->
 
     DocIdsRev = [DocIdFun(I) || I <- lists:seq(EndKeyNum + 1, ?NUM_DOCS)],
 
-    {ok, DocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {end_key_gt, EndKey}
         ]),
@@ -236,7 +238,7 @@ fold_end_key_gt(FoldFun, DocIdFun) ->
 
 
 fold_range(FoldFun, DocIdFun) ->
-    {ok, Engine, St} = init_st(DocIdFun),
+    {ok, Db} = init_st(DocIdFun),
 
     StartKeyNum = ?NUM_DOCS div 4,
     EndKeyNum = StartKeyNum * 3,
@@ -244,12 +246,12 @@ fold_range(FoldFun, DocIdFun) ->
     StartKey = DocIdFun(StartKeyNum),
     EndKey = DocIdFun(EndKeyNum),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, <<"">>},
             {end_key, <<"">>}
         ])),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, <<"">>},
             {end_key, <<255>>}
@@ -257,14 +259,14 @@ fold_range(FoldFun, DocIdFun) ->
 
     AllDocIds = [DocIdFun(I) || I <- lists:seq(1, ?NUM_DOCS)],
 
-    {ok, AllDocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, <<"">>},
             {end_key, <<255>>}
         ]),
     ?assertEqual(length(AllDocIds), length(AllDocIdAccFwd)),
     ?assertEqual(AllDocIds, lists:reverse(AllDocIdAccFwd)),
 
-    {ok, AllDocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, AllDocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, <<255>>},
             {end_key_gt, <<"">>}
@@ -274,7 +276,7 @@ fold_range(FoldFun, DocIdFun) ->
 
     DocIdsFwd = [DocIdFun(I) || I <- lists:seq(StartKeyNum, EndKeyNum)],
 
-    {ok, DocIdAccFwd} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {start_key, StartKey},
             {end_key, EndKey}
         ]),
@@ -283,13 +285,13 @@ fold_range(FoldFun, DocIdFun) ->
 
     DocIdsRev = [DocIdFun(I) || I <- lists:seq(StartKeyNum, EndKeyNum)],
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, StartKey},
             {end_key, EndKey}
         ])),
 
-    {ok, DocIdAccRev} = Engine:FoldFun(St, fun fold_fun/2, [], [
+    {ok, DocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_fun/2, [], [
             {dir, rev},
             {start_key, EndKey},
             {end_key, StartKey}
@@ -298,24 +300,24 @@ fold_range(FoldFun, DocIdFun) ->
     ?assertEqual(DocIdsRev, DocIdAccRev).
 
 
-fold_stop(FoldFun, DocIdFun) ->
-    {ok, Engine, St} = init_st(DocIdFun),
+fold_user_fun_stop(FoldFun, DocIdFun) ->
+    {ok, Db} = init_st(DocIdFun),
 
     StartKeyNum = ?NUM_DOCS div 4,
     StartKey = DocIdFun(StartKeyNum),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {start_key, <<255>>}
         ])),
 
-    ?assertEqual({ok, []}, Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    ?assertEqual({ok, []}, couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {dir, rev},
             {start_key, <<"">>}
         ])),
 
     SuffixDocIds = [DocIdFun(I) || I <- lists:seq(?NUM_DOCS - 3, ?NUM_DOCS)],
 
-    {ok, SuffixDocIdAcc} = Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    {ok, SuffixDocIdAcc} = couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {start_key, DocIdFun(?NUM_DOCS - 3)}
         ]),
     ?assertEqual(length(SuffixDocIds), length(SuffixDocIdAcc)),
@@ -323,7 +325,7 @@ fold_stop(FoldFun, DocIdFun) ->
 
     PrefixDocIds = [DocIdFun(I) || I <- lists:seq(1, 3)],
 
-    {ok, PrefixDocIdAcc} = Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    {ok, PrefixDocIdAcc} = couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {dir, rev},
             {start_key, DocIdFun(3)}
         ]),
@@ -333,7 +335,7 @@ fold_stop(FoldFun, DocIdFun) ->
     FiveDocIdsFwd = [DocIdFun(I)
             || I <- lists:seq(StartKeyNum, StartKeyNum + 5)],
 
-    {ok, FiveDocIdAccFwd} = Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    {ok, FiveDocIdAccFwd} = couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {start_key, StartKey}
         ]),
     ?assertEqual(length(FiveDocIdsFwd), length(FiveDocIdAccFwd)),
@@ -342,7 +344,7 @@ fold_stop(FoldFun, DocIdFun) ->
     FiveDocIdsRev = [DocIdFun(I)
             || I <- lists:seq(StartKeyNum - 5, StartKeyNum)],
 
-    {ok, FiveDocIdAccRev} = Engine:FoldFun(St, fun fold_fun_stop/2, [], [
+    {ok, FiveDocIdAccRev} = couch_db_engine:FoldFun(Db, fun fold_stop/2, [], [
             {dir, rev},
             {start_key, StartKey}
         ]),
@@ -351,12 +353,11 @@ fold_stop(FoldFun, DocIdFun) ->
 
 
 init_st(DocIdFun) ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
     Actions = lists:map(fun(Id) ->
-        {create, {DocIdFun(Id), [{<<"int">>, Id}]}}
+        {create, {DocIdFun(Id), {[{<<"int">>, Id}]}}}
     end, lists:seq(1, ?NUM_DOCS)),
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, Engine, St2}.
+    test_engine_util:apply_batch(Db1, Actions).
 
 
 fold_fun(Doc, Acc) ->
@@ -367,7 +368,7 @@ fold_fun(Doc, Acc) ->
     {ok, [Id | Acc]}.
 
 
-fold_fun_stop(Doc, Acc) ->
+fold_stop(Doc, Acc) ->
     Id = case Doc of
         #doc{id = Id0} -> Id0;
         #full_doc_info{id = Id0} -> Id0
diff --git a/src/couch/src/test_engine_get_set_props.erl b/src/couch/src/test_engine_get_set_props.erl
index 6d2a447..764fe39 100644
--- a/src/couch/src/test_engine_get_set_props.erl
+++ b/src/couch/src/test_engine_get_set_props.erl
@@ -18,32 +18,52 @@
 
 
 cet_default_props() ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
-
-    {ok, St} = Engine:init(DbPath, [
-            create,
-            {default_security_object, dso}
-        ]),
-
+    {ok, {_App, Engine, _Extension}} = application:get_env(couch, test_engine),
+    {ok, Db} = test_engine_util:create_db(),
     Node = node(),
 
-    ?assertEqual(0, Engine:get_doc_count(St)),
-    ?assertEqual(0, Engine:get_del_doc_count(St)),
-    ?assertEqual(true, is_list(Engine:get_size_info(St))),
-    ?assertEqual(true, is_integer(Engine:get_disk_version(St))),
-    ?assertEqual(0, Engine:get_update_seq(St)),
-    ?assertEqual(0, Engine:get_purge_seq(St)),
-    ?assertEqual([], Engine:get_last_purged(St)),
-    ?assertEqual(dso, Engine:get_security(St)),
-    ?assertEqual(1000, Engine:get_revs_limit(St)),
-    ?assertMatch(<<_:32/binary>>, Engine:get_uuid(St)),
-    ?assertEqual([{Node, 0}], Engine:get_epochs(St)),
-    ?assertEqual(0, Engine:get_compacted_seq(St)).
+    ?assertEqual(Engine, couch_db_engine:get_engine(Db)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db)),
+    ?assertEqual(true, is_list(couch_db_engine:get_size_info(Db))),
+    ?assertEqual(true, is_integer(couch_db_engine:get_disk_version(Db))),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db)),
+    ?assertEqual(0, couch_db_engine:get_purge_seq(Db)),
+    ?assertEqual([], couch_db_engine:get_last_purged(Db)),
+    ?assertEqual([], couch_db_engine:get_security(Db)),
+    ?assertEqual(1000, couch_db_engine:get_revs_limit(Db)),
+    ?assertMatch(<<_:32/binary>>, couch_db_engine:get_uuid(Db)),
+    ?assertEqual([{Node, 0}], couch_db_engine:get_epochs(Db)),
+    ?assertEqual(0, couch_db_engine:get_compacted_seq(Db)).
+
+
+-define(ADMIN_ONLY_SEC_PROPS, {[
+    {<<"members">>, {[
+        {<<"roles">>, [<<"_admin">>]}
+    ]}},
+    {<<"admins">>, {[
+        {<<"roles">>, [<<"_admin">>]}
+    ]}}
+]}).
+
+
+cet_admin_only_security() ->
+    Config = [{"couchdb", "default_security", "admin_only"}],
+    {ok, Db1} = test_engine_util:with_config(Config, fun() ->
+        test_engine_util:create_db()
+    end),
+
+    ?assertEqual(?ADMIN_ONLY_SEC_PROPS, couch_db:get_security(Db1)),
+    test_engine_util:shutdown_db(Db1),
+
+    {ok, Db2} = couch_db:reopen(Db1),
+    couch_log:error("~n~n~n~n~s -> ~s~n~n", [couch_db:name(Db1), couch_db:name(Db2)]),
+    ?assertEqual(?ADMIN_ONLY_SEC_PROPS, couch_db:get_security(Db2)).
 
 
 cet_set_security() ->
-    check_prop_set(get_security, set_security, dso, [{<<"readers">>, []}]).
+    SecProps = {[{<<"foo">>, <<"bar">>}]},
+    check_prop_set(get_security, set_security, {[]}, SecProps).
 
 
 cet_set_revs_limit() ->
@@ -51,20 +71,16 @@ cet_set_revs_limit() ->
 
 
 check_prop_set(GetFun, SetFun, Default, Value) ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
+    {ok, Db0} = test_engine_util:create_db(),
 
-    {ok, St0} = Engine:init(DbPath, [
-            create,
-            {default_security_object, dso}
-        ]),
-    ?assertEqual(Default, Engine:GetFun(St0)),
+    ?assertEqual(Default, couch_db:GetFun(Db0)),
+    ?assertMatch(ok, couch_db:SetFun(Db0, Value)),
 
-    {ok, St1} = Engine:SetFun(St0, Value),
-    ?assertEqual(Value, Engine:GetFun(St1)),
+    {ok, Db1} = couch_db:reopen(Db0),
+    ?assertEqual(Value, couch_db:GetFun(Db1)),
 
-    {ok, St2} = Engine:commit_data(St1),
-    Engine:terminate(normal, St2),
+    ?assertMatch({ok, _}, couch_db:ensure_full_commit(Db1)),
+    test_engine_util:shutdown_db(Db1),
 
-    {ok, St3} = Engine:init(DbPath, []),
-    ?assertEqual(Value, Engine:GetFun(St3)).
+    {ok, Db2} = couch_db:reopen(Db1),
+    ?assertEqual(Value, couch_db:GetFun(Db2)).
diff --git a/src/couch/src/test_engine_open_close_delete.erl b/src/couch/src/test_engine_open_close_delete.erl
index b099d9f..ce0187e 100644
--- a/src/couch/src/test_engine_open_close_delete.erl
+++ b/src/couch/src/test_engine_open_close_delete.erl
@@ -18,64 +18,59 @@
 
 
 cet_open_non_existent() ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
-
-    ?assertEqual(false, Engine:exists(DbPath)),
-    ?assertThrow({not_found, no_db_file}, Engine:init(DbPath, [])),
-    ?assertEqual(false, Engine:exists(DbPath)).
+    % Try twice to check that a failed open doesn't create
+    % the database for some reason.
+    DbName = test_engine_util:dbname(),
+    ?assertEqual({not_found, no_db_file}, test_engine_util:open_db(DbName)),
+    ?assertEqual({not_found, no_db_file}, test_engine_util:open_db(DbName)).
 
 
 cet_open_create() ->
-    process_flag(trap_exit, true),
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
+    DbName = test_engine_util:dbname(),
 
-    ?assertEqual(false, Engine:exists(DbPath)),
-    ?assertMatch({ok, _}, Engine:init(DbPath, [create])),
-    ?assertEqual(true, Engine:exists(DbPath)).
+    ?assertEqual(false, couch_server:exists(DbName)),
+    ?assertEqual({not_found, no_db_file}, test_engine_util:open_db(DbName)),
+    ?assertMatch({ok, _}, test_engine_util:create_db(DbName)),
+    ?assertEqual(true, couch_server:exists(DbName)).
 
 
 cet_open_when_exists() ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
+    DbName = test_engine_util:dbname(),
 
-    ?assertEqual(false, Engine:exists(DbPath)),
-    ?assertMatch({ok, _}, Engine:init(DbPath, [create])),
-    ?assertThrow({error, eexist}, Engine:init(DbPath, [create])).
+    ?assertEqual(false, couch_server:exists(DbName)),
+    ?assertEqual({not_found, no_db_file}, test_engine_util:open_db(DbName)),
+    ?assertMatch({ok, _}, test_engine_util:create_db(DbName)),
+    ?assertEqual(file_exists, test_engine_util:create_db(DbName)).
 
 
 cet_terminate() ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
+    DbName = test_engine_util:dbname(),
 
-    ?assertEqual(false, Engine:exists(DbPath)),
-    {ok, St} = Engine:init(DbPath, [create]),
-    Engine:terminate(normal, St),
-    ?assertEqual(true, Engine:exists(DbPath)).
+    ?assertEqual(false, couch_server:exists(DbName)),
+    ?assertEqual({not_found, no_db_file}, test_engine_util:open_db(DbName)),
+    ?assertEqual(ok, cycle_db(DbName, create_db)),
+    ?assertEqual(true, couch_server:exists(DbName)).
 
 
 cet_rapid_recycle() ->
-    Engine = test_engine_util:get_engine(),
-    DbPath = test_engine_util:dbpath(),
-
-    {ok, St0} = Engine:init(DbPath, [create]),
-    Engine:terminate(normal, St0),
+    DbName = test_engine_util:dbname(),
 
+    ?assertEqual(ok, cycle_db(DbName, create_db)),
     lists:foreach(fun(_) ->
-        {ok, St1} = Engine:init(DbPath, []),
-        Engine:terminate(normal, St1)
+        ?assertEqual(ok, cycle_db(DbName, open_db))
     end, lists:seq(1, 100)).
 
 
 cet_delete() ->
-    Engine = test_engine_util:get_engine(),
-    RootDir = test_engine_util:rootdir(),
-    DbPath = test_engine_util:dbpath(),
-
-    ?assertEqual(false, Engine:exists(DbPath)),
-    {ok, St} = Engine:init(DbPath, [create]),
-    Engine:terminate(normal, St),
-    ?assertEqual(true, Engine:exists(DbPath)),
-    ?assertEqual(ok, Engine:delete(RootDir, DbPath, [async])),
-    ?assertEqual(false, Engine:exists(DbPath)).
+    DbName = test_engine_util:dbname(),
+
+    ?assertEqual(false, couch_server:exists(DbName)),
+    ?assertMatch(ok, cycle_db(DbName, create_db)),
+    ?assertEqual(true, couch_server:exists(DbName)),
+    ?assertEqual(ok, couch_server:delete(DbName, [])),
+    ?assertEqual(false, couch_server:exists(DbName)).
+
+
+cycle_db(DbName, Type) ->
+    {ok, Db} = test_engine_util:Type(DbName),
+    test_engine_util:shutdown_db(Db).
diff --git a/src/couch/src/test_engine_purge_docs.erl b/src/couch/src/test_engine_purge_docs.erl
index e5bf249..7d83f60 100644
--- a/src/couch/src/test_engine_purge_docs.erl
+++ b/src/couch/src/test_engine_purge_docs.erl
@@ -19,140 +19,140 @@
 
 
 cet_purge_simple() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
 
     Actions1 = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions1),
 
-    ?assertEqual(1, Engine:get_doc_count(St2)),
-    ?assertEqual(0, Engine:get_del_doc_count(St2)),
-    ?assertEqual(1, Engine:get_update_seq(St2)),
-    ?assertEqual(0, Engine:get_purge_seq(St2)),
-    ?assertEqual([], Engine:get_last_purged(St2)),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db2)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db2)),
+    ?assertEqual(1, couch_db_engine:get_update_seq(Db2)),
+    ?assertEqual(0, couch_db_engine:get_purge_seq(Db2)),
+    ?assertEqual([], couch_db_engine:get_last_purged(Db2)),
 
-    [FDI] = Engine:open_docs(St2, [<<"foo">>]),
+    [FDI] = couch_db_engine:open_docs(Db2, [<<"foo">>]),
     PrevRev = test_engine_util:prev_rev(FDI),
     Rev = PrevRev#rev_info.rev,
 
     Actions2 = [
         {purge, {<<"foo">>, Rev}}
     ],
-    {ok, St3} = test_engine_util:apply_actions(Engine, St2, Actions2),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
 
-    ?assertEqual(0, Engine:get_doc_count(St3)),
-    ?assertEqual(0, Engine:get_del_doc_count(St3)),
-    ?assertEqual(2, Engine:get_update_seq(St3)),
-    ?assertEqual(1, Engine:get_purge_seq(St3)),
-    ?assertEqual([{<<"foo">>, [Rev]}], Engine:get_last_purged(St3)).
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db3)),
+    ?assertEqual(1, couch_db_engine:get_purge_seq(Db3)),
+    ?assertEqual([{<<"foo">>, [Rev]}], couch_db_engine:get_last_purged(Db3)).
 
 
 cet_purge_conflicts() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
 
     Actions1 = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {conflict, {<<"foo">>, [{<<"vsn">>, 2}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {conflict, {<<"foo">>, {[{<<"vsn">>, 2}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions1),
 
-    ?assertEqual(1, Engine:get_doc_count(St2)),
-    ?assertEqual(0, Engine:get_del_doc_count(St2)),
-    ?assertEqual(2, Engine:get_update_seq(St2)),
-    ?assertEqual(0, Engine:get_purge_seq(St2)),
-    ?assertEqual([], Engine:get_last_purged(St2)),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db2)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db2)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db2)),
+    ?assertEqual(0, couch_db_engine:get_purge_seq(Db2)),
+    ?assertEqual([], couch_db_engine:get_last_purged(Db2)),
 
-    [FDI1] = Engine:open_docs(St2, [<<"foo">>]),
+    [FDI1] = couch_db_engine:open_docs(Db2, [<<"foo">>]),
     PrevRev1 = test_engine_util:prev_rev(FDI1),
     Rev1 = PrevRev1#rev_info.rev,
 
     Actions2 = [
         {purge, {<<"foo">>, Rev1}}
     ],
-    {ok, St3} = test_engine_util:apply_actions(Engine, St2, Actions2),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
 
-    ?assertEqual(1, Engine:get_doc_count(St3)),
-    ?assertEqual(0, Engine:get_del_doc_count(St3)),
-    ?assertEqual(4, Engine:get_update_seq(St3)),
-    ?assertEqual(1, Engine:get_purge_seq(St3)),
-    ?assertEqual([{<<"foo">>, [Rev1]}], Engine:get_last_purged(St3)),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(4, couch_db_engine:get_update_seq(Db3)),
+    ?assertEqual(1, couch_db_engine:get_purge_seq(Db3)),
+    ?assertEqual([{<<"foo">>, [Rev1]}], couch_db_engine:get_last_purged(Db3)),
 
-    [FDI2] = Engine:open_docs(St3, [<<"foo">>]),
+    [FDI2] = couch_db_engine:open_docs(Db3, [<<"foo">>]),
     PrevRev2 = test_engine_util:prev_rev(FDI2),
     Rev2 = PrevRev2#rev_info.rev,
 
     Actions3 = [
         {purge, {<<"foo">>, Rev2}}
     ],
-    {ok, St4} = test_engine_util:apply_actions(Engine, St3, Actions3),
+    {ok, Db4} = test_engine_util:apply_actions(Db3, Actions3),
 
-    ?assertEqual(0, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(5, Engine:get_update_seq(St4)),
-    ?assertEqual(2, Engine:get_purge_seq(St4)),
-    ?assertEqual([{<<"foo">>, [Rev2]}], Engine:get_last_purged(St4)).
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db4)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db4)),
+    ?assertEqual(5, couch_db_engine:get_update_seq(Db4)),
+    ?assertEqual(2, couch_db_engine:get_purge_seq(Db4)),
+    ?assertEqual([{<<"foo">>, [Rev2]}], couch_db_engine:get_last_purged(Db4)).
 
 
 cet_add_delete_purge() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
 
     Actions1 = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {delete, {<<"foo">>, [{<<"vsn">>, 2}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {delete, {<<"foo">>, {[{<<"vsn">>, 2}]}}}
     ],
 
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions1),
 
-    ?assertEqual(0, Engine:get_doc_count(St2)),
-    ?assertEqual(1, Engine:get_del_doc_count(St2)),
-    ?assertEqual(2, Engine:get_update_seq(St2)),
-    ?assertEqual(0, Engine:get_purge_seq(St2)),
-    ?assertEqual([], Engine:get_last_purged(St2)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db2)),
+    ?assertEqual(1, couch_db_engine:get_del_doc_count(Db2)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db2)),
+    ?assertEqual(0, couch_db_engine:get_purge_seq(Db2)),
+    ?assertEqual([], couch_db_engine:get_last_purged(Db2)),
 
-    [FDI] = Engine:open_docs(St2, [<<"foo">>]),
+    [FDI] = couch_db_engine:open_docs(Db2, [<<"foo">>]),
     PrevRev = test_engine_util:prev_rev(FDI),
     Rev = PrevRev#rev_info.rev,
 
     Actions2 = [
         {purge, {<<"foo">>, Rev}}
     ],
-    {ok, St3} = test_engine_util:apply_actions(Engine, St2, Actions2),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
 
-    ?assertEqual(0, Engine:get_doc_count(St3)),
-    ?assertEqual(0, Engine:get_del_doc_count(St3)),
-    ?assertEqual(3, Engine:get_update_seq(St3)),
-    ?assertEqual(1, Engine:get_purge_seq(St3)),
-    ?assertEqual([{<<"foo">>, [Rev]}], Engine:get_last_purged(St3)).
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(3, couch_db_engine:get_update_seq(Db3)),
+    ?assertEqual(1, couch_db_engine:get_purge_seq(Db3)),
+    ?assertEqual([{<<"foo">>, [Rev]}], couch_db_engine:get_last_purged(Db3)).
 
 
 cet_add_two_purge_one() ->
-    {ok, Engine, St1} = test_engine_util:init_engine(),
+    {ok, Db1} = test_engine_util:create_db(),
 
     Actions1 = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {create, {<<"bar">>, []}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {create, {<<"bar">>, {[]}}}
     ],
 
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions1),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions1),
 
-    ?assertEqual(2, Engine:get_doc_count(St2)),
-    ?assertEqual(0, Engine:get_del_doc_count(St2)),
-    ?assertEqual(2, Engine:get_update_seq(St2)),
-    ?assertEqual(0, Engine:get_purge_seq(St2)),
-    ?assertEqual([], Engine:get_last_purged(St2)),
+    ?assertEqual(2, couch_db_engine:get_doc_count(Db2)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db2)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db2)),
+    ?assertEqual(0, couch_db_engine:get_purge_seq(Db2)),
+    ?assertEqual([], couch_db_engine:get_last_purged(Db2)),
 
-    [FDI] = Engine:open_docs(St2, [<<"foo">>]),
+    [FDI] = couch_db_engine:open_docs(Db2, [<<"foo">>]),
     PrevRev = test_engine_util:prev_rev(FDI),
     Rev = PrevRev#rev_info.rev,
 
     Actions2 = [
         {purge, {<<"foo">>, Rev}}
     ],
-    {ok, St3} = test_engine_util:apply_actions(Engine, St2, Actions2),
+    {ok, Db3} = test_engine_util:apply_actions(Db2, Actions2),
 
-    ?assertEqual(1, Engine:get_doc_count(St3)),
-    ?assertEqual(0, Engine:get_del_doc_count(St3)),
-    ?assertEqual(3, Engine:get_update_seq(St3)),
-    ?assertEqual(1, Engine:get_purge_seq(St3)),
-    ?assertEqual([{<<"foo">>, [Rev]}], Engine:get_last_purged(St3)).
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(3, couch_db_engine:get_update_seq(Db3)),
+    ?assertEqual(1, couch_db_engine:get_purge_seq(Db3)),
+    ?assertEqual([{<<"foo">>, [Rev]}], couch_db_engine:get_last_purged(Db3)).
diff --git a/src/couch/src/test_engine_read_write_docs.erl b/src/couch/src/test_engine_read_write_docs.erl
index 4307702..2eeeab5 100644
--- a/src/couch/src/test_engine_read_write_docs.erl
+++ b/src/couch/src/test_engine_read_write_docs.erl
@@ -19,45 +19,49 @@
 
 
 cet_read_empty_docs() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
+    {ok, Db} = test_engine_util:create_db(),
 
-    ?assertEqual([not_found], Engine:open_docs(St, [<<"foo">>])),
+    ?assertEqual([not_found], couch_db_engine:open_docs(Db, [<<"foo">>])),
     ?assertEqual(
         [not_found, not_found],
-        Engine:open_docs(St, [<<"a">>, <<"b">>])
+        couch_db_engine:open_docs(Db, [<<"a">>, <<"b">>])
     ).
 
 
 cet_read_empty_local_docs() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
+    {ok, Db} = test_engine_util:create_db(),
 
-    ?assertEqual([not_found], Engine:open_local_docs(St, [<<"_local/foo">>])),
+    {LocalA, LocalB} = {<<"_local/a">>, <<"_local/b">>},
+    ?assertEqual([not_found], couch_db_engine:open_local_docs(Db, [LocalA])),
     ?assertEqual(
         [not_found, not_found],
-        Engine:open_local_docs(St, [<<"_local/a">>, <<"_local/b">>])
+        couch_db_engine:open_local_docs(Db, [LocalA, LocalB])
     ).
 
 
 cet_write_one_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db2)),
 
-    ?assertEqual(1, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(1, Engine:get_update_seq(St4)),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
 
-    [FDI] = Engine:open_docs(St4, [<<"foo">>]),
+    {ok, Db3} = couch_db:reopen(Db2),
+
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(1, couch_db_engine:get_update_seq(Db3)),
+
+    [FDI] = couch_db_engine:open_docs(Db3, [<<"foo">>]),
     #rev_info{
         rev = {RevPos, PrevRevId},
         deleted = Deleted,
@@ -71,85 +75,88 @@ cet_write_one_doc() ->
         body = DocPtr
     },
 
-    Doc1 = Engine:read_doc_body(St4, Doc0),
+    Doc1 = couch_db_engine:read_doc_body(Db3, Doc0),
     Body1 = if not is_binary(Doc1#doc.body) -> Doc1#doc.body; true ->
         couch_compress:decompress(Doc1#doc.body)
     end,
-    ?assertEqual([{<<"vsn">>, 1}], Body1).
+    ?assertEqual({[{<<"vsn">>, 1}]}, Body1).
 
 
 cet_write_two_docs() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {create, {<<"bar">>, [{<<"stuff">>, true}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {create, {<<"bar">>, {[{<<"stuff">>, true}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    ?assertEqual(2, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(2, Engine:get_update_seq(St4)),
+    ?assertEqual(2, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db3)),
 
-    Resps = Engine:open_docs(St4, [<<"foo">>, <<"bar">>]),
+    Resps = couch_db_engine:open_docs(Db3, [<<"foo">>, <<"bar">>]),
     ?assertEqual(false, lists:member(not_found, Resps)).
 
 
 cet_write_three_doc_batch() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
         {batch, [
-            {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-            {create, {<<"bar">>, [{<<"stuff">>, true}]}},
-            {create, {<<"baz">>, []}}
+            {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+            {create, {<<"bar">>, {[{<<"stuff">>, true}]}}},
+            {create, {<<"baz">>, {[]}}}
         ]}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
 
-    ?assertEqual(3, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(3, Engine:get_update_seq(St4)),
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    Resps = Engine:open_docs(St4, [<<"foo">>, <<"bar">>, <<"baz">>]),
+    ?assertEqual(3, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(3, couch_db_engine:get_update_seq(Db3)),
+
+    Resps = couch_db_engine:open_docs(Db3, [<<"foo">>, <<"bar">>, <<"baz">>]),
     ?assertEqual(false, lists:member(not_found, Resps)).
 
 
 cet_update_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {update, {<<"foo">>, [{<<"vsn">>, 2}]}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {update, {<<"foo">>, {[{<<"vsn">>, 2}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    ?assertEqual(1, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(2, Engine:get_update_seq(St4)),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db3)),
 
-    [FDI] = Engine:open_docs(St4, [<<"foo">>]),
+    [FDI] = couch_db_engine:open_docs(Db3, [<<"foo">>]),
 
     #rev_info{
         rev = {RevPos, PrevRevId},
@@ -164,35 +171,35 @@ cet_update_doc() ->
         body = DocPtr
     },
 
-    Doc1 = Engine:read_doc_body(St4, Doc0),
+    Doc1 = couch_db_engine:read_doc_body(Db3, Doc0),
     Body1 = if not is_binary(Doc1#doc.body) -> Doc1#doc.body; true ->
         couch_compress:decompress(Doc1#doc.body)
     end,
 
-    ?assertEqual([{<<"vsn">>, 2}], Body1).
+    ?assertEqual({[{<<"vsn">>, 2}]}, Body1).
 
 
 cet_delete_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"foo">>, [{<<"vsn">>, 1}]}},
-        {delete, {<<"foo">>, []}}
+        {create, {<<"foo">>, {[{<<"vsn">>, 1}]}}},
+        {delete, {<<"foo">>, {[]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
 
-    ?assertEqual(0, Engine:get_doc_count(St4)),
-    ?assertEqual(1, Engine:get_del_doc_count(St4)),
-    ?assertEqual(2, Engine:get_update_seq(St4)),
+    {ok, Db3} = couch_db:reopen(Db2),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(1, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(2, couch_db_engine:get_update_seq(Db3)),
 
-    [FDI] = Engine:open_docs(St4, [<<"foo">>]),
+    [FDI] = couch_db_engine:open_docs(Db3, [<<"foo">>]),
 
     #rev_info{
         rev = {RevPos, PrevRevId},
@@ -207,111 +214,118 @@ cet_delete_doc() ->
         body = DocPtr
     },
 
-    Doc1 = Engine:read_doc_body(St4, Doc0),
+    Doc1 = couch_db_engine:read_doc_body(Db3, Doc0),
     Body1 = if not is_binary(Doc1#doc.body) -> Doc1#doc.body; true ->
         couch_compress:decompress(Doc1#doc.body)
     end,
 
-    ?assertEqual([], Body1).
+    ?assertEqual({[]}, Body1).
 
 
 cet_write_local_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"_local/foo">>, [{<<"yay">>, false}]}}
+        {create, {<<"_local/foo">>, {[{<<"yay">>, false}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    ?assertEqual(0, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(0, Engine:get_update_seq(St4)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db3)),
 
-    [not_found] = Engine:open_docs(St4, [<<"_local/foo">>]),
-    [#doc{} = Doc] = Engine:open_local_docs(St4, [<<"_local/foo">>]),
-    ?assertEqual([{<<"yay">>, false}], Doc#doc.body).
+    [not_found] = couch_db_engine:open_docs(Db3, [<<"_local/foo">>]),
+    [#doc{} = Doc] = couch_db_engine:open_local_docs(Db3, [<<"_local/foo">>]),
+    ?assertEqual({[{<<"yay">>, false}]}, Doc#doc.body).
 
 
 cet_write_mixed_batch() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
         {batch, [
-            {create, {<<"bar">>, []}},
-            {create, {<<"_local/foo">>, [{<<"yay">>, false}]}}
+            {create, {<<"bar">>, {[]}}},
+            {create, {<<"_local/foo">>, {[{<<"yay">>, false}]}}}
         ]}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
 
-    ?assertEqual(1, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(1, Engine:get_update_seq(St4)),
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    [#full_doc_info{}] = Engine:open_docs(St4, [<<"bar">>]),
-    [not_found] = Engine:open_docs(St4, [<<"_local/foo">>]),
+    ?assertEqual(1, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(1, couch_db_engine:get_update_seq(Db3)),
 
-    [not_found] = Engine:open_local_docs(St4, [<<"bar">>]),
-    [#doc{}] = Engine:open_local_docs(St4, [<<"_local/foo">>]).
+    [#full_doc_info{}] = couch_db_engine:open_docs(Db3, [<<"bar">>]),
+    [not_found] = couch_db_engine:open_docs(Db3, [<<"_local/foo">>]),
+
+    [not_found] = couch_db_engine:open_local_docs(Db3, [<<"bar">>]),
+    [#doc{}] = couch_db_engine:open_local_docs(Db3, [<<"_local/foo">>]).
 
 
 cet_update_local_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
-        {create, {<<"_local/foo">>, []}},
-        {update, {<<"_local/foo">>, [{<<"stuff">>, null}]}}
+        {create, {<<"_local/foo">>, {[]}}},
+        {update, {<<"_local/foo">>, {[{<<"stuff">>, null}]}}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db1),
+    test_engine_util:shutdown_db(Db2),
+
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    ?assertEqual(0, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(0, Engine:get_update_seq(St4)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db3)),
 
-    [not_found] = Engine:open_docs(St4, [<<"_local/foo">>]),
-    [#doc{} = Doc] = Engine:open_local_docs(St4, [<<"_local/foo">>]),
-    ?assertEqual([{<<"stuff">>, null}], Doc#doc.body).
+    [not_found] = couch_db_engine:open_docs(Db3, [<<"_local/foo">>]),
+    [#doc{} = Doc] = couch_db_engine:open_local_docs(Db3, [<<"_local/foo">>]),
+    ?assertEqual({[{<<"stuff">>, null}]}, Doc#doc.body).
 
 
 cet_delete_local_doc() ->
-    {ok, Engine, DbPath, St1} = test_engine_util:init_engine(dbpath),
+    {ok, Db1} = test_engine_util:create_db(),
 
-    ?assertEqual(0, Engine:get_doc_count(St1)),
-    ?assertEqual(0, Engine:get_del_doc_count(St1)),
-    ?assertEqual(0, Engine:get_update_seq(St1)),
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db1)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db1)),
 
     Actions = [
         {create, {<<"_local/foo">>, []}},
         {delete, {<<"_local/foo">>, []}}
     ],
-    {ok, St2} = test_engine_util:apply_actions(Engine, St1, Actions),
-    {ok, St3} = Engine:commit_data(St2),
-    Engine:terminate(normal, St3),
-    {ok, St4} = Engine:init(DbPath, []),
+    {ok, Db2} = test_engine_util:apply_actions(Db1, Actions),
+    {ok, _} = couch_db:ensure_full_commit(Db2),
+    test_engine_util:shutdown_db(Db2),
 
-    ?assertEqual(0, Engine:get_doc_count(St4)),
-    ?assertEqual(0, Engine:get_del_doc_count(St4)),
-    ?assertEqual(0, Engine:get_update_seq(St4)),
+    {ok, Db3} = couch_db:reopen(Db2),
 
-    [not_found] = Engine:open_docs(St4, [<<"_local/foo">>]),
-    ?assertEqual([not_found], Engine:open_local_docs(St4, [<<"_local/foo">>])).
+    ?assertEqual(0, couch_db_engine:get_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_del_doc_count(Db3)),
+    ?assertEqual(0, couch_db_engine:get_update_seq(Db3)),
+
+    [not_found] = couch_db_engine:open_docs(Db3, [<<"_local/foo">>]),
+    ?assertEqual(
+            [not_found],
+            couch_db_engine:open_local_docs(Db3, [<<"_local/foo">>])
+        ).
diff --git a/src/couch/src/test_engine_ref_counting.erl b/src/couch/src/test_engine_ref_counting.erl
index 18e75fb..f0a2489 100644
--- a/src/couch/src/test_engine_ref_counting.erl
+++ b/src/couch/src/test_engine_ref_counting.erl
@@ -22,48 +22,53 @@
 
 
 cet_empty_monitors() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
-    Pids = Engine:monitored_by(St),
+    {ok, Db} = test_engine_util:create_db(),
+    Pids = couch_db_engine:monitored_by(Db),
     ?assert(is_list(Pids)),
-    ?assertEqual([], Pids -- [self(), whereis(couch_stats_process_tracker)]).
+    Expected = [
+        self(),
+        couch_db:get_pid(Db),
+        whereis(couch_stats_process_tracker)
+    ],
+    ?assertEqual([], Pids -- Expected).
 
 
 cet_incref_decref() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
+    {ok, Db} = test_engine_util:create_db(),
 
-    {Pid, _} = Client = start_client(Engine, St),
+    {Pid, _} = Client = start_client(Db),
     wait_client(Client),
 
-    Pids1 = Engine:monitored_by(St),
+    Pids1 = couch_db_engine:monitored_by(Db),
     ?assert(lists:member(Pid, Pids1)),
 
     close_client(Client),
 
-    Pids2 = Engine:monitored_by(St),
+    Pids2 = couch_db_engine:monitored_by(Db),
     ?assert(not lists:member(Pid, Pids2)).
 
 
 cet_incref_decref_many() ->
-    {ok, Engine, St} = test_engine_util:init_engine(),
+    {ok, Db} = test_engine_util:create_db(),
     Clients = lists:map(fun(_) ->
-        start_client(Engine, St)
+        start_client(Db)
     end, lists:seq(1, ?NUM_CLIENTS)),
 
     lists:foreach(fun(C) -> wait_client(C) end, Clients),
 
-    Pids1 = Engine:monitored_by(St),
-    % +2 for db pid and process tracker
-    ?assertEqual(?NUM_CLIENTS + 2, length(Pids1)),
+    Pids1 = couch_db_engine:monitored_by(Db),
+    % +3 for self, db pid, and process tracker
+    ?assertEqual(?NUM_CLIENTS + 3, length(Pids1)),
 
     lists:foreach(fun(C) -> close_client(C) end, Clients),
 
-    Pids2 = Engine:monitored_by(St),
-    ?assertEqual(2, length(Pids2)).
+    Pids2 = couch_db_engine:monitored_by(Db),
+    ?assertEqual(3, length(Pids2)).
 
 
-start_client(Engine, St1) ->
+start_client(Db0) ->
     spawn_monitor(fun() ->
-        {ok, St2} = Engine:incref(St1),
+        {ok, Db1} = couch_db:open_int(couch_db:name(Db0), []),
 
         receive
             {waiting, Pid} ->
@@ -74,12 +79,11 @@ start_client(Engine, St1) ->
 
         receive
             close ->
+                couch_db:close(Db1),
                 ok
         after 1000 ->
             erlang:error(timeout)
-        end,
-
-        Engine:decref(St2)
+        end
     end).
 
 
diff --git a/src/couch/src/test_engine_util.erl b/src/couch/src/test_engine_util.erl
index 6cc6bcc..5235809 100644
--- a/src/couch/src/test_engine_util.erl
+++ b/src/couch/src/test_engine_util.erl
@@ -29,21 +29,27 @@
     test_engine_ref_counting
 ]).
 
+
+-define(SHUTDOWN_TIMEOUT, 5000).
 -define(COMPACTOR_TIMEOUT, 50000).
 -define(ATTACHMENT_WRITE_TIMEOUT, 10000).
 -define(MAKE_DOC_SUMMARY_TIMEOUT, 5000).
 
-create_tests(EngineApp) ->
-    create_tests(EngineApp, EngineApp).
+
+create_tests(EngineApp, Extension) ->
+    create_tests(EngineApp, EngineApp, Extension).
 
 
-create_tests(EngineApp, EngineModule) ->
-    application:set_env(couch, test_engine, {EngineApp, EngineModule}),
+create_tests(EngineApp, EngineModule, Extension) ->
+    TestEngine = {EngineApp, EngineModule, Extension},
+    application:set_env(couch, test_engine, TestEngine),
     Tests = lists:map(fun(TestMod) ->
         {atom_to_list(TestMod), gather(TestMod)}
     end, ?TEST_MODULES),
     Setup = fun() ->
         Ctx = test_util:start_couch(),
+        EngineModStr = atom_to_list(EngineModule),
+        config:set("couchdb_engines", Extension, EngineModStr, false),
         config:set("log", "include_sasl", "false", false),
         Ctx
     end,
@@ -77,93 +83,114 @@ make_test_fun(Module, Fun) ->
     end,
     {Name, Wrapper}.
 
+
 rootdir() ->
     config:get("couchdb", "database_dir", ".").
 
 
-dbpath() ->
-    binary_to_list(filename:join(rootdir(), couch_uuids:random())).
+dbname() ->
+    UUID = couch_uuids:random(),
+    <<"db-", UUID/binary>>.
 
 
 get_engine() ->
     case application:get_env(couch, test_engine) of
-        {ok, {_, Engine}} ->
-            Engine;
+        {ok, {_App, _Mod, Extension}} ->
+            list_to_binary(Extension);
         _ ->
-            couch_bt_engine
+            <<"couch">>
     end.
 
 
-init_engine() ->
-    init_engine(default).
+create_db() ->
+    create_db(dbname()).
 
 
-init_engine(default) ->
+create_db(DbName) ->
     Engine = get_engine(),
-    DbPath = dbpath(),
-    {ok, St} = Engine:init(DbPath, [
-            create,
-            {default_security_object, []}
-        ]),
-    {ok, Engine, St};
-
-init_engine(dbpath) ->
+    couch_db:create(DbName, [{engine, Engine}, ?ADMIN_CTX]).
+
+
+open_db(DbName) ->
     Engine = get_engine(),
-    DbPath = dbpath(),
-    {ok, St} = Engine:init(DbPath, [
-            create,
-            {default_security_object, []}
-        ]),
-    {ok, Engine, DbPath, St}.
+    couch_db:open_int(DbName, [{engine, Engine}, ?ADMIN_CTX]).
+
+
+shutdown_db(Db) ->
+    Pid = couch_db:get_pid(Db),
+    Ref = erlang:monitor(process, Pid),
+    exit(Pid, kill),
+    receive
+        {'DOWN', Ref, _, _, _} ->
+            ok
+    after ?SHUTDOWN_TIMEOUT ->
+        erlang:error(database_shutdown_timeout)
+    end,
+    test_util:wait(fun() ->
+        case ets:member(couch_dbs, couch_db:name(Db)) of
+            true -> wait;
+            false -> ok
+        end
+    end).
 
 
-apply_actions(_Engine, St, []) ->
-    {ok, St};
+apply_actions(Db, []) ->
+    {ok, Db};
 
-apply_actions(Engine, St, [Action | Rest]) ->
-    NewSt = apply_action(Engine, St, Action),
-    apply_actions(Engine, NewSt, Rest).
+apply_actions(Db, [Action | Rest]) ->
+    {ok, NewDb} = apply_action(Db, Action),
+    apply_actions(NewDb, Rest).
 
 
-apply_action(Engine, St, {batch, BatchActions}) ->
-    apply_batch(Engine, St, BatchActions);
+apply_action(Db, {batch, BatchActions}) ->
+    apply_batch(Db, BatchActions);
 
-apply_action(Engine, St, Action) ->
-    apply_batch(Engine, St, [Action]).
+apply_action(Db, Action) ->
+    apply_batch(Db, [Action]).
 
 
-apply_batch(Engine, St, Actions) ->
-    UpdateSeq = Engine:get_update_seq(St) + 1,
-    AccIn = {UpdateSeq, [], [], []},
+apply_batch(Db, Actions) ->
+    AccIn = {[], [], [], []},
     AccOut = lists:foldl(fun(Action, Acc) ->
-        {SeqAcc, DocAcc, LDocAcc, PurgeAcc} = Acc,
-        case Action of
-            {_, {<<"_local/", _/binary>>, _}} ->
-                LDoc = gen_local_write(Engine, St, Action),
-                {SeqAcc, DocAcc, [LDoc | LDocAcc], PurgeAcc};
-            _ ->
-                case gen_write(Engine, St, Action, SeqAcc) of
-                    {_OldFDI, _NewFDI} = Pair ->
-                        {SeqAcc + 1, [Pair | DocAcc], LDocAcc, PurgeAcc};
-                    {Pair, NewSeqAcc, NewPurgeInfo} ->
-                        NewPurgeAcc = [NewPurgeInfo | PurgeAcc],
-                        {NewSeqAcc, [Pair | DocAcc], LDocAcc, NewPurgeAcc}
-                end
+        {DocAcc, ConfAcc, LDocAcc, PurgeAcc} = Acc,
+        case gen_write(Db, Action) of
+            {update, Doc} ->
+                {[Doc | DocAcc], ConfAcc, LDocAcc, PurgeAcc};
+            {conflict, Doc} ->
+                {DocAcc, [Doc | ConfAcc], LDocAcc, PurgeAcc};
+            {local, Doc} ->
+                {DocAcc, ConfAcc, [Doc | LDocAcc], PurgeAcc};
+            {purge, PurgeInfo} ->
+                {DocAcc, ConfAcc, LDocAcc, [PurgeInfo | PurgeAcc]}
         end
     end, AccIn, Actions),
-    {_, Docs0, LDocs, PurgeIdRevs} = AccOut,
+
+    {Docs0, Conflicts0, LDocs0, PurgeInfos0} = AccOut,
     Docs = lists:reverse(Docs0),
-    {ok, NewSt} = Engine:write_doc_infos(St, Docs, LDocs, PurgeIdRevs),
-    NewSt.
+    Conflicts = lists:reverse(Conflicts0),
+    LDocs = lists:reverse(LDocs0),
+    PurgeInfos = lists:reverse(PurgeInfos0),
+
+    {ok, Resp} = couch_db:update_docs(Db, Docs ++ LDocs),
+    false = lists:member(conflict, Resp),
+    {ok, Db1} = couch_db:reopen(Db),
+
+    {ok, []} = couch_db:update_docs(Db, Conflicts, [], replicated_changes),
+    {ok, Db2} = couch_db:reopen(Db1),
+
+    if PurgeInfos == [] -> ok; true ->
+        {ok, _, _} = couch_db:purge_docs(Db2, PurgeInfos)
+    end,
+    couch_db:reopen(Db2).
 
 
-gen_local_write(Engine, St, {Action, {DocId, Body}}) ->
-    PrevRev = case Engine:open_local_docs(St, [DocId]) of
-        [not_found] ->
+gen_write(Db, {Action, {<<"_local/", _/binary>> = DocId, Body}}) ->
+    PrevRev = case couch_db:open_doc(Db, DocId) of
+        {not_found, _} ->
             0;
-        [#doc{revs = {0, []}}] ->
+        {ok, #doc{revs = {0, []}}} ->
             0;
-        [#doc{revs = {0, [RevStr | _]}}] ->
+        {ok, #doc{revs = {0, [RevStr | _]}}} ->
             binary_to_integer(RevStr)
     end,
     {RevId, Deleted} = case Action of
@@ -172,117 +199,41 @@ gen_local_write(Engine, St, {Action, {DocId, Body}}) ->
         delete ->
             {0, true}
     end,
-    #doc{
+    {local, #doc{
         id = DocId,
-        revs = {0, [RevId]},
+        revs = {0, [list_to_binary(integer_to_list(RevId))]},
         body = Body,
         deleted = Deleted
-    }.
-
-gen_write(Engine, St, {Action, {DocId, Body}}, UpdateSeq) ->
-    gen_write(Engine, St, {Action, {DocId, Body, []}}, UpdateSeq);
-
-gen_write(Engine, St, {create, {DocId, Body, Atts0}}, UpdateSeq) ->
-    [not_found] = Engine:open_docs(St, [DocId]),
-    Atts = [couch_att:to_disk_term(Att) || Att <- Atts0],
+    }};
 
     Rev = couch_hash:md5_hash(term_to_binary({DocId, Body, Atts})),
 
-    Doc0 = #doc{
+gen_write(Db, {create, {DocId, Body, Atts}}) ->
+    {not_found, _} = couch_db:open_doc(Db, DocId),
+    {update, #doc{
         id = DocId,
-        revs = {0, [Rev]},
+        revs = {0, []},
         deleted = false,
         body = Body,
         atts = Atts
-    },
-
-    Doc1 = make_doc_summary(Engine, St, Doc0),
-    {ok, Doc2, Len} = Engine:write_doc_body(St, Doc1),
-
-    Sizes = #size_info{
-        active = Len,
-        external = erlang:external_size(Doc1#doc.body)
-    },
-
-    Leaf = #leaf{
-        deleted = false,
-        ptr = Doc2#doc.body,
-        seq = UpdateSeq,
-        sizes = Sizes,
-        atts = Atts
-    },
-
-    {not_found, #full_doc_info{
-        id = DocId,
-        deleted = false,
-        update_seq = UpdateSeq,
-        rev_tree = [{0, {Rev, Leaf, []}}],
-        sizes = Sizes
     }};
 
-gen_write(Engine, St, {purge, {DocId, PrevRevs0, _}}, UpdateSeq) ->
-    [#full_doc_info{} = PrevFDI] = Engine:open_docs(St, [DocId]),
+gen_write(_Db, {purge, {DocId, PrevRevs0, _}}) ->
     PrevRevs = if is_list(PrevRevs0) -> PrevRevs0; true -> [PrevRevs0] end,
+    {purge, {DocId, PrevRevs}};
 
-    #full_doc_info{
-        rev_tree = PrevTree
-    } = PrevFDI,
-
-    {NewTree, RemRevs} = couch_key_tree:remove_leafs(PrevTree, PrevRevs),
-    RemovedAll = lists:sort(RemRevs) == lists:sort(PrevRevs),
-    if RemovedAll -> ok; true ->
-        % If we didn't purge all the requested revisions
-        % then its a bug in the test.
-        erlang:error({invalid_purge_test_revs, PrevRevs})
-    end,
-
-    case NewTree of
-        [] ->
-            % We've completely purged the document
-            {{PrevFDI, not_found}, UpdateSeq, {DocId, RemRevs}};
-        _ ->
-            % We have to relabel the update_seq of all
-            % leaves. See couch_db_updater for details.
-            {NewNewTree, NewUpdateSeq} = couch_key_tree:mapfold(fun
-                (_RevId, Leaf, leaf, InnerSeqAcc) ->
-                    {Leaf#leaf{seq = InnerSeqAcc}, InnerSeqAcc + 1};
-                (_RevId, Value, _Type, InnerSeqAcc) ->
-                    {Value, InnerSeqAcc}
-            end, UpdateSeq, NewTree),
-            NewFDI = PrevFDI#full_doc_info{
-                update_seq = NewUpdateSeq - 1,
-                rev_tree = NewNewTree
-            },
-            {{PrevFDI, NewFDI}, NewUpdateSeq, {DocId, RemRevs}}
-    end;
-
-gen_write(Engine, St, {Action, {DocId, Body, Atts0}}, UpdateSeq) ->
-    [#full_doc_info{} = PrevFDI] = Engine:open_docs(St, [DocId]),
-    Atts = [couch_att:to_disk_term(Att) || Att <- Atts0],
+gen_write(Db, {Action, {DocId, Body, Atts}}) ->
+    #full_doc_info{} = PrevFDI = couch_db:get_full_doc_info(Db, DocId),
 
     #full_doc_info{
-        id = DocId,
-        rev_tree = PrevRevTree
+        id = DocId
     } = PrevFDI,
 
     #rev_info{
         rev = PrevRev
     } = prev_rev(PrevFDI),
 
-    {RevPos, PrevRevId} = PrevRev,
-
-    Rev = gen_revision(Action, DocId, PrevRev, Body, Atts),
-
-    Doc0 = #doc{
-        id = DocId,
-        revs = {RevPos + 1, [Rev, PrevRevId]},
-        deleted = false,
-        body = Body,
-        atts = Atts
-    },
-
-    Doc1 = make_doc_summary(Engine, St, Doc0),
-    {ok, Doc2, Len} = Engine:write_doc_body(St, Doc1),
+    NewRev = gen_rev(Action, DocId, PrevRev, Body, Atts),
 
     Deleted = case Action of
         update -> false;
@@ -290,16 +241,16 @@ gen_write(Engine, St, {Action, {DocId, Body, Atts0}}, UpdateSeq) ->
         delete -> true
     end,
 
-    Sizes = #size_info{
-        active = Len,
-        external = erlang:external_size(Doc1#doc.body)
-    },
+    Type = case Action of
+        conflict -> conflict;
+        _ -> update
+    end,
 
-    Leaf = #leaf{
+    {Type, #doc{
+        id = DocId,
+        revs = NewRev,
         deleted = Deleted,
-        ptr = Doc2#doc.body,
-        seq = UpdateSeq,
-        sizes = Sizes,
+        body = Body,
         atts = Atts
     },
 
@@ -330,34 +281,21 @@ gen_revision(update, DocId, PrevRev, Body, Atts) ->
     couch_hash:md5_hash(term_to_binary({DocId, PrevRev, Body, Atts})).
 
 
-gen_path(conflict, _RevPos, _PrevRevId, Rev, Leaf) ->
-    {0, {Rev, Leaf, []}};
-gen_path(delete, RevPos, PrevRevId, Rev, Leaf) ->
-    gen_path(update, RevPos, PrevRevId, Rev, Leaf);
-gen_path(update, RevPos, PrevRevId, Rev, Leaf) ->
-    {RevPos, {PrevRevId, ?REV_MISSING, [{Rev, Leaf, []}]}}.
+gen_rev(A, DocId, {Pos, Rev}, Body, Atts) when A == update; A == delete ->
+    NewRev = crypto:hash(md5, term_to_binary({DocId, Rev, Body, Atts})),
+    {Pos + 1, [NewRev, Rev]};
+gen_rev(conflict, DocId, _, Body, Atts) ->
+    UUID = couch_uuids:random(),
+    NewRev = crypto:hash(md5, term_to_binary({DocId, UUID, Body, Atts})),
+    {1, [NewRev]}.
 
 
-make_doc_summary(Engine, St, DocData) ->
-    {_, Ref} = spawn_monitor(fun() ->
-        exit({result, Engine:serialize_doc(St, DocData)})
-    end),
-    receive
-        {'DOWN', Ref, _, _, {result, Summary}} ->
-            Summary;
-        {'DOWN', Ref, _, _, Error} ->
-            erlang:error({make_doc_summary_error, Error})
-    after ?MAKE_DOC_SUMMARY_TIMEOUT ->
-        erlang:error(make_doc_summary_timeout)
-    end.
-
-
-prep_atts(_Engine, _St, []) ->
+prep_atts(_Db, []) ->
     [];
 
-prep_atts(Engine, St, [{FileName, Data} | Rest]) ->
+prep_atts(Db, [{FileName, Data} | Rest]) ->
     {_, Ref} = spawn_monitor(fun() ->
-        {ok, Stream} = Engine:open_write_stream(St, []),
+        {ok, Stream} = couch_db:open_write_stream(Db, []),
         exit(write_att(Stream, FileName, Data, Data))
     end),
     Att = receive
@@ -368,7 +306,7 @@ prep_atts(Engine, St, [{FileName, Data} | Rest]) ->
         after ?ATTACHMENT_WRITE_TIMEOUT ->
             erlang:error(attachment_write_timeout)
     end,
-    [Att | prep_atts(Engine, St, Rest)].
+    [Att | prep_atts(Db, Rest)].
 
 
 write_att(Stream, FileName, OrigData, <<>>) ->
@@ -404,16 +342,16 @@ prev_rev(#full_doc_info{} = FDI) ->
     PrevRev.
 
 
-db_as_term(Engine, St) ->
+db_as_term(Db) ->
     [
-        {props, db_props_as_term(Engine, St)},
-        {docs, db_docs_as_term(Engine, St)},
-        {local_docs, db_local_docs_as_term(Engine, St)},
-        {changes, db_changes_as_term(Engine, St)}
+        {props, db_props_as_term(Db)},
+        {docs, db_docs_as_term(Db)},
+        {local_docs, db_local_docs_as_term(Db)},
+        {changes, db_changes_as_term(Db)}
     ].
 
 
-db_props_as_term(Engine, St) ->
+db_props_as_term(Db) ->
     Props = [
         get_doc_count,
         get_del_doc_count,
@@ -427,40 +365,40 @@ db_props_as_term(Engine, St) ->
         get_epochs
     ],
     lists:map(fun(Fun) ->
-        {Fun, Engine:Fun(St)}
+        {Fun, couch_db_engine:Fun(Db)}
     end, Props).
 
 
-db_docs_as_term(Engine, St) ->
+db_docs_as_term(Db) ->
     FoldFun = fun(FDI, Acc) -> {ok, [FDI | Acc]} end,
-    {ok, FDIs} = Engine:fold_docs(St, FoldFun, [], []),
+    {ok, FDIs} = couch_db:fold_docs(Db, FoldFun, [], []),
     lists:reverse(lists:map(fun(FDI) ->
-        fdi_to_term(Engine, St, FDI)
+        fdi_to_term(Db, FDI)
     end, FDIs)).
 
 
-db_local_docs_as_term(Engine, St) ->
+db_local_docs_as_term(Db) ->
     FoldFun = fun(Doc, Acc) -> {ok, [Doc | Acc]} end,
-    {ok, LDocs} = Engine:fold_local_docs(St, FoldFun, [], []),
+    {ok, LDocs} = couch_db:fold_local_docs(Db, FoldFun, [], []),
     lists:reverse(LDocs).
 
 
-db_changes_as_term(Engine, St) ->
+db_changes_as_term(Db) ->
     FoldFun = fun(FDI, Acc) -> {ok, [FDI | Acc]} end,
-    {ok, Changes} = Engine:fold_changes(St, 0, FoldFun, [], []),
+    {ok, Changes} = couch_db:fold_changes(Db, 0, FoldFun, [], []),
     lists:reverse(lists:map(fun(FDI) ->
-        fdi_to_term(Engine, St, FDI)
+        fdi_to_term(Db, FDI)
     end, Changes)).
 
 
-fdi_to_term(Engine, St, FDI) ->
+fdi_to_term(Db, FDI) ->
     #full_doc_info{
         id = DocId,
         rev_tree = OldTree
     } = FDI,
     {NewRevTree, _} = couch_key_tree:mapfold(fun(Rev, Node, Type, Acc) ->
         tree_to_term(Rev, Node, Type, Acc, DocId)
-    end, {Engine, St}, OldTree),
+    end, Db, OldTree),
     FDI#full_doc_info{
         rev_tree = NewRevTree,
         % Blank out sizes because we allow storage
@@ -476,7 +414,7 @@ fdi_to_term(Engine, St, FDI) ->
 tree_to_term(_Rev, _Leaf, branch, Acc, _DocId) ->
     {?REV_MISSING, Acc};
 
-tree_to_term({Pos, RevId}, #leaf{} = Leaf, leaf, {Engine, St}, DocId) ->
+tree_to_term({Pos, RevId}, #leaf{} = Leaf, leaf, Db, DocId) ->
     #leaf{
         deleted = Deleted,
         ptr = Ptr
@@ -489,7 +427,7 @@ tree_to_term({Pos, RevId}, #leaf{} = Leaf, leaf, {Engine, St}, DocId) ->
         body = Ptr
     },
 
-    Doc1 = Engine:read_doc_body(St, Doc0),
+    Doc1 = couch_db_engine:read_doc_body(Db, Doc0),
 
     Body = if not is_binary(Doc1#doc.body) -> Doc1#doc.body; true ->
         couch_compress:decompress(Doc1#doc.body)
@@ -499,7 +437,7 @@ tree_to_term({Pos, RevId}, #leaf{} = Leaf, leaf, {Engine, St}, DocId) ->
         couch_compress:decompress(Doc1#doc.atts)
     end,
 
-    StreamSrc = fun(Sp) -> Engine:open_read_stream(St, Sp) end,
+    StreamSrc = fun(Sp) -> couch_db:open_read_stream(Db, Sp) end,
     Atts2 = [couch_att:from_disk_term(StreamSrc, Att) || Att <- Atts1],
     Atts = [att_to_term(Att) || Att <- Atts2],
 
@@ -508,7 +446,7 @@ tree_to_term({Pos, RevId}, #leaf{} = Leaf, leaf, {Engine, St}, DocId) ->
         sizes = #size_info{active = -1, external = -1},
         atts = Atts
     },
-    {NewLeaf, {Engine, St}}.
+    {NewLeaf, Db}.
 
 
 att_to_term(Att) ->
@@ -565,9 +503,8 @@ list_diff([T1 | R1], [T2 | R2]) ->
     end.
 
 
-compact(Engine, St1, DbPath) ->
-    DbName = filename:basename(DbPath),
-    {ok, St2, Pid} = Engine:start_compaction(St1, DbName, [], self()),
+compact(Db) ->
+    {ok, Pid} = couch_db:start_compact(Db),
     Ref = erlang:monitor(process, Pid),
 
     % Ideally I'd assert that Pid is linked to us
@@ -575,16 +512,29 @@ compact(Engine, St1, DbPath) ->
     % that it could have finished compacting by
     % the time we check... Quite the quandry.
 
-    Term = receive
-        {'$gen_cast', {compact_done, Engine, Term0}} ->
-            Term0;
+    receive
+        {'DOWN', Ref, _, _, normal} ->
+            ok;
+        {'DOWN', Ref, _, _, noproc} ->
+            ok;
         {'DOWN', Ref, _, _, Reason} ->
             erlang:error({compactor_died, Reason})
         after ?COMPACTOR_TIMEOUT ->
             erlang:error(compactor_timed_out)
     end,
 
-    {ok, St2, DbName, Pid, Term}.
+    test_util:wait(fun() ->
+        {ok, Db2} = couch_db:open_int(couch_db:name(Db), []),
+        try
+            CPid = couch_db:get_compactor_pid(Db2),
+            case is_pid(CPid) of
+                true -> wait;
+                false -> ok
+            end
+        after
+            couch_db:close(Db2)
+        end
+    end).
 
 
 with_config(Config, Fun) ->
@@ -602,7 +552,7 @@ apply_config([]) ->
 apply_config([{Section, Key, Value} | Rest]) ->
     Orig = config:get(Section, Key),
     case Value of
-        undefined -> config:delete(Section, Key);
-        _ -> config:set(Section, Key, Value)
+        undefined -> config:delete(Section, Key, false);
+        _ -> config:set(Section, Key, Value, false)
     end,
     [{Section, Key, Orig} | apply_config(Rest)].
diff --git a/src/couch/test/couch_bt_engine_tests.erl b/src/couch/test/couch_bt_engine_tests.erl
index df200df..c4055d0 100644
--- a/src/couch/test/couch_bt_engine_tests.erl
+++ b/src/couch/test/couch_bt_engine_tests.erl
@@ -17,4 +17,4 @@
 
 
 couch_bt_engine_test_()->
-    test_engine_util:create_tests(couch, couch_bt_engine).
+    test_engine_util:create_tests(couch, couch_bt_engine, "couch").