26f897c1ec
release / release-please (push) Failing after 1m49s
docs / build (push) Failing after 6m34s
release / build-and-upload (arm64, linux) (push) Has been cancelled
release / build-and-upload (arm64, windows) (push) Has been cancelled
release / build-darwin (amd64, darwin) (push) Has been cancelled
release / checksums (push) Has been cancelled
release / finalize (push) Has been cancelled
release / build-darwin (arm64, darwin) (push) Has been cancelled
release / build-and-upload (amd64, linux) (push) Has been cancelled
release / build-and-upload (amd64, windows) (push) Has been cancelled
docs / deploy (push) Has been cancelled
162 lines
3.9 KiB
Go
162 lines
3.9 KiB
Go
package ipc_test
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/kunchenguid/no-mistakes/internal/ipc"
|
|
)
|
|
|
|
func TestStreamHandler(t *testing.T) {
|
|
sock := socketPath(t)
|
|
srv := startServer(t, sock)
|
|
|
|
type streamParams struct {
|
|
Count int `json:"count"`
|
|
}
|
|
type streamEvent struct {
|
|
Index int `json:"index"`
|
|
}
|
|
|
|
srv.HandleStream("stream_test", func(_ context.Context, raw json.RawMessage, send func(interface{}) error) error {
|
|
var p streamParams
|
|
if err := json.Unmarshal(raw, &p); err != nil {
|
|
return err
|
|
}
|
|
for i := 0; i < p.Count; i++ {
|
|
if err := send(streamEvent{Index: i}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// Dial and send the subscribe-like request manually.
|
|
conn, err := ipc.Dial(sock)
|
|
if err != nil {
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
// First, verify we get the initial OK response via Call.
|
|
// Actually, Call reads exactly one line as response, so let's use
|
|
// the Subscribe pattern manually with a raw connection.
|
|
conn.Close()
|
|
|
|
// Use raw connection to test streaming.
|
|
rawConn := rawDial(t, sock)
|
|
defer rawConn.Close()
|
|
|
|
encoder := json.NewEncoder(rawConn)
|
|
scanner := bufio.NewScanner(rawConn)
|
|
scanner.Buffer(make([]byte, 0, 1024*1024), 1024*1024)
|
|
|
|
req, _ := ipc.NewRequest("stream_test", streamParams{Count: 3})
|
|
if err := encoder.Encode(req); err != nil {
|
|
t.Fatalf("send request: %v", err)
|
|
}
|
|
|
|
// Read initial response.
|
|
if !scanner.Scan() {
|
|
t.Fatal("no initial response")
|
|
}
|
|
var resp ipc.Response
|
|
if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil {
|
|
t.Fatalf("parse response: %v", err)
|
|
}
|
|
if resp.Error != nil {
|
|
t.Fatalf("initial response error: %v", resp.Error)
|
|
}
|
|
|
|
// Read 3 streamed events.
|
|
for i := 0; i < 3; i++ {
|
|
if !scanner.Scan() {
|
|
t.Fatalf("event %d: no data", i)
|
|
}
|
|
var event streamEvent
|
|
if err := json.Unmarshal(scanner.Bytes(), &event); err != nil {
|
|
t.Fatalf("event %d parse: %v", i, err)
|
|
}
|
|
if event.Index != i {
|
|
t.Errorf("event %d: index=%d, want %d", i, event.Index, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestStreamRequestsLogAtInfo(t *testing.T) {
|
|
sock := socketPath(t)
|
|
srv := startServer(t, sock)
|
|
|
|
type streamEvent struct {
|
|
Index int `json:"index"`
|
|
}
|
|
|
|
srv.HandleStream("stream_test", func(_ context.Context, _ json.RawMessage, send func(interface{}) error) error {
|
|
return send(streamEvent{Index: 0})
|
|
})
|
|
|
|
var logs bytes.Buffer
|
|
logger := slog.New(slog.NewTextHandler(&logs, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
|
prev := slog.Default()
|
|
slog.SetDefault(logger)
|
|
defer slog.SetDefault(prev)
|
|
|
|
rawConn := rawDial(t, sock)
|
|
defer rawConn.Close()
|
|
|
|
encoder := json.NewEncoder(rawConn)
|
|
scanner := bufio.NewScanner(rawConn)
|
|
scanner.Buffer(make([]byte, 0, 1024*1024), 1024*1024)
|
|
|
|
req, _ := ipc.NewRequest("stream_test", nil)
|
|
if err := encoder.Encode(req); err != nil {
|
|
t.Fatalf("send request: %v", err)
|
|
}
|
|
|
|
if !scanner.Scan() {
|
|
t.Fatal("no initial response")
|
|
}
|
|
|
|
if !scanner.Scan() {
|
|
t.Fatal("no stream event")
|
|
}
|
|
|
|
logOutput := logs.String()
|
|
if !strings.Contains(logOutput, "msg=\"ipc stream request\" method=stream_test") {
|
|
t.Fatalf("stream request log missing: %s", logOutput)
|
|
}
|
|
}
|
|
|
|
func TestStreamHandlerAndRegularCoexist(t *testing.T) {
|
|
sock := socketPath(t)
|
|
srv := startServer(t, sock)
|
|
|
|
// Register both a regular and a stream handler.
|
|
srv.Handle("echo", func(_ context.Context, raw json.RawMessage) (interface{}, error) {
|
|
return map[string]string{"echo": "hello"}, nil
|
|
})
|
|
srv.HandleStream("stream_noop", func(_ context.Context, _ json.RawMessage, send func(interface{}) error) error {
|
|
return nil // stream handler that completes immediately
|
|
})
|
|
|
|
// Regular handler should still work.
|
|
c, err := ipc.Dial(sock)
|
|
if err != nil {
|
|
t.Fatalf("dial: %v", err)
|
|
}
|
|
defer c.Close()
|
|
|
|
var result map[string]string
|
|
if err := c.Call("echo", nil, &result); err != nil {
|
|
t.Fatalf("call: %v", err)
|
|
}
|
|
if result["echo"] != "hello" {
|
|
t.Errorf("got echo=%q, want %q", result["echo"], "hello")
|
|
}
|
|
}
|