Files
lazyntfy/internal/ntfy/client_test.go
T
ahp cd19d4c665 feat(ntfy): add the HTTP client, stream manager, and account discovery
Speak the ntfy JSON API directly: subscribe, publish, group topics that share a server and credentials, reconnect with backoff and a since cursor, and list account subscriptions, reservations, and ACL grants.
2026-10-11 12:04:53 +03:30

103 lines
2.6 KiB
Go

package ntfy
import (
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"lazyntfy/internal/config"
)
func TestOpenStreamAndPublish(t *testing.T) {
var published string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Authorization") != "Bearer tk_test" {
t.Errorf("auth header missing")
}
switch r.Method {
case http.MethodGet:
if !strings.Contains(r.URL.Path, "/alerts/json") {
t.Errorf("path %s", r.URL.Path)
}
w.Header().Set("X-Messages-Truncated", "1")
_, _ = io.WriteString(w, "{\"id\":\"m1\",\"time\":10,\"event\":\"message\",\"topic\":\"alerts\",\"message\":\"hi\"}\n")
case http.MethodPost:
if r.URL.Path != "/alerts" {
t.Errorf("post path %s", r.URL.Path)
}
if r.Header.Get("Title") != "Disk" || r.Header.Get("Priority") != "high" || r.Header.Get("Tags") != "a,b" {
t.Errorf("headers %v", r.Header)
}
b, _ := io.ReadAll(r.Body)
published = string(b)
w.WriteHeader(http.StatusOK)
default:
t.Errorf("method %s", r.Method)
}
}))
defer srv.Close()
c := NewClient()
auth := config.Auth{Token: "tk_test"}
resp, meta, err := c.OpenStream(context.Background(), srv.URL+"/alerts/json?since=all", auth)
if err != nil {
t.Fatal(err)
}
defer resp.Body.Close()
if !meta.Truncated {
t.Fatal("expected truncation header")
}
var n int
if err := ReadLines(resp.Body, func(ev Event) error {
n++
if ev.Message != "hi" {
t.Fatalf("%+v", ev)
}
return nil
}, nil); err != nil {
t.Fatal(err)
}
if n != 1 {
t.Fatalf("events %d", n)
}
err = c.Publish(context.Background(), srv.URL, "alerts", auth, PublishRequest{
Title: "Disk", Message: "full", Priority: 4, Tags: []string{"a", "b"},
})
if err != nil {
t.Fatal(err)
}
if published != "full" {
t.Fatalf("body %q", published)
}
}
func TestUnauthorizedHidesBody(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = io.WriteString(w, "token tk_supersecret rejected")
}))
defer srv.Close()
_, _, err := NewClient().OpenStream(context.Background(), srv.URL+"/alerts/json", config.Auth{Token: "tk_test"})
if err == nil || strings.Contains(err.Error(), "tk_supersecret") || !strings.Contains(err.Error(), "not authorized") {
t.Fatalf("%v", err)
}
}
func TestParsePriority(t *testing.T) {
p, err := ParsePriority("high")
if err != nil || p != 4 {
t.Fatal(p, err)
}
if _, err := ParsePriority("nope"); err == nil {
t.Fatal("expected error")
}
tags := ParseTags(" a, b ,,c ")
if strings.Join(tags, "|") != "a|b|c" {
t.Fatal(tags)
}
}