about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEmery Hemingway <ehmry@posteo.net>2024-08-26T02·06+0300
committerEmery Hemingway <ehmry@posteo.net>2024-08-27T15·01+0300
commit0e35e937e47ce68c35ee6e997c81b2cd412bb32a (patch)
treec1422747480d3f8866b52891115ce4b58a14aad6
parent151037cf4dac74a3d9eb2cbe84f167a21c50d820 (diff)
Swap argument order at <eval …>
-rw-r--r--protocol.prs7
-rw-r--r--sbom.json2
-rw-r--r--src/nix_actor.nim2
-rw-r--r--tests/test_eval_actor.nim191
4 files changed, 197 insertions, 5 deletions
diff --git a/protocol.prs b/protocol.prs
index c39a44a6853d..e9ad096989c0 100644
--- a/protocol.prs
+++ b/protocol.prs
@@ -39,9 +39,10 @@ Realise = <realise @value any @result #:Result> .
 CopyClosure = <copy-closure @dest #:any @storePath string @result #:Result>.
 
 # Assertion.
-# Eval at a nix-repo. @expr must be a function that takes two parameters,
-# the first is the nix-repo value, the second is @args.
-# The result is asserted to @result
+# Eval at a nix capability.
+# @expr must be a function that takes two parameters,
+# the first is @args and the second is the value of
+# the previous evaluation. The result is asserted to @result
 Eval = <eval @expr string @args any @result #:Result> .
 
 AttrSet = {symbol: any ...:...} .
diff --git a/sbom.json b/sbom.json
index 4082821204a3..12deb59ddb58 100644
--- a/sbom.json
+++ b/sbom.json
@@ -7,7 +7,7 @@
       "bom-ref": "pkg:nim/nix_actor",
       "name": "nix_actor",
       "description": "Syndicated Nix Actor",
-      "version": "20240825",
+      "version": "20240826",
       "authors": [
         {
           "name": "Emery Hemingway"
diff --git a/src/nix_actor.nim b/src/nix_actor.nim
index e19b1397e251..2a2715296159 100644
--- a/src/nix_actor.nim
+++ b/src/nix_actor.nim
@@ -154,8 +154,8 @@ proc serve(entity: NixEntity; turn: Turn; r: Realise) =
 proc serve(entity: NixEntity; turn: Turn; e: Eval) =
   tryPublish(turn, e.result.Cap):
     var expr = entity.state.eval.evalFromString(e.expr)
-    expr = entity.state.eval.apply(expr, entity.root)
     expr = entity.state.eval.apply(expr, e.args.toNix(entity.state.eval))
+    expr = entity.state.eval.apply(expr, entity.root)
     publishOk(turn, e.result.Cap, entity.newChild(turn, expr).self.toPreserves)
 
 method publish(entity: NixEntity; turn: Turn; a: AssertionRef; h: Handle) =
diff --git a/tests/test_eval_actor.nim b/tests/test_eval_actor.nim
new file mode 100644
index 000000000000..384ab58635c0
--- /dev/null
+++ b/tests/test_eval_actor.nim
@@ -0,0 +1,191 @@
+# SPDX-FileCopyrightText: ☭ Emery Hemingway
+# SPDX-License-Identifier: Unlicense
+
+import
+  std/options,
+  pkg/balls,
+  pkg/sys/ioqueue,
+  pkg/preserves,
+  pkg/preserves/sugar,
+  pkg/syndicate,
+  pkg/syndicate/protocols/[gatekeeper, rpc],
+  ../src/nix_actor,
+  ../src/nix_actor/[nix_api, nix_values, protocol]
+
+type Value = preserves.Value
+
+initLibstore()
+initLibexpr()
+
+type
+  ResultContinuation {.final.} = ref object of Entity
+    cb: proc (turn: Turn; v: Value)
+
+method publish(cont: ResultContinuation; turn: Turn; ass: AssertionRef; h: Handle) =
+  cont.cb(turn, ass.value)
+
+proc newResultContinuation[T](turn: Turn; cb: proc (turn: Turn; v: T)): Cap =
+  proc wrapper(turn: Turn; v: Value) =
+    var
+      err: ResultError
+      ok: ResultOk
+    if err.fromPreserves(v):
+      raiseAssert $err.error
+    check ok.fromPreserves(v)
+    var x = ok.value.preservesTo(T)
+    check x.isSome
+    if x.isSome: cb(turn, x.get)
+  turn.newCap(ResultContinuation(cb: wrapper))
+
+suite "basic":
+
+  var completed: bool
+
+  proc actorTest(turn: Turn) =
+    turn.onStop do (turn: Turn):
+      block:
+        ## actor stopped
+        check completed
+
+    checkpoint "actor booted"
+    let rootFacet = turn.facet
+    let ds = turn.newDataspace()
+
+    let stepC = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepC"
+      block:
+        ## stepC
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint("stepC grabbed nix value " & $v)
+          assert not v.isRecord("null")
+          assert v == %"Hello VolgaSprint!"
+          completed = true
+          stop(rootFacet)
+
+    let stepB = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepB"
+      block:
+        ## stepB
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint("stepB grabbed nix value " & $v)
+          assert not v.isRecord("null")
+          check v == %"Hello Volga"
+        publish(turn, nix, Eval(
+            expr: "y: x: x + y",
+            args: %"Sprint!",
+            result: stepC
+          ))
+
+    let stepA = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepA"
+      block:
+        ## stepA
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint "stepA grabbed nix value " & $v
+          assert not v.isRecord("null")
+          check v == %"Hello"
+        publish(turn, nix, Eval(
+            expr: "y: x: x + y",
+            args: %" Volga",
+            result: stepB
+          ))
+
+    during(turn, ds, ResolvedAccepted.grabWithin) do (nix: Cap):
+      checkpoint "resolve accepted"
+      block:
+        ## Resolved nix actor through gatekeeper
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint $v
+        publish(turn, nix, Eval(
+            expr: "y: x: y",
+            args: %"Hello",
+            result: stepA,
+          ))
+
+    during(turn, ds, Rejected.grabType) do (rej: Rejected):
+      raiseAssert("resolve failed: " & $rej)
+
+    publish(turn, ds, Resolve(
+        step: parsePreserves"""<nix { }>""",
+        observer: ds,
+      ))
+
+    nix_actor.bootActor(turn, ds)
+
+  block:
+    ## runActor
+    runActor("tests", actorTest)
+    check completed
+
+suite "nixpkgs":
+
+  var completed: bool
+
+  proc actorTest(turn: Turn) =
+    turn.onStop do (turn: Turn):
+      block:
+        ## actor stopped
+        check completed
+
+    checkpoint "actor booted"
+    let rootFacet = turn.facet
+    let ds = turn.newDataspace()
+
+    let stepC = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepC"
+      block:
+        ## stepC
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint("stepC grabbed nix value " & $v)
+          assert v == %"https://9fans.github.io/plan9port/"
+          completed = true
+          stop(rootFacet)
+
+    let stepB = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepB"
+      block:
+        ## stepB
+        publish(turn, nix, Eval(
+            expr: "_: pkg: pkg.meta.homepage",
+            args: %false,
+            result: stepC
+          ))
+
+    let stepA = newResultContinuation(turn) do (turn: Turn; nix: Cap):
+      checkpoint "stepA"
+      block:
+        ## stepA
+        publish(turn, nix, Eval(
+            expr: "builtins.getAttr",
+            args: %"plan9port",
+            result: stepB
+          ))
+
+    during(turn, ds, ResolvedAccepted.grabWithin) do (nix: Cap):
+      checkpoint "resolve accepted"
+      block:
+        ## Resolved nix actor through gatekeeper
+        onPublish(turn, nix, grab()) do (v: Value):
+          checkpoint $v
+        publish(turn, nix, Eval(
+            expr: "args: _: import <nixpkgs> args",
+            args: initDictionary(),
+            result: stepA,
+          ))
+
+    during(turn, ds, Rejected.grabType) do (rej: Rejected):
+      raiseAssert("resolve failed: " & $rej)
+
+    publish(turn, ds, Resolve(
+        step: parsePreserves"""
+            <nix { lookupPath: [ "nixpkgs=/home/repo/nixpkgs" ] }>
+          """,
+        observer: ds,
+      ))
+
+    nix_actor.bootActor(turn, ds)
+
+  block:
+    ## runActor
+    runActor("tests", actorTest)
+    check completed