94 lines
3.6 KiB
Go
94 lines
3.6 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"yovision/bell/internal/alert"
|
|
)
|
|
|
|
type fakeRepository struct {
|
|
limit int
|
|
actor string
|
|
}
|
|
|
|
func (*fakeRepository) AlertReady(context.Context) error { return nil }
|
|
func (*fakeRepository) PublishRule(context.Context, alert.RuleSpec) (bool, error) { return true, nil }
|
|
func (*fakeRepository) EvaluateNext(context.Context) (bool, error) { return false, nil }
|
|
func (f *fakeRepository) ListAlerts(_ context.Context, _, _ int64, _ string, limit int, _ string) (alert.Page, error) {
|
|
f.limit = limit
|
|
return alert.Page{Items: []alert.Summary{}}, nil
|
|
}
|
|
func (*fakeRepository) GetAlert(context.Context, int64, int64, string) (alert.Detail, error) {
|
|
return alert.Detail{}, alert.ErrNotFound
|
|
}
|
|
func (f *fakeRepository) Command(_ context.Context, _, _ int64, id, command, key, actor string, _ *string) (int, alert.CommandResponse, error) {
|
|
f.actor = actor
|
|
return 200, alert.CommandResponse{AlertID: id, State: "acknowledged", ActorRef: actor}, nil
|
|
}
|
|
|
|
func testMux(t *testing.T) (*http.ServeMux, *fakeRepository) {
|
|
t.Helper()
|
|
repository := &fakeRepository{}
|
|
handler, err := NewHandler(repository, Config{Token: "12345678901234567890123456789012", TenantID: 1, SiteID: 2, ActorRef: "operator:local"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mux := http.NewServeMux()
|
|
handler.Register(mux)
|
|
return mux, repository
|
|
}
|
|
|
|
func TestPageIsNoStoreAndDoesNotEmbedToken(t *testing.T) {
|
|
mux, _ := testMux(t)
|
|
request := httptest.NewRequest(http.MethodGet, "/bell-console/", nil)
|
|
response := httptest.NewRecorder()
|
|
mux.ServeHTTP(response, request)
|
|
if response.Code != 200 || response.Header().Get("Cache-Control") != "no-store" {
|
|
t.Fatalf("page response: %d %#v", response.Code, response.Header())
|
|
}
|
|
if body := response.Body.String(); body == "" || strings.Contains(body, "12345678901234567890123456789012") {
|
|
t.Fatal("page missing or leaked console token")
|
|
}
|
|
}
|
|
|
|
func TestAPIRequiresBearerAndDefaultsToSixteen(t *testing.T) {
|
|
mux, repository := testMux(t)
|
|
request := httptest.NewRequest(http.MethodGet, "/bell-console/api/v1/alerts", nil)
|
|
response := httptest.NewRecorder()
|
|
mux.ServeHTTP(response, request)
|
|
if response.Code != http.StatusUnauthorized {
|
|
t.Fatalf("unauthorized status %d", response.Code)
|
|
}
|
|
request = httptest.NewRequest(http.MethodGet, "/bell-console/api/v1/alerts", nil)
|
|
request.Header.Set("Authorization", "Bearer 12345678901234567890123456789012")
|
|
response = httptest.NewRecorder()
|
|
mux.ServeHTTP(response, request)
|
|
if response.Code != http.StatusOK || repository.limit != alert.DefaultPageSize {
|
|
t.Fatalf("authorized list: status=%d limit=%d", response.Code, repository.limit)
|
|
}
|
|
}
|
|
|
|
func TestCommandUsesServerActorAndRequiresIdempotencyKey(t *testing.T) {
|
|
mux, repository := testMux(t)
|
|
path := "/bell-console/api/v1/alerts/alt_01J8XQ2K7M3P5R9T0V4W6Y8Z2C:ack"
|
|
request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(`{"note":null}`))
|
|
request.Header.Set("Authorization", "Bearer 12345678901234567890123456789012")
|
|
response := httptest.NewRecorder()
|
|
mux.ServeHTTP(response, request)
|
|
if response.Code != http.StatusBadRequest {
|
|
t.Fatalf("missing idempotency status %d", response.Code)
|
|
}
|
|
request = httptest.NewRequest(http.MethodPost, path, strings.NewReader(`{"note":null}`))
|
|
request.Header.Set("Authorization", "Bearer 12345678901234567890123456789012")
|
|
request.Header.Set("Idempotency-Key", "command-0001")
|
|
response = httptest.NewRecorder()
|
|
mux.ServeHTTP(response, request)
|
|
if response.Code != http.StatusOK || repository.actor != "operator:local" {
|
|
t.Fatalf("command status=%d actor=%q", response.Code, repository.actor)
|
|
}
|
|
}
|