Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
- OAuth PKCE flow for Max subscription auth (no API key needed) - Claude API client with SSE streaming (Messages API v1) - 16 tool definitions: terminal, SFTP, RDP, session management - Tool dispatch router mapping to existing Wraith services - Conversation manager with SQLite persistence - Terminal output ring buffer for AI context - RDP screenshot encoder (RGBA → JPEG with downscaling) - Wired into Wails app as AIService Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
176 lines
3.6 KiB
Go
176 lines
3.6 KiB
Go
package ai
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
func TestWriteAndRead(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
|
|
buf.Write([]byte("line1\nline2\nline3\n"))
|
|
|
|
all := buf.ReadAll()
|
|
if len(all) != 3 {
|
|
t.Fatalf("expected 3 lines, got %d", len(all))
|
|
}
|
|
if all[0] != "line1" || all[1] != "line2" || all[2] != "line3" {
|
|
t.Errorf("unexpected lines: %v", all)
|
|
}
|
|
}
|
|
|
|
func TestRingBufferOverflow(t *testing.T) {
|
|
buf := NewTerminalBuffer(200)
|
|
|
|
// Write 300 lines
|
|
for i := 0; i < 300; i++ {
|
|
buf.Write([]byte(fmt.Sprintf("line %d\n", i)))
|
|
}
|
|
|
|
all := buf.ReadAll()
|
|
if len(all) != 200 {
|
|
t.Fatalf("expected 200 lines (ring buffer), got %d", len(all))
|
|
}
|
|
|
|
// First line should be "line 100" (oldest retained)
|
|
if all[0] != "line 100" {
|
|
t.Errorf("expected first line 'line 100', got %q", all[0])
|
|
}
|
|
|
|
// Last line should be "line 299"
|
|
if all[199] != "line 299" {
|
|
t.Errorf("expected last line 'line 299', got %q", all[199])
|
|
}
|
|
}
|
|
|
|
func TestReadLastSubset(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
|
|
buf.Write([]byte("a\nb\nc\nd\ne\n"))
|
|
|
|
last3 := buf.ReadLast(3)
|
|
if len(last3) != 3 {
|
|
t.Fatalf("expected 3 lines, got %d", len(last3))
|
|
}
|
|
if last3[0] != "c" || last3[1] != "d" || last3[2] != "e" {
|
|
t.Errorf("unexpected lines: %v", last3)
|
|
}
|
|
|
|
// Request more than available
|
|
last10 := buf.ReadLast(10)
|
|
if len(last10) != 5 {
|
|
t.Fatalf("expected 5 lines (all available), got %d", len(last10))
|
|
}
|
|
}
|
|
|
|
func TestConcurrentAccess(t *testing.T) {
|
|
buf := NewTerminalBuffer(1000)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Spawn 10 writers
|
|
for w := 0; w < 10; w++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
buf.Write([]byte(fmt.Sprintf("writer %d line %d\n", id, i)))
|
|
}
|
|
}(w)
|
|
}
|
|
|
|
// Spawn 5 readers
|
|
for r := 0; r < 5; r++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for i := 0; i < 100; i++ {
|
|
_ = buf.ReadLast(10)
|
|
_ = buf.Len()
|
|
}
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
total := buf.Len()
|
|
if total != 1000 {
|
|
t.Errorf("expected 1000 lines (10 writers * 100), got %d", total)
|
|
}
|
|
}
|
|
|
|
func TestWritePartialLines(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
|
|
// Write data without trailing newline
|
|
buf.Write([]byte("partial"))
|
|
|
|
// Should have no complete lines yet
|
|
if buf.Len() != 0 {
|
|
t.Errorf("expected 0 lines for partial write, got %d", buf.Len())
|
|
}
|
|
|
|
// Complete the line
|
|
buf.Write([]byte(" line\n"))
|
|
|
|
if buf.Len() != 1 {
|
|
t.Fatalf("expected 1 line after completing partial, got %d", buf.Len())
|
|
}
|
|
|
|
all := buf.ReadAll()
|
|
if all[0] != "partial line" {
|
|
t.Errorf("expected 'partial line', got %q", all[0])
|
|
}
|
|
}
|
|
|
|
func TestWriteMultiplePartials(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
|
|
buf.Write([]byte("hello "))
|
|
buf.Write([]byte("world"))
|
|
buf.Write([]byte("!\nfoo\n"))
|
|
|
|
all := buf.ReadAll()
|
|
if len(all) != 2 {
|
|
t.Fatalf("expected 2 lines, got %d: %v", len(all), all)
|
|
}
|
|
if all[0] != "hello world!" {
|
|
t.Errorf("expected 'hello world!', got %q", all[0])
|
|
}
|
|
if all[1] != "foo" {
|
|
t.Errorf("expected 'foo', got %q", all[1])
|
|
}
|
|
}
|
|
|
|
func TestClear(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
|
|
buf.Write([]byte("line1\nline2\n"))
|
|
buf.Clear()
|
|
|
|
if buf.Len() != 0 {
|
|
t.Errorf("expected 0 lines after clear, got %d", buf.Len())
|
|
}
|
|
}
|
|
|
|
func TestReadLastZero(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
buf.Write([]byte("line\n"))
|
|
|
|
result := buf.ReadLast(0)
|
|
if len(result) != 0 {
|
|
t.Errorf("expected empty result for ReadLast(0), got %d lines", len(result))
|
|
}
|
|
}
|
|
|
|
func TestReadLastNegative(t *testing.T) {
|
|
buf := NewTerminalBuffer(100)
|
|
buf.Write([]byte("line\n"))
|
|
|
|
result := buf.ReadLast(-1)
|
|
if len(result) != 0 {
|
|
t.Errorf("expected empty result for ReadLast(-1), got %d lines", len(result))
|
|
}
|
|
}
|