Tentacle enhancements.
This commit is contained in:
1 parent
4f9b89e38b
commit
9e15f8652d
12 files changed
+619
-22
No files matched your search
@@ -0,0 +1,151 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package tentacle
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
|
||||
)
|
||||
|
||||
func speech_fixture_lease(t *testing.T, session *Session, role string, grants []string) tentaclewire.RemoteLease {
|
||||
t.Helper()
|
||||
action, err := session.AuthorizeRemote(role, grants)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
invokeSessionSDK(t, session, "event", nil)
|
||||
raw, code := remoteCall(t, session, "remote.open", tentaclewire.RemoteOpen{Action: action.Action, Epoch: action.Epoch, Role: role, Grants: grants})
|
||||
if code != 0 {
|
||||
t.Fatal("open", code)
|
||||
}
|
||||
var lease tentaclewire.RemoteLease
|
||||
if err := json.Unmarshal(raw, &lease); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return lease
|
||||
}
|
||||
|
||||
func TestRemoteSpeechSDKDeliveryAndRevocation(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, "speech")
|
||||
lease := speech_fixture_lease(t, session, "controller", []string{"remote-present"})
|
||||
request := tentaclewire.RemotePresentation{RemoteOperation: tentaclewire.RemoteOperation{Lease: lease.Lease, Epoch: lease.Epoch, Sequence: 1}, Speech: tentaclewire.RemoteSpeech{Kind: "speak", Parts: []tentaclewire.RemoteSpeechPart{{Text: " text\t世界 ", Characters: true, Language: "en_US"}}}}
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != -32601 {
|
||||
t.Fatal("accepted without reader owner", code)
|
||||
}
|
||||
deliveries := session.EnableRemoteSpeech()
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != 0 {
|
||||
t.Fatal(code)
|
||||
}
|
||||
first := <-deliveries
|
||||
if first.Speech.Parts[0] != request.Speech.Parts[0] || first.Context.Err() != nil {
|
||||
t.Fatal("changed speech or invalid lifetime")
|
||||
}
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != -32001 {
|
||||
t.Fatal("accepted replay", code)
|
||||
}
|
||||
request.Sequence++
|
||||
request.Speech = tentaclewire.RemoteSpeech{Kind: "cancel"}
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != 0 {
|
||||
t.Fatal(code)
|
||||
}
|
||||
request.Sequence++
|
||||
paused := true
|
||||
request.Speech = tentaclewire.RemoteSpeech{Kind: "pause", Paused: &paused}
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != 0 {
|
||||
t.Fatal(code)
|
||||
}
|
||||
if (<-deliveries).Speech.Kind != "cancel" || (<-deliveries).Speech.Kind != "pause" {
|
||||
t.Fatal("lost cancel ordering")
|
||||
}
|
||||
// Heartbeat shares the operation sequence, but speech is not a heartbeat.
|
||||
if _, code := remoteCall(t, session, "remote.heartbeat", request.RemoteOperation); code != -32001 {
|
||||
t.Fatal("heartbeat replay", code)
|
||||
}
|
||||
request.Sequence++
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != 0 {
|
||||
t.Fatal(code)
|
||||
}
|
||||
session.RevokeRemote()
|
||||
if first.Context.Err() == nil {
|
||||
t.Fatal("accepted work survived revoke")
|
||||
}
|
||||
if _, err := session.RemoteContext(lease, "remote-present"); err == nil {
|
||||
t.Fatal("delivery-time authorization survived revoke")
|
||||
}
|
||||
select {
|
||||
case <-deliveries:
|
||||
t.Fatal("retained revoked work")
|
||||
default:
|
||||
}
|
||||
request.Sequence++
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != -32001 {
|
||||
t.Fatal("accepted stale lease", code)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteSpeechSDKOutputAndOrigins(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, "speech")
|
||||
lease := speech_fixture_lease(t, session, "controlled", []string{"output-observe"})
|
||||
value := tentaclewire.RemoteSpeech{Kind: "speak", Priority: 2, Parts: []tentaclewire.RemoteSpeechPart{{Text: " whitespace \n "}}}
|
||||
for _, origin := range []string{"remote", "status", "secret", ""} {
|
||||
if err := session.PublishRemoteSpeech(lease, origin, value); err == nil {
|
||||
t.Fatal("exported origin", origin)
|
||||
}
|
||||
}
|
||||
if err := session.PublishRemoteSpeech(lease, "local", value); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var event tentaclewire.SessionEvent
|
||||
if err := json.Unmarshal(invokeSessionSDK(t, session, "event", nil), &event); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if event.Kind != "remote.output" || event.Lease != lease.Lease || event.Epoch != lease.Epoch || event.Speech == nil || event.Speech.Parts[0] != value.Parts[0] {
|
||||
t.Fatal("changed output event", event)
|
||||
}
|
||||
if _, code := remoteCall(t, session, "remote.present", tentaclewire.RemotePresentation{RemoteOperation: tentaclewire.RemoteOperation{Lease: lease.Lease, Epoch: lease.Epoch, Sequence: 1}, Speech: value}); code != -32001 {
|
||||
t.Fatal("wrong-direction grant", code)
|
||||
}
|
||||
session.RevokeRemote()
|
||||
if err := session.PublishRemoteSpeech(lease, "local", value); err == nil {
|
||||
t.Fatal("exported after revoke")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoteSpeechQueueOverflowRetiresLease(t *testing.T) {
|
||||
manager := test_manager(t, DefaultLimits(), nil)
|
||||
session := startSessionSDK(t, manager, "go", "speech")
|
||||
lease := speech_fixture_lease(t, session, "controller", []string{"remote-present"})
|
||||
deliveries := session.EnableRemoteSpeech()
|
||||
request := tentaclewire.RemotePresentation{RemoteOperation: tentaclewire.RemoteOperation{Lease: lease.Lease, Epoch: lease.Epoch}, Speech: tentaclewire.RemoteSpeech{Kind: "cancel"}}
|
||||
for index := 1; index <= tentaclewire.RemoteSpeechQueueSize; index++ {
|
||||
request.Sequence = uint64(index)
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != 0 {
|
||||
t.Fatal(index, code)
|
||||
}
|
||||
}
|
||||
request.Sequence++
|
||||
if _, code := remoteCall(t, session, "remote.present", request); code != -32002 {
|
||||
t.Fatal("queue did not fail closed", code)
|
||||
}
|
||||
if _, err := session.RemoteContext(lease, "remote-present"); err == nil {
|
||||
t.Fatal("overflow retained authorization")
|
||||
}
|
||||
select {
|
||||
case <-deliveries:
|
||||
t.Fatal("overflow retained pending speech")
|
||||
default:
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user