Extend `enable_database_recovery` behaviour to views directories

If config option `enable_database_recovery` set to true then during database
deletion all its ddoc's directories that hold view files will be renamed
in the same fashion as database file, i.e. with added timestamp and
suffix "deleted"
diff --git a/src/couch_file.erl b/src/couch_file.erl
index d2c28d4..8aa4a50 100644
--- a/src/couch_file.erl
+++ b/src/couch_file.erl
@@ -264,6 +264,18 @@
     filename:rootname(Original) ++ Suffix.
 
 nuke_dir(RootDelDir, Dir) ->
+    EnableRecovery = config:get_boolean("couchdb",
+        "enable_database_recovery", false),
+    case EnableRecovery of
+        true ->
+            rename_file(Dir);
+        false ->
+            delete_dir(RootDelDir, Dir)
+    end.
+
+delete_dir(RootDelDir, Dir) ->
+    DeleteAfterRename = config:get_boolean("couchdb",
+        "delete_after_rename", true),
     FoldFun = fun(File) ->
         Path = Dir ++ "/" ++ File,
         case filelib:is_dir(Path) of
@@ -271,7 +283,7 @@
                 ok = nuke_dir(RootDelDir, Path),
                 file:del_dir(Path);
             false ->
-                delete(RootDelDir, Path, false)
+                delete_file(RootDelDir, Path, false, DeleteAfterRename)
         end
     end,
     case file:list_dir(Dir) of
diff --git a/test/couch_file_tests.erl b/test/couch_file_tests.erl
index 8edbaac..62f5844 100644
--- a/test/couch_file_tests.erl
+++ b/test/couch_file_tests.erl
@@ -346,3 +346,95 @@
         ?_assertNot(FileExistsAfter),
         ?_assertEqual(ExpectRenamedCount, length(RenamedFiles))
     ].
+
+
+nuke_dir_test_() ->
+    {
+        "Nuke directory tests",
+        {
+            foreach,
+            fun() ->
+                meck:new(config, [passthrough]),
+                File0 = ?tempfile() ++ ".couch",
+                RootDir = filename:dirname(File0),
+                BaseName = filename:basename(File0),
+                Seed = crypto:rand_uniform(1000000000, 9999999999),
+                DDocDir = io_lib:format("db.~b_design", [Seed]),
+                ViewDir = filename:join([RootDir, DDocDir]),
+                file:make_dir(ViewDir),
+                File = filename:join([ViewDir, BaseName]),
+                file:rename(File0, File),
+                ok = couch_file:init_delete_dir(RootDir),
+                ok = file:write_file(File, <<>>),
+                {RootDir, ViewDir}
+            end,
+            fun({RootDir, ViewDir}) ->
+                meck:unload(config),
+                remove_dir(ViewDir),
+                Ext = filename:extension(ViewDir),
+                case filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext) of
+                    [DelDir] -> remove_dir(DelDir);
+                    _ -> ok
+                end
+            end,
+            [
+                fun(Cfg) ->
+                    {"enable_database_recovery = false",
+                    make_rename_dir_test_case(Cfg, false)}
+                end,
+                fun(Cfg) ->
+                    {"enable_database_recovery = true",
+                    make_rename_dir_test_case(Cfg, true)}
+                end,
+                fun(Cfg) ->
+                    {"delete_after_rename = true",
+                    make_delete_dir_test_case(Cfg, true)}
+                end,
+                fun(Cfg) ->
+                    {"delete_after_rename = false",
+                    make_delete_dir_test_case(Cfg, false)}
+                end
+            ]
+        }
+    }.
+
+
+make_rename_dir_test_case({RootDir, ViewDir}, EnableRecovery) ->
+    meck:expect(config, get_boolean, fun
+        ("couchdb", "enable_database_recovery", _) -> EnableRecovery;
+        ("couchdb", "delete_after_rename", _) -> true
+    end),
+    DirExistsBefore = filelib:is_dir(ViewDir),
+    couch_file:nuke_dir(RootDir, ViewDir),
+    DirExistsAfter = filelib:is_dir(ViewDir),
+    Ext = filename:extension(ViewDir),
+    RenamedDirs = filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext),
+    ExpectRenamedCount = if EnableRecovery -> 1; true -> 0 end,
+    [
+        ?_assert(DirExistsBefore),
+        ?_assertNot(DirExistsAfter),
+        ?_assertEqual(ExpectRenamedCount, length(RenamedDirs))
+    ].
+
+make_delete_dir_test_case({RootDir, ViewDir}, DeleteAfterRename) ->
+    meck:expect(config, get_boolean, fun
+        ("couchdb", "enable_database_recovery", _) -> false;
+        ("couchdb", "delete_after_rename", _) -> DeleteAfterRename
+    end),
+    DirExistsBefore = filelib:is_dir(ViewDir),
+    couch_file:nuke_dir(RootDir, ViewDir),
+    DirExistsAfter = filelib:is_dir(ViewDir),
+    Ext = filename:extension(ViewDir),
+    RenamedDirs = filelib:wildcard(RootDir ++ "/*.deleted" ++ Ext),
+    RenamedFiles = filelib:wildcard(RootDir ++ "/.delete/*"),
+    ExpectRenamedCount = if DeleteAfterRename -> 0; true -> 1 end,
+    [
+        ?_assert(DirExistsBefore),
+        ?_assertNot(DirExistsAfter),
+        ?_assertEqual(0, length(RenamedDirs)),
+        ?_assertEqual(ExpectRenamedCount, length(RenamedFiles))
+    ].
+
+remove_dir(Dir) ->
+    [file:delete(File) || File <- filelib:wildcard(filename:join([Dir, "*"]))],
+    file:del_dir(Dir).