ScuttleBot

scuttlebot / cmd / gemini-relay / main_test.go
Source Blame History 128 lines
016a29f… lmata 1 package main
016a29f… lmata 2
016a29f… lmata 3 import (
016a29f… lmata 4 "bytes"
016a29f… lmata 5 "path/filepath"
016a29f… lmata 6 "testing"
016a29f… lmata 7 "time"
016a29f… lmata 8
016a29f… lmata 9 "github.com/conflicthq/scuttlebot/pkg/sessionrelay"
016a29f… lmata 10 )
016a29f… lmata 11
016a29f… lmata 12 func TestFilterMessages(t *testing.T) {
016a29f… lmata 13 now := time.Now()
016a29f… lmata 14 nick := "gemini-test"
016a29f… lmata 15 messages := []message{
016a29f… lmata 16 {Nick: "operator", Text: "gemini-test: hello", At: now},
016a29f… lmata 17 {Nick: "gemini-test", Text: "i am gemini", At: now}, // self
016a29f… lmata 18 {Nick: "other", Text: "not for me", At: now}, // no mention
016a29f… lmata 19 {Nick: "bridge", Text: "system message", At: now}, // service bot
016a29f… lmata 20 }
016a29f… lmata 21
cefe27d… lmata 22 filtered, _ := filterMessages(messages, now.Add(-time.Minute), nick, "worker")
016a29f… lmata 23 if len(filtered) != 1 {
016a29f… lmata 24 t.Errorf("expected 1 filtered message, got %d", len(filtered))
016a29f… lmata 25 }
016a29f… lmata 26 if filtered[0].Nick != "operator" {
016a29f… lmata 27 t.Errorf("expected operator message, got %s", filtered[0].Nick)
016a29f… lmata 28 }
016a29f… lmata 29 }
016a29f… lmata 30
016a29f… lmata 31 func TestLoadConfig(t *testing.T) {
016a29f… lmata 32 t.Setenv("SCUTTLEBOT_CONFIG_FILE", filepath.Join(t.TempDir(), "scuttlebot-relay.env"))
016a29f… lmata 33 t.Setenv("SCUTTLEBOT_URL", "http://test:8080")
016a29f… lmata 34 t.Setenv("SCUTTLEBOT_TOKEN", "test-token")
016a29f… lmata 35 t.Setenv("GEMINI_SESSION_ID", "abc")
016a29f… lmata 36 t.Setenv("SCUTTLEBOT_TRANSPORT", "irc")
016a29f… lmata 37 t.Setenv("SCUTTLEBOT_IRC_ADDR", "127.0.0.1:7667")
016a29f… lmata 38 t.Setenv("SCUTTLEBOT_SESSION_ID", "")
016a29f… lmata 39 t.Setenv("SCUTTLEBOT_NICK", "")
016a29f… lmata 40
016a29f… lmata 41 cfg, err := loadConfig([]string{"--cd", "../.."})
016a29f… lmata 42 if err != nil {
016a29f… lmata 43 t.Fatal(err)
016a29f… lmata 44 }
016a29f… lmata 45
016a29f… lmata 46 if cfg.URL != "http://test:8080" {
016a29f… lmata 47 t.Errorf("expected URL http://test:8080, got %s", cfg.URL)
016a29f… lmata 48 }
016a29f… lmata 49 if cfg.Token != "test-token" {
016a29f… lmata 50 t.Errorf("expected token test-token, got %s", cfg.Token)
016a29f… lmata 51 }
016a29f… lmata 52 if cfg.SessionID != "abc" {
016a29f… lmata 53 t.Errorf("expected session ID abc, got %s", cfg.SessionID)
016a29f… lmata 54 }
016a29f… lmata 55 if cfg.Nick != "gemini-scuttlebot-abc" {
016a29f… lmata 56 t.Errorf("expected nick gemini-scuttlebot-abc, got %s", cfg.Nick)
016a29f… lmata 57 }
016a29f… lmata 58 if cfg.Transport != sessionrelay.TransportIRC {
016a29f… lmata 59 t.Errorf("expected transport irc, got %s", cfg.Transport)
016a29f… lmata 60 }
016a29f… lmata 61 if cfg.IRCAddr != "127.0.0.1:7667" {
016a29f… lmata 62 t.Errorf("expected irc addr 127.0.0.1:7667, got %s", cfg.IRCAddr)
016a29f… lmata 63 }
016a29f… lmata 64 }
016a29f… lmata 65
016a29f… lmata 66 func TestRelayStateShouldInterruptOnlyWhenRecentlyBusy(t *testing.T) {
016a29f… lmata 67 t.Helper()
016a29f… lmata 68
016a29f… lmata 69 var state relayState
016a29f… lmata 70 now := time.Date(2026, 3, 31, 21, 47, 0, 0, time.UTC)
016a29f… lmata 71 state.observeOutput([]byte("Working (1s • esc to interrupt)"), now)
016a29f… lmata 72
016a29f… lmata 73 if !state.shouldInterrupt(now.Add(defaultBusyWindow / 2)) {
016a29f… lmata 74 t.Fatal("shouldInterrupt = false, want true for recent busy session")
016a29f… lmata 75 }
016a29f… lmata 76 if state.shouldInterrupt(now.Add(defaultBusyWindow + time.Millisecond)) {
016a29f… lmata 77 t.Fatal("shouldInterrupt = true, want false after busy window expires")
016a29f… lmata 78 }
016a29f… lmata 79 }
016a29f… lmata 80
016a29f… lmata 81 func TestInjectMessagesIdleSkipsCtrlCAndSubmits(t *testing.T) {
016a29f… lmata 82 t.Helper()
016a29f… lmata 83
016a29f… lmata 84 var writer bytes.Buffer
016a29f… lmata 85 cfg := config{
016a29f… lmata 86 Nick: "gemini-scuttlebot-1234",
016a29f… lmata 87 InterruptOnMessage: true,
016a29f… lmata 88 }
016a29f… lmata 89 state := &relayState{}
016a29f… lmata 90 batch := []message{{
016a29f… lmata 91 Nick: "glengoolie",
016a29f… lmata 92 Text: "gemini-scuttlebot-1234: check README.md",
016a29f… lmata 93 }}
016a29f… lmata 94
1d3caa2… lmata 95 if err := injectMessages(&writer, cfg, state, "#general", batch); err != nil {
016a29f… lmata 96 t.Fatal(err)
016a29f… lmata 97 }
016a29f… lmata 98
1d3caa2… lmata 99 want := bracketedPasteStart + "[IRC operator messages]\n[general] glengoolie: check README.md\n" + bracketedPasteEnd + "\r"
016a29f… lmata 100 if writer.String() != want {
016a29f… lmata 101 t.Fatalf("injectMessages idle = %q, want %q", writer.String(), want)
016a29f… lmata 102 }
016a29f… lmata 103 }
016a29f… lmata 104
016a29f… lmata 105 func TestInjectMessagesBusySendsCtrlCBeforeSubmit(t *testing.T) {
016a29f… lmata 106 t.Helper()
016a29f… lmata 107
016a29f… lmata 108 var writer bytes.Buffer
016a29f… lmata 109 cfg := config{
016a29f… lmata 110 Nick: "gemini-scuttlebot-1234",
016a29f… lmata 111 InterruptOnMessage: true,
016a29f… lmata 112 }
016a29f… lmata 113 state := &relayState{}
016a29f… lmata 114 state.observeOutput([]byte("Working (2s • esc to interrupt)"), time.Now())
016a29f… lmata 115 batch := []message{{
016a29f… lmata 116 Nick: "glengoolie",
016a29f… lmata 117 Text: "gemini-scuttlebot-1234: stop and re-read bridge.go",
016a29f… lmata 118 }}
016a29f… lmata 119
1d3caa2… lmata 120 if err := injectMessages(&writer, cfg, state, "#general", batch); err != nil {
016a29f… lmata 121 t.Fatal(err)
016a29f… lmata 122 }
016a29f… lmata 123
1d3caa2… lmata 124 want := string([]byte{3}) + bracketedPasteStart + "[IRC operator messages]\n[general] glengoolie: stop and re-read bridge.go\n" + bracketedPasteEnd + "\r"
016a29f… lmata 125 if writer.String() != want {
016a29f… lmata 126 t.Fatalf("injectMessages busy = %q, want %q", writer.String(), want)
016a29f… lmata 127 }
016a29f… lmata 128 }

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button