aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorEstevan Castilho <tevo@riajuu.net>2026-08-22 17:55:26 +0000
committerEstevan Castilho <tevo@riajuu.net>2026-08-23 03:06:58 +0000
commitdb968eccee931abc8ad00d74d152625a2ab3174e (patch)
tree3d5018dd9e298cfc1fb14bf404cde3fce5953fca /test
parentb242516fc820a0a1ab00e24151a5b978f9a6f4a3 (diff)
downloadRNT-db968eccee931abc8ad00d74d152625a2ab3174e.tar.gz
RNT-db968eccee931abc8ad00d74d152625a2ab3174e.zip
Tidy up
Diffstat (limited to 'test')
-rw-r--r--test/test_rnt.ml5
-rw-r--r--test/unit/backend/Lifecycle.ml147
-rw-r--r--test/unit/backend/Storage.ml6
-rw-r--r--test/unit/concepts/Serialization.ml45
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 ] ) ]