sic v2 client WP3: buildChain — fold wrapHop into the nested onion

buildChain(verbs, cmd, payload): innermost v2Frame(cmd,payload), wrap outward so verbs[0] is the
outermost layer; zero verbs = a single v2 frame (bare host). @godev/deepseek.
This commit is contained in:
Claude (noether)
2026-07-23 11:18:20 +02:00
parent f412d84738
commit f72c77e2a7
2 changed files with 40 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
package main
import (
"bytes"
"testing"
)
// WP3: buildChain folds wrapHop over the resolved per-hop verbs (verbs[0] outermost) around the
// innermost v2Frame(cmd, payload). Relational: each want is built from the real v2Frame/wrapHop,
// so this pins the composition and fold ORDER, not a re-derived byte layout.
func TestBuildChain(t *testing.T) {
cmd := []byte("cat")
payload := []byte("hi")
cases := []struct {
name string
verbs []string
want []byte
}{
{"zero hops nil = single v2 frame", nil, v2Frame(cmd, payload)},
{"zero hops empty slice", []string{}, v2Frame(cmd, payload)},
{"one hop", []string{"incus exec c --"},
wrapHop("incus exec c --", v2Frame(cmd, payload))},
{"two hops, verbs[0] is the OUTERMOST layer", []string{"incus exec c --", "docker exec d"},
wrapHop("incus exec c --", wrapHop("docker exec d", v2Frame(cmd, payload)))},
}
for _, tc := range cases {
if got := buildChain(tc.verbs, cmd, payload); !bytes.Equal(got, tc.want) {
t.Fatalf("%s:\n got % x\n want % x", tc.name, got, tc.want)
}
}
}
+9
View File
@@ -33,3 +33,12 @@ func v2Frame(command []byte, payload []byte) []byte {
func wrapHop(verb string, inner []byte) []byte {
return v2Frame([]byte(verb+" sicd"), inner)
}
// buildChain builds a chain of wrapped frames from verbs, with the innermost being v2Frame(cmd, payload).
func buildChain(verbs []string, cmd []byte, payload []byte) []byte {
frame := v2Frame(cmd, payload)
for i := len(verbs) - 1; i >= 0; i-- {
frame = wrapHop(verbs[i], frame)
}
return frame
}