test: notification handler + gotify client unit tests
- 24 tests covering all X-Resource routes - Mock Gotify server for message/application CRUD - Error cases: nil gotify, invalid JSON, missing fields, 429, 500 - Fix readError() to handle io.ReadAll failure - GotifyClient direct tests for all 7 methods
This commit is contained in:
@@ -252,6 +252,9 @@ func (c *GotifyClient) DeleteApplication(id int) error {
|
|||||||
// --- Helpers ---
|
// --- Helpers ---
|
||||||
|
|
||||||
func (c *GotifyClient) readError(resp *http.Response) error {
|
func (c *GotifyClient) readError(resp *http.Response) error {
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("gotify API error (HTTP %d): failed to read body: %w", resp.StatusCode, err)
|
||||||
|
}
|
||||||
return fmt.Errorf("gotify API error (HTTP %d): %s", resp.StatusCode, string(body))
|
return fmt.Errorf("gotify API error (HTTP %d): %s", resp.StatusCode, string(body))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,513 @@
|
|||||||
|
package notification
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockGotifyServer creates a test server that simulates the Gotify API.
|
||||||
|
func mockGotifyServer() *httptest.Server {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
|
||||||
|
// POST /message — send message
|
||||||
|
mux.HandleFunc("/message", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodPost:
|
||||||
|
var msg GotifyMessage
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&msg); err != nil {
|
||||||
|
http.Error(w, "bad request", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
msg.ID = 42
|
||||||
|
msg.AppID = 1
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(msg)
|
||||||
|
|
||||||
|
case http.MethodGet:
|
||||||
|
// list messages
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(GotifyMessageList{
|
||||||
|
Messages: []GotifyMessage{
|
||||||
|
{ID: 1, Title: "Test", Message: "hello", Priority: 3},
|
||||||
|
{ID: 2, Title: "Alert", Message: "world", Priority: 7},
|
||||||
|
},
|
||||||
|
Paging: GotifyPaging{Size: 2, Limit: 50},
|
||||||
|
})
|
||||||
|
|
||||||
|
case http.MethodDelete:
|
||||||
|
// delete all messages
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
||||||
|
|
||||||
|
default:
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// DELETE /message/{id}
|
||||||
|
mux.HandleFunc("/message/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodDelete {
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
||||||
|
})
|
||||||
|
|
||||||
|
// GET/POST/DELETE /application
|
||||||
|
mux.HandleFunc("/application", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodGet:
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode([]GotifyApplication{
|
||||||
|
{ID: 1, Name: "app1", Token: "tok1"},
|
||||||
|
{ID: 2, Name: "app2", Token: "tok2"},
|
||||||
|
})
|
||||||
|
|
||||||
|
case http.MethodPost:
|
||||||
|
var app GotifyApplication
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&app); err != nil {
|
||||||
|
http.Error(w, "bad request", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.ID = 10
|
||||||
|
app.Token = "new-token"
|
||||||
|
w.WriteHeader(http.StatusCreated)
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
json.NewEncoder(w).Encode(app)
|
||||||
|
|
||||||
|
default:
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// DELETE /application/{id}
|
||||||
|
mux.HandleFunc("/application/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodDelete {
|
||||||
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
|
||||||
|
})
|
||||||
|
|
||||||
|
return httptest.NewServer(mux)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestHandler(gotifyURL string) *Handler {
|
||||||
|
h := &Handler{}
|
||||||
|
if gotifyURL != "" {
|
||||||
|
h.gotify = NewGotifyClient(gotifyURL, "test-app-token", "test-client-token")
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func doRequest(h *Handler, method, resource string, body interface{}) *httptest.ResponseRecorder {
|
||||||
|
var reqBody io.Reader
|
||||||
|
if body != nil {
|
||||||
|
b, _ := json.Marshal(body)
|
||||||
|
reqBody = bytes.NewReader(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest(method, "/", reqBody)
|
||||||
|
req.Header.Set("X-Resource", resource)
|
||||||
|
if body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(w, req)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeResponse(t *testing.T, w *httptest.ResponseRecorder) map[string]interface{} {
|
||||||
|
t.Helper()
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil {
|
||||||
|
t.Fatalf("decode response: %v (body: %s)", err, w.Body.String())
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Handler routing tests
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func TestHandler_UnknownResource(t *testing.T) {
|
||||||
|
h := newTestHandler("")
|
||||||
|
w := doRequest(h, "GET", "unknown-resource", nil)
|
||||||
|
if w.Code != http.StatusNotFound {
|
||||||
|
t.Errorf("expected 404, got %d", w.Code)
|
||||||
|
}
|
||||||
|
data := decodeResponse(t, w)
|
||||||
|
if _, ok := data["error"]; !ok {
|
||||||
|
t.Error("expected error in response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_GotifyNotConfigured(t *testing.T) {
|
||||||
|
h := newTestHandler("") // no gotify
|
||||||
|
|
||||||
|
resources := []struct {
|
||||||
|
method string
|
||||||
|
resource string
|
||||||
|
body interface{}
|
||||||
|
}{
|
||||||
|
{"POST", "send-message", map[string]string{"title": "t", "message": "m"}},
|
||||||
|
{"GET", "list-messages", nil},
|
||||||
|
{"DELETE", "delete-message", map[string]int{"id": 1}},
|
||||||
|
{"DELETE", "delete-all-messages", nil},
|
||||||
|
{"GET", "list-applications", nil},
|
||||||
|
{"POST", "create-application", map[string]string{"name": "app"}},
|
||||||
|
{"DELETE", "delete-application", map[string]int{"id": 1}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range resources {
|
||||||
|
t.Run(tc.resource, func(t *testing.T) {
|
||||||
|
w := doRequest(h, tc.method, tc.resource, tc.body)
|
||||||
|
if w.Code != http.StatusServiceUnavailable {
|
||||||
|
t.Errorf("expected 503, got %d", w.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Gotify message tests (via handler)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func TestHandler_SendMessage(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "POST", "send-message", map[string]interface{}{
|
||||||
|
"title": "Test Alert",
|
||||||
|
"message": "Something happened",
|
||||||
|
"priority": 5,
|
||||||
|
})
|
||||||
|
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
data := decodeResponse(t, w)
|
||||||
|
if data["title"] != "Test Alert" {
|
||||||
|
t.Errorf("expected title 'Test Alert', got %v", data["title"])
|
||||||
|
}
|
||||||
|
if int(data["id"].(float64)) != 42 {
|
||||||
|
t.Errorf("expected id 42, got %v", data["id"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_SendMessage_InvalidJSON(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
req := httptest.NewRequest("POST", "/", bytes.NewReader([]byte("not json")))
|
||||||
|
req.Header.Set("X-Resource", "send-message")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected 400, got %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_ListMessages(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "GET", "list-messages", nil)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var result GotifyMessageList
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil {
|
||||||
|
t.Fatalf("decode: %v", err)
|
||||||
|
}
|
||||||
|
if len(result.Messages) != 2 {
|
||||||
|
t.Errorf("expected 2 messages, got %d", len(result.Messages))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_DeleteMessage(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "DELETE", "delete-message", map[string]int{"id": 1})
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_DeleteMessage_MissingID(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "DELETE", "delete-message", map[string]int{"id": 0})
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected 400, got %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_DeleteAllMessages(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "DELETE", "delete-all-messages", nil)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Gotify application tests (via handler)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func TestHandler_ListApplications(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "GET", "list-applications", nil)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
var apps []GotifyApplication
|
||||||
|
if err := json.Unmarshal(w.Body.Bytes(), &apps); err != nil {
|
||||||
|
t.Fatalf("decode: %v", err)
|
||||||
|
}
|
||||||
|
if len(apps) != 2 {
|
||||||
|
t.Errorf("expected 2 apps, got %d", len(apps))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_CreateApplication(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "POST", "create-application", map[string]string{
|
||||||
|
"name": "my-app",
|
||||||
|
"description": "test app",
|
||||||
|
})
|
||||||
|
if w.Code != http.StatusCreated {
|
||||||
|
t.Fatalf("expected 201, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
data := decodeResponse(t, w)
|
||||||
|
if data["name"] != "my-app" {
|
||||||
|
t.Errorf("expected name 'my-app', got %v", data["name"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_DeleteApplication(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "DELETE", "delete-application", map[string]int{"id": 1})
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected 200, got %d: %s", w.Code, w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_DeleteApplication_MissingID(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
h := newTestHandler(srv.URL)
|
||||||
|
|
||||||
|
w := doRequest(h, "DELETE", "delete-application", map[string]int{"id": 0})
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected 400, got %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// Email tests (routing only, no SMTP)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func TestHandler_SendEmail_MissingTo(t *testing.T) {
|
||||||
|
h := newTestHandler("")
|
||||||
|
|
||||||
|
w := doRequest(h, "POST", "send-email", map[string]string{
|
||||||
|
"subject": "Test",
|
||||||
|
"body": "Hello",
|
||||||
|
})
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected 400, got %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHandler_SendEmail_InvalidJSON(t *testing.T) {
|
||||||
|
h := newTestHandler("")
|
||||||
|
|
||||||
|
req := httptest.NewRequest("POST", "/", bytes.NewReader([]byte("{bad")))
|
||||||
|
req.Header.Set("X-Resource", "send-email")
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
h.ServeHTTP(w, req)
|
||||||
|
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected 400, got %d", w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// GotifyClient direct tests
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
func TestGotifyClient_SendMessage(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
msg, err := client.SendMessage(GotifyMessage{
|
||||||
|
Title: "Direct Test",
|
||||||
|
Message: "Hello",
|
||||||
|
Priority: 3,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("send: %v", err)
|
||||||
|
}
|
||||||
|
if msg.ID != 42 {
|
||||||
|
t.Errorf("expected id 42, got %d", msg.ID)
|
||||||
|
}
|
||||||
|
if msg.Title != "Direct Test" {
|
||||||
|
t.Errorf("expected title 'Direct Test', got %s", msg.Title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_ListMessages(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
list, err := client.ListMessages(50)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("list: %v", err)
|
||||||
|
}
|
||||||
|
if len(list.Messages) != 2 {
|
||||||
|
t.Errorf("expected 2 messages, got %d", len(list.Messages))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_DeleteMessage(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
if err := client.DeleteMessage(1); err != nil {
|
||||||
|
t.Fatalf("delete: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_DeleteAllMessages(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
if err := client.DeleteAllMessages(); err != nil {
|
||||||
|
t.Fatalf("delete all: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_ListApplications(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
apps, err := client.ListApplications()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("list: %v", err)
|
||||||
|
}
|
||||||
|
if len(apps) != 2 {
|
||||||
|
t.Errorf("expected 2 apps, got %d", len(apps))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_CreateApplication(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
app, err := client.CreateApplication(GotifyApplication{
|
||||||
|
Name: "new-app",
|
||||||
|
Description: "test",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("create: %v", err)
|
||||||
|
}
|
||||||
|
if app.ID != 10 {
|
||||||
|
t.Errorf("expected id 10, got %d", app.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_DeleteApplication(t *testing.T) {
|
||||||
|
srv := mockGotifyServer()
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
if err := client.DeleteApplication(1); err != nil {
|
||||||
|
t.Fatalf("delete: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_ErrorResponse(t *testing.T) {
|
||||||
|
// Server that returns 500 for everything
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
fmt.Fprint(w, "internal error")
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
_, err := client.SendMessage(GotifyMessage{Title: "test"})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.ListMessages(10)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.ListApplications()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_RateLimited(t *testing.T) {
|
||||||
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusTooManyRequests)
|
||||||
|
fmt.Fprint(w, "rate limited")
|
||||||
|
}))
|
||||||
|
defer srv.Close()
|
||||||
|
client := NewGotifyClient(srv.URL, "app-token", "client-token")
|
||||||
|
|
||||||
|
_, err := client.SendMessage(GotifyMessage{Title: "test"})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error on 429")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGotifyClient_InvalidURL(t *testing.T) {
|
||||||
|
client := NewGotifyClient("http://localhost:1", "app-token", "client-token")
|
||||||
|
|
||||||
|
_, err := client.SendMessage(GotifyMessage{Title: "test"})
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected connection error")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user