package nats import ( "testing" "time" ) func TestInProcessConnSubscribeAndPublish(t *testing.T) { conn := NewInProcess() sub, err := conn.Subscribe("cyrene.test.echo") if err != nil { t.Fatalf("Subscribe error: %v", err) } err = conn.Publish("cyrene.test.echo", []byte("hello")) if err != nil { t.Fatalf("Publish error: %v", err) } select { case msg := <-sub.MsgCh: if msg.Subject != "cyrene.test.echo" { t.Errorf("expected subject cyrene.test.echo, got %s", msg.Subject) } if string(msg.Data) != "hello" { t.Errorf("expected data 'hello', got %s", string(msg.Data)) } case <-time.After(time.Second): t.Fatal("timeout waiting for message") } } func TestInProcessConnRequestReply(t *testing.T) { conn := NewInProcess() // Set up a responder sub, err := conn.Subscribe("cyrene.test.add") if err != nil { t.Fatalf("Subscribe error: %v", err) } // Responder goroutine go func() { msg := <-sub.MsgCh if msg.Reply != "" { conn.Publish(msg.Reply, []byte("42")) } }() // Give responder a moment to start time.Sleep(10 * time.Millisecond) reply, err := conn.Request("cyrene.test.add", []byte("40+2"), 2*time.Second) if err != nil { t.Fatalf("Request error: %v", err) } if string(reply.Data) != "42" { t.Errorf("expected reply '42', got %s", string(reply.Data)) } } func TestInProcessConnMultipleSubscribers(t *testing.T) { conn := NewInProcess() sub1, _ := conn.Subscribe("cyrene.test.multi") sub2, _ := conn.Subscribe("cyrene.test.multi") conn.Publish("cyrene.test.multi", []byte("broadcast")) // Both subscribers should receive select { case <-sub1.MsgCh: case <-time.After(time.Second): t.Fatal("subscriber 1 did not receive message") } select { case <-sub2.MsgCh: case <-time.After(time.Second): t.Fatal("subscriber 2 did not receive message") } } func TestInProcessConnClose(t *testing.T) { conn := NewInProcess() err := conn.Close() if err != nil { t.Fatalf("Close error: %v", err) } if !conn.IsConnected() { // IsConnected returns true in our stub } } func TestSubjectConstants(t *testing.T) { // Verify subject naming follows the cyrene.{service}.{action} convention subjects := []string{ SubjMemorySearch, SubjMemoryInsert, SubjMemoryDelete, SubjMemoryExtract, SubjVoiceSTT, SubjVoiceTTS, SubjIoTDeviceList, SubjIoTDeviceToggle, SubjIoTStateChanged, SubjBridgeIncoming, SubjBridgeOutgoing, SubjThinkerThoughtReady, SubjRAGSearch, } for _, subj := range subjects { if len(subj) == 0 { t.Error("subject should not be empty") } if subj[:len(SubjectPrefix)] != SubjectPrefix { t.Errorf("subject %s should start with %s", subj, SubjectPrefix) } } } func TestSubscriptionUnsubscribe(t *testing.T) { conn := NewInProcess() sub, _ := conn.Subscribe("cyrene.test.temp") err := sub.Unsubscribe() if err != nil { t.Errorf("Unsubscribe error: %v", err) } } func TestConnectionInterface(t *testing.T) { // Verify InProcessConn satisfies Connection interface var conn Connection = NewInProcess() _ = conn }