let basic_test (module Test_db : TEST_DATABASE) uri_string () =   let open Test_db in   let open Trakeva.Action in   let local_assert name c =     Test.check (name :: test_name :: uri_string :: []) c in   DB.load uri_string   >>= fun db ->   let test_get ?(handle=db) ?collection k f =     DB.get handle ?collection ~key:k     >>= fun opt ->     local_assert (sprintf "get %s/%s" (Option.value collection ~default:"") k)       (f opt);     return () in   let is_none = ((=) Nonein   test_get "k" is_none >>= fun () ->   test_get ~collection:"c" "k" is_none >>= fun () ->   DB.get_all db ~collection:"c"   >>= fun list ->   local_assert "all c" (list = []);   let test_actions res actions =     let action = seq actions in     DB.act db ~action     >>= function     | r when r = res -> return ()     | `Done ->       ksprintf Test.fail "Action %s should be Not_done" (to_string action);       return ()     | `Not_done ->       ksprintf Test.fail "Action %s should be Done" (to_string action);       return ()   in   test_actions `Done [set ~key:"k" "v0"] >>= fun () ->   test_get  "k" ((=) (Some "v0")) >>= fun () ->   test_actions `Done [set ~key:"k" "v"] >>= fun () ->   test_get  "k" ((=) (Some "v")) >>= fun () ->   test_actions `Done [     contains ~key:"k" "v";     unset "k";     set ~key:"k1" ~collection:"c" "V";   ] >>= fun () ->   test_actions `Done [     set ~key:"thekey" ~collection:"c1" "v1";     set ~key:"thekey" ~collection:"c2" "v2";   ]   >>= fun () ->   test_get ?collection:None "thekey" ((=) None) >>= fun () ->   test_get ~collection:"c1" "thekey" ((=) (Some "v1")) >>= fun () ->   test_get ~collection:"c2" "thekey" ((=) (Some "v2")) >>= fun () ->   test_actions `Not_done [     contains ~key:"k" "v";     set ~key:"k1" ~collection:"c" "V";   ] >>= fun () ->   test_actions `Done [     is_not_set "k";     set ~key:"k2" ~collection:"c" "V2";     set ~key:"k3" ~collection:"c" "V3";     set ~key:"k4" ~collection:"c" "V4";     set ~key:"k5" ~collection:"c" "V5";   ] >>= fun () ->   DB.get_all db ~collection:"c"   >>= fun list ->   local_assert "full collection 'c'"     (List.sort ~cmp:String.compare list = ["k1""k2""k3""k4""k5"]);   let key = "K" in   let insane =     let buf = Bytes.make 256 '\000' in     for i = 0 to 255 do Bytes.set buf i (char_of_int i) done;     Bytes.to_string buf in   test_actions `Done [     set ~key "\"";     set ~key "\\\"";     set ~key "\"'\"";     set ~key:insane insane;   ]   >>= fun () ->   test_get ?collection:None insane ((=) (Some insane))   >>= fun () ->   let to_list res_stream =     let rec go acc =       res_stream ()       >>= function       | None -> return acc       | Some v -> go (v :: acc) in     go []   in   let list_equal l1 l2 =     let prep = List.sort ~cmp:Pervasives.compare in     match prep l1 = prep l2 with     | true -> true     | false ->       say "[%s] ≠ [%s]"         (String.concat  ~sep:", " l1)         (String.concat  ~sep:", " l2);       false   in   let check_iterator_like_get_all ~collection =     let stream = DB.iterator db ~collection in     to_list stream     >>= fun all ->     DB.get_all db ~collection     >>= fun all_too ->     local_assert (sprintf "iter %s" collection) (list_equal all all_too);     return ()   in   check_iterator_like_get_all "c" >>= fun () ->   check_iterator_like_get_all "cc" >>= fun () ->   (*      We now test going through a collection with `iterator` while      modifying the values of the collection.   *)   let make_self_collection ~collection =     let keyvalues = List.init 10 ~f:(sprintf "kv%d"in     let actions = List.map keyvalues ~f:(fun kv -> set ~collection ~key:kv kv) in     test_actions `Done actions     >>= fun () ->     return keyvalues   in   let iterate_and_set ~collection =     let stream = DB.iterator db ~collection in     let rec go_through () =       stream () >>= function       | Some kv ->         (* say "%s got some %S in the stream" Test_db.test_name kv; *)         test_actions `Done [set ~collection ~key:kv ("SET" ^ kv)]         >>= fun () ->         go_through ()       | None -> return ()     in     go_through ()   in   let test_rw_interleave collection =     make_self_collection ~collection     >>= fun keyvalues ->     iterate_and_set ~collection     >>= fun () ->     check_iterator_like_get_all collection     >>= fun () ->     DB.get_all db ~collection     >>= fun allnew ->     (* let modified = List.map keyvalues (fun v -> "SET" ^ v) in *)     local_assert (sprintf "test_rw_interleave %s" collection)       (list_equal keyvalues allnew);     return ()   in   (* Test_db.debug_mode true; *)   test_rw_interleave "ccc"   >>= fun () ->   (*      We now try to delete all values in a collection while iterating on it.   *)   let iterate_and_delete ~collection ~at ~all =     let stream = DB.iterator db ~collection in     let rec go_through remaining =       stream () >>= function       | Some kv when remaining = 0 ->         say "%s got some %S in the stream" Test_db.test_name kv;         test_actions `Done (List.map all ~f:(fun key -> unset ~collection key))         >>= fun () ->         go_through (-1)       | Some kv ->         say "%s got some %S in the stream : remaining: %d" Test_db.test_name kv remaining;         go_through (remaining - 1)       | None -> return ()     in     go_through at   in   let test_delete_iterleave collection =     make_self_collection ~collection     >>= fun keyvalues ->     iterate_and_delete       ~collection ~all:keyvalues ~at:(List.length keyvalues / 2)     >>= fun () ->     DB.get_all db ~collection     >>= fun allnew ->     local_assert ("test_delete_iterleave") (allnew = []);     return ()   in   test_delete_iterleave "aaa"   >>= fun () ->   (* Read and write concurrently: *)   let bunch_of_ints = List.init 100 ~f:(fun i -> i) in   Deferred_list.for_concurrent bunch_of_ints ~f:(function     | n when n mod 2 = 0 ->       let v = sprintf "%d" n in       test_actions `Done [set ~key:v v]     | n ->       DB.get db ~key       >>= fun _ ->       return ()     )   >>= fun ((_ : unit list), errors) ->   begin match errors with   | [] -> return ()   | more ->     let msg =       sprintf "concurrent errors: %s"         (List.map more ~f:(function            | `Database (`Get _, m)            | `Database (`Act _, m) -> m)          |> String.concat ~sep:"; "in     local_assert msg false;     return ()   end   >>= fun () ->   (* Test_db.debug_mode false; *)   DB.close db