Files
cthulhu/internal/tentacle/remote_braille_test.go
Chase CichorzandClaude Opus 5.5 2651b5e9bd Add Remote Braille IPC to the host and both SDKs
remote.braille requests and events carry a typed op under a
braille-stream lease: the controller's width and gestures for a
controlled reader, rendered cells back to its child, and cells, local
geometry and display gestures for a controller. Direction is validated
per role; a full mailbox revokes the lease. No display owner is
attached yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 16:06:38 -05:00

120 lines
5.4 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package tentacle
import (
"encoding/json"
"errors"
"reflect"
"strings"
"testing"
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
)
func brailleRequest(lease tentaclewire.RemoteLease, sequence uint64, value tentaclewire.RemoteBraille) tentaclewire.RemoteBrailleRequest {
return tentaclewire.RemoteBrailleRequest{RemoteOperation: tentaclewire.RemoteOperation{Lease: lease.Lease, Epoch: lease.Epoch, Sequence: sequence}, Braille: value}
}
func TestRemoteBrailleSDKDirectionsAndEvents(t *testing.T) {
for _, language := range []string{"go", "python"} {
t.Run(language, func(t *testing.T) {
manager := test_manager(t, DefaultLimits(), nil)
session := startSessionSDK(t, manager, language, "braille", "braille-stream")
lease := speech_fixture_lease(t, session, "controlled", []string{"output-observe", "braille-stream"})
size := tentaclewire.RemoteBraille{Op: "size", Width: 40}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 1, size)); code != -32601 {
t.Fatal("Braille admitted without owner", code)
}
deliveries := session.EnableRemoteBraille()
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 1, size)); code != 0 {
t.Fatal("size refused", code)
}
if delivery := <-deliveries; delivery.Role != "controlled" || !reflect.DeepEqual(delivery.Braille, size) || delivery.Lease != lease {
t.Fatal("size delivery changed", delivery)
}
route := tentaclewire.RemoteBraille{Op: "gesture", Gesture: "route", Index: 7}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 2, route)); code != 0 {
t.Fatal("gesture refused", code)
}
<-deliveries
cells := tentaclewire.RemoteBraille{Op: "cells", Cells: []int{1, 255, 0}}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 3, cells)); code != -32001 {
t.Fatal("controlled child sent display cells to its reader", code)
}
if err := session.PublishRemoteBraille(lease, cells); err != nil {
t.Fatal(err)
}
if event := nextSDKEvent(t, session); event.Kind != "remote.braille" || event.Braille == nil || !reflect.DeepEqual(*event.Braille, cells) {
t.Fatal("cells event changed", event)
}
if !errors.Is(session.PublishRemoteBraille(lease, route), ErrPermission) {
t.Fatal("controlled reader published a gesture")
}
session.RevokeRemote()
nextSDKEvent(t, session)
lease = speech_fixture_lease(t, session, "controller", []string{"remote-present", "braille-stream"})
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 1, cells)); code != 0 {
t.Fatal("controller cells refused", code)
}
if delivery := <-deliveries; delivery.Role != "controller" || !reflect.DeepEqual(delivery.Braille.Cells, cells.Cells) {
t.Fatal("controller cells changed", delivery)
}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 2, size)); code != -32001 {
t.Fatal("controller sent a size request", code)
}
for _, value := range []tentaclewire.RemoteBraille{{Op: "geometry", Width: 32}, {Op: "gesture", Gesture: "pan-right"}} {
if err := session.PublishRemoteBraille(lease, value); err != nil {
t.Fatal(err)
}
if event := nextSDKEvent(t, session); event.Braille == nil || !reflect.DeepEqual(*event.Braille, value) {
t.Fatal("controller event changed", event)
}
}
data, _ := json.Marshal(brailleRequest(lease, 3, cells))
for _, raw := range []string{
strings.Replace(string(data), `[1,255,0]`, `[1,256,0]`, 1),
strings.Replace(string(data), `"op":"cells"`, `"op":"text"`, 1),
strings.Replace(string(data), `"op":"cells"`, `"op":"cells","width":3`, 1),
strings.Replace(string(data), `"sequence":3`, `"sequence":3,"origin":"local"`, 1),
} {
if _, code := remoteCall(t, session, "remote.braille", json.RawMessage(raw)); code != -32602 {
t.Fatal("invalid Braille admitted", code, raw)
}
}
session.RevokeRemote()
nextSDKEvent(t, session)
if !errors.Is(session.PublishRemoteBraille(lease, cells), ErrPermission) {
t.Fatal("retired lease published Braille")
}
})
}
}
func TestRemoteBrailleSDKGrantAndSaturation(t *testing.T) {
manager := test_manager(t, DefaultLimits(), nil)
session := startSessionSDK(t, manager, "go", "braille", "braille-stream")
deliveries := session.EnableRemoteBraille()
lease := speech_fixture_lease(t, session, "controlled", []string{"output-observe"})
size := tentaclewire.RemoteBraille{Op: "size", Width: 40}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 1, size)); code != -32001 {
t.Fatal("Braille admitted without grant", code)
}
session.RevokeRemote()
invokeSessionSDK(t, session, "event", nil)
lease = speech_fixture_lease(t, session, "controlled", []string{"braille-stream"})
for sequence := uint64(1); sequence <= tentaclewire.RemoteBrailleQueueSize; sequence++ {
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, sequence, size)); code != 0 {
t.Fatal("refused before saturation", code)
}
}
if _, code := remoteCall(t, session, "remote.braille", brailleRequest(lease, 99, size)); code != -32002 {
t.Fatal("saturation did not fail", code)
}
if _, err := session.RemoteContext(lease, "braille-stream"); err == nil || len(deliveries) != 0 {
t.Fatal("saturation left the lease or queue")
}
}