diff options
Diffstat (limited to '')
| -rw-r--r-- | test/test_rnt.ml | 5 | ||||
| -rw-r--r-- | test/unit/backend/Lifecycle.ml | 147 | ||||
| -rw-r--r-- | test/unit/backend/Storage.ml | 6 | ||||
| -rw-r--r-- | test/unit/concepts/Serialization.ml | 45 |
4 files changed, 4 insertions, 199 deletions
diff --git a/test/test_rnt.ml b/test/test_rnt.ml index d46be1e..c4fbbaf 100644 --- a/test/test_rnt.ml +++ b/test/test_rnt.ml @@ -1,7 +1,4 @@ let all_suites = - Unit.Concepts.Serialization.suites () - @ Unit.Backend.Storage.suites () - @ Unit.Backend.Lifecycle.suites () - @ Unit.Kernel.Merkle.suites () + Unit.Backend.Storage.suites () let () = Alcotest.run "RNT" all_suites diff --git a/test/unit/backend/Lifecycle.ml b/test/unit/backend/Lifecycle.ml deleted file mode 100644 index 3e5b3e9..0000000 --- a/test/unit/backend/Lifecycle.ml +++ /dev/null @@ -1,147 +0,0 @@ -module Object = Rnt.Backend.Managers.Object -module Lifecycle = Rnt.Backend.Managers.Lifecycle -module Path = Rnt.Concepts.Path - -(* Small builders so the tests read like the invariants they check. *) - -let path segments = Path.of_list segments -let relation name = Object.make_object (Object.Relation {merkle_root= name}) - -let session () = - Object.make_object (Object.Session {connection_context= (); branch_overrides= BatMap.String.empty}) - -let branch name = Object.make_object (Object.Branch {name; target_hash= "hash"}) -let namespace label = Object.make_object (Object.Namespace {label; predicate= (fun _ -> true)}) -let dependencies paths = List.fold_left BatFingerTree.snoc BatFingerTree.empty paths - -let ephemeral name deps = - Object.make_object (Object.EphemeralRelation {merkle_root= name; dependencies= dependencies deps}) - -let register_exn tree p object' = Helpers.condition_as_failure (Object.register p object' tree) -let unregister_exn tree p = Helpers.condition_as_failure (Object.unregister p tree) -let collect_exn tree p = Helpers.condition_as_failure (Lifecycle.collect tree p) - -let reference_count tree p = - match Object.find p tree with Some r -> r.Object.reference_count | None -> -1 - -let present tree p = Object.find p tree <> None - -(* An ephemeral relation holds its inputs resident. Registering it raises the - input's reference_count; unregistering it lowers it again. This is the - distinction between reference counting (real edges) and pinning. *) -let test_edges_track_dependents () = - let tree = register_exn Object.root (path ["r1"]) (relation "r1") in - let tree = register_exn tree (path ["er1"]) (ephemeral "er1" [path ["r1"]]) in - Alcotest.(check int) - "dependent raises the input's reference count" 1 - (reference_count tree (path ["r1"])); - let tree = unregister_exn tree (path ["er1"]) in - Alcotest.(check int) - "removing the dependent releases the input" 0 - (reference_count tree (path ["r1"])) - -(* The four gates of eligibility, each shown to block on its own. *) -let test_eligibility_gates () = - let tree = register_exn Object.root (path ["r1"]) (relation "r1") in - Alcotest.(check bool) - "a fresh durable object is collectable" true - (Lifecycle.is_eligible_for_gc tree (path ["r1"])); - Alcotest.(check bool) - "an open handle blocks collection" false - (Lifecycle.is_eligible_for_gc (Lifecycle.monitor tree (path ["r1"])) (path ["r1"])); - Alcotest.(check bool) - "a pin blocks collection" false - (Lifecycle.is_eligible_for_gc (Lifecycle.pin tree (path ["r1"])) (path ["r1"])); - let with_branch = register_exn Object.root (path ["b1"]) (branch "b1") in - Alcotest.(check bool) - "a branch is exempt even with zero counts" false - (Lifecycle.is_eligible_for_gc with_branch (path ["b1"])) - -(* Collecting a dependent cascades into the inputs it releases, and the input - cannot be collected first while the dependent is alive. *) -let test_cascade_follows_edges () = - let tree = register_exn Object.root (path ["r1"]) (relation "r1") in - let tree = register_exn tree (path ["er1"]) (ephemeral "er1" [path ["r1"]]) in - Alcotest.(check bool) - "a live dependent keeps its input" false - (Lifecycle.is_eligible_for_gc tree (path ["r1"])); - let tree, disposals = collect_exn tree (path ["er1"]) in - Alcotest.(check bool) "the dependent is collected" false (present tree (path ["er1"])); - Alcotest.(check bool) "the released input is cascaded out" false (present tree (path ["r1"])); - Alcotest.(check int) "durable collection needs no disposal" 0 (BatFingerTree.size disposals) - -(* A pin overrides the cascade: the input stays even after its dependent goes. *) -let test_pin_survives_cascade () = - let tree = register_exn Object.root (path ["r1"]) (relation "r1") in - let tree = register_exn tree (path ["er1"]) (ephemeral "er1" [path ["r1"]]) in - let tree = Lifecycle.pin tree (path ["r1"]) in - let tree, _ = collect_exn tree (path ["er1"]) in - Alcotest.(check bool) "the dependent is still collected" false (present tree (path ["er1"])); - Alcotest.(check bool) "the pinned input survives" true (present tree (path ["r1"])) - -(* Collecting a runtime object surfaces a disposal for the caller to run, - because there is no durable form to rehydrate from. *) -let test_runtime_collection_surfaces_disposal () = - let tree = register_exn Object.root (path ["s1"]) (session ()) in - let tree, disposals = collect_exn tree (path ["s1"]) in - Alcotest.(check bool) "the session is removed" false (present tree (path ["s1"])); - match BatFingerTree.front disposals with - | Some (rest, {Lifecycle.kind= Object.Session _; _}) when BatFingerTree.is_empty rest -> () - | _ -> Alcotest.fail "expected exactly one session disposal" - -(* A namespace with objects under it is scaffolding, so it is kept rather than - collected, and this is not an error. *) -let test_populated_namespace_is_kept () = - let tree = register_exn Object.root (path ["ns"]) (namespace "ns") in - let tree = register_exn tree (path ["ns"; "r1"]) (relation "r1") in - let tree, _ = collect_exn tree (path ["ns"]) in - Alcotest.(check bool) "a populated namespace is kept" true (present tree (path ["ns"])) - -(* Property: pinning is a decision, reference counting is bookkeeping. No - sequence of pin/unpin may ever move the reference count. *) -let prop_pin_never_moves_reference_count = - QCheck.Test.make ~name:"pin/unpin never changes reference_count" ~count:200 - QCheck.(list bool) - (fun operations -> - let tree = register_exn Object.root (path ["r1"]) (relation "r1") in - let tree = - List.fold_left - (fun tree pin -> - if pin then Lifecycle.pin tree (path ["r1"]) else Lifecycle.unpin tree (path ["r1"]) ) - tree operations - in - reference_count tree (path ["r1"]) = 0 ) - -(* Property: reference edges are balanced. Registering an ephemeral relation - over any selection of inputs and then unregistering it returns every input - to its baseline count, whatever the selection or its duplicates. *) -let prop_edges_are_balanced = - QCheck.Test.make ~name:"register then unregister an ER restores input counts" ~count:200 - QCheck.(pair (int_range 1 5) (list (int_range 0 4))) - (fun (input_count, selection) -> - let inputs = List.init input_count (fun i -> path [Printf.sprintf "r%d" i]) in - let tree = - List.fold_left - (fun tree p -> register_exn tree p (relation (Path.to_string p))) - Object.root inputs - in - let chosen = - List.filter (fun i -> i < input_count) selection - |> List.map (fun i -> path [Printf.sprintf "r%d" i]) - in - let tree = register_exn tree (path ["er"]) (ephemeral "er" chosen) in - let tree = unregister_exn tree (path ["er"]) in - List.for_all (fun p -> reference_count tree p = 0) inputs ) - -let suites () = - [ ( "lifecycle/registry", - [ Alcotest.test_case "edges track dependents" `Quick test_edges_track_dependents; - Alcotest.test_case "eligibility gates" `Quick test_eligibility_gates; - Alcotest.test_case "cascade follows edges" `Quick test_cascade_follows_edges; - Alcotest.test_case "pin survives cascade" `Quick test_pin_survives_cascade; - Alcotest.test_case "runtime collection surfaces disposal" `Quick - test_runtime_collection_surfaces_disposal; - Alcotest.test_case "populated namespace is kept" `Quick test_populated_namespace_is_kept ] ); - ( "lifecycle/properties", - List.map QCheck_alcotest.to_alcotest - [prop_pin_never_moves_reference_count; prop_edges_are_balanced] ) ] diff --git a/test/unit/backend/Storage.ml b/test/unit/backend/Storage.ml index e184e1b..a6765bf 100644 --- a/test/unit/backend/Storage.ml +++ b/test/unit/backend/Storage.ml @@ -6,9 +6,9 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = module H = Helpers.Storage.Make (S) (C) let storage_and_retrieval conn = - let key = Concepts.Hash.hash_of_value (Concepts.Value.String "value") in + let key = Concepts.Value.String "value" |> Concepts.Encoding.blob_of_value |> Concepts.Hash.hash_of_blob in let value = Concepts.Value.Integer 42 in - let blob = Concepts.Representation.blob_of_value value in + let blob = Concepts.Encoding.blob_of_value value in let v, v' = begin let open Utilities.Result in @@ -16,7 +16,7 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let* v = S.get tx (S.Hash key) in let* () = S.put tx (S.Hash key) blob in let* v' = S.get tx (S.Hash key) in - Ok Concepts.Representation.(Option.map value_of_blob v, Option.map value_of_blob v') + Ok Concepts.Encoding.(Option.map value_of_blob v, Option.map value_of_blob v') end |> Helpers.condition_as_failure in diff --git a/test/unit/concepts/Serialization.ml b/test/unit/concepts/Serialization.ml deleted file mode 100644 index 9df8d26..0000000 --- a/test/unit/concepts/Serialization.ml +++ /dev/null @@ -1,45 +0,0 @@ -module Branch = Rnt.Concepts.Branch -module Hash = Rnt.Concepts.Hash -module Multigroup = Rnt.Concepts.Multigroup -module Relation = Rnt.Concepts.Relation - -let fail_condition c = Alcotest.fail (Rnt.Concepts.Condition.to_string_hum c) -let hash text = Hash.hash_of_bytes (Bytes.of_string text) - -let check_hash label expected actual = - Alcotest.(check bool) label true (Hash.hash_equals expected actual) - -let test_branch_round_trips () = - let expected = Branch.make ~name:"master" ~target:(hash "master-target") in - match Branch.(expected |> to_bytes |> of_bytes) with - | Ok actual -> - Alcotest.(check string) "name" (Branch.name expected) (Branch.name actual); - check_hash "target" (Branch.target expected) (Branch.target actual) - | Error c -> fail_condition c - -let test_multigroup_round_trips () = - let expected = Multigroup.make ~name:"public" ~relations:(hash "public-relations") in - match Multigroup.(expected |> to_bytes |> of_bytes) with - | Ok actual -> - Alcotest.(check string) "name" (Multigroup.name expected) (Multigroup.name actual); - check_hash "relations" (Multigroup.relations expected) (Multigroup.relations actual) - | Error c -> fail_condition c - -let test_relation_round_trips () = - let schema = Relation.schema_of_list ["tag", "string"; "name", "string"] in - let expected = Relation.make ~name:"users" ~tuples:(hash "users-tuples") ~schema in - match Relation.(expected |> to_bytes |> of_bytes) with - | Ok actual -> - Alcotest.(check string) "name" (Relation.name expected) (Relation.name actual); - check_hash "tuples" (Relation.tuples expected) (Relation.tuples actual); - Alcotest.(check (list (pair string string))) - "schema" - (Relation.schema expected |> Relation.schema_to_list) - (Relation.schema actual |> Relation.schema_to_list) - | Error c -> fail_condition c - -let suites () = - [ ( "concepts/serialization", - [ Alcotest.test_case "branch round-trips" `Quick test_branch_round_trips; - Alcotest.test_case "multigroup round-trips" `Quick test_multigroup_round_trips; - Alcotest.test_case "relation round-trips" `Quick test_relation_round_trips ] ) ] |
