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.
103 lines
2.6 KiB
Go
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)
|
|
}
|
|
}
|