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>
120 lines
5.4 KiB
Go
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")
|
|
}
|
|
}
|