goutils/http/httpErr_test.go
2025-04-24 15:59:15 +02:00

235 lines
7.4 KiB
Go

package webutils_test
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
webutils "git.mstar.dev/mstar/goutils/http"
"git.mstar.dev/mstar/goutils/maputils"
"git.mstar.dev/mstar/goutils/other"
"git.mstar.dev/mstar/goutils/sliceutils"
)
func TestHttpErr(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.HttpErr(recorder, 1, "some error", 500)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
res := recorder.Result()
if res.StatusCode != 500 {
t.Fatalf("Expected status code 500, got %v", res.StatusCode)
}
body := string(other.Must(io.ReadAll(res.Body)))
expected := `{"id": 1, "message": "some error"}`
if body != expected {
t.Fatalf("Expected body %q, got %q", expected, body)
}
}
func TestProblemDetailsStatusOnly(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.ProblemDetailsStatusOnly(recorder, 500)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
res := recorder.Result()
if ct := res.Header.Get("Content-Type"); ct != "application/problem+json" {
t.Fatalf("Expected content type to be \"application/problem+json\" got %v", ct)
}
body := string(other.Must(io.ReadAll(res.Body)))
data := map[string]any{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
t.Fatalf("response body is not json: %v", err)
}
if dt, ok := data["type"].(string); !ok || dt != "about:blank" {
t.Fatalf(`Expected key "type" as "about:blank", got %v`, dt)
}
if dt, ok := data["title"].(string); !ok || dt != http.StatusText(500) {
t.Fatalf(`Expected key "title" as "%v", got %v`, http.StatusText(500), dt)
}
if dt, ok := data["status"].(float64); !ok || dt != 500 {
t.Fatalf(`Expected key "status" as 500, got %v`, dt)
}
if dt, ok := data["reference"].(string); !ok || dt != "RFC 9457" {
t.Fatalf(`Expected key "reference" as "RFC 9457", got %v`, dt)
}
}
func TestProblemDetailsNoDetailsOrExtras(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.ProblemDetails(
recorder,
500,
"error-type",
"error-title",
nil,
nil,
)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
res := recorder.Result()
if ct := res.Header.Get("Content-Type"); ct != "application/problem+json" {
t.Fatalf("Expected content type to be \"application/problem+json\" got %v", ct)
}
body := string(other.Must(io.ReadAll(res.Body)))
data := map[string]any{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
t.Fatalf("response body is not json: %v", err)
}
expectedFields := []string{"type", "title", "status"}
gotFields := maputils.KeysFromMap(data)
if !sliceutils.CompareUnordered(gotFields, expectedFields) {
t.Fatalf("Expected fields %v, got %v", expectedFields, gotFields)
}
if dt, ok := data["type"].(string); !ok || dt != "error-type" {
t.Fatalf(`Expected key "type" as "error-type", got %v`, dt)
}
if dt, ok := data["title"].(string); !ok || dt != "error-title" {
t.Fatalf(`Expected key "title" as "error-title", got %v`, dt)
}
if dt, ok := data["status"].(float64); !ok || dt != 500 {
t.Fatalf(`Expected key "status" as 500, got %v`, dt)
}
}
func TestProblemDetailsNoDetailsWithExtras(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.ProblemDetails(
recorder,
500,
"error-type",
"error-title",
nil,
map[string]any{"foo": "bar"},
)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
res := recorder.Result()
if ct := res.Header.Get("Content-Type"); ct != "application/problem+json" {
t.Fatalf("Expected content type to be \"application/problem+json\" got %v", ct)
}
body := string(other.Must(io.ReadAll(res.Body)))
data := map[string]any{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
t.Fatalf("response body is not json: %v", err)
}
expectedFields := []string{"type", "title", "status", "foo"}
gotFields := maputils.KeysFromMap(data)
if !sliceutils.CompareUnordered(gotFields, expectedFields) {
t.Fatalf("Expected fields %v, got %v", expectedFields, gotFields)
}
if dt, ok := data["type"].(string); !ok || dt != "error-type" {
t.Fatalf(`Expected key "type" as "error-type", got %v`, dt)
}
if dt, ok := data["title"].(string); !ok || dt != "error-title" {
t.Fatalf(`Expected key "title" as "error-title", got %v`, dt)
}
if dt, ok := data["status"].(float64); !ok || dt != 500 {
t.Fatalf(`Expected key "status" as 500, got %v`, dt)
}
if dt, ok := data["foo"].(string); !ok || dt != "bar" {
t.Fatalf(`Expected key "foo" as "bar", got %v`, dt)
}
}
func TestProblemDetailsWithDetailsNoExtras(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.ProblemDetails(
recorder,
500,
"error-type",
"error-title",
other.IntoPointer("error-details"),
nil,
)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
res := recorder.Result()
if ct := res.Header.Get("Content-Type"); ct != "application/problem+json" {
t.Fatalf("Expected content type to be \"application/problem+json\" got %v", ct)
}
body := string(other.Must(io.ReadAll(res.Body)))
data := map[string]any{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
t.Fatalf("response body is not json: %v", err)
}
expectedFields := []string{"type", "title", "status", "detail"}
gotFields := maputils.KeysFromMap(data)
if !sliceutils.CompareUnordered(gotFields, expectedFields) {
t.Fatalf("Expected fields %v, got %v", expectedFields, gotFields)
}
if dt, ok := data["type"].(string); !ok || dt != "error-type" {
t.Fatalf(`Expected key "type" as "error-type", got %v`, dt)
}
if dt, ok := data["title"].(string); !ok || dt != "error-title" {
t.Fatalf(`Expected key "title" as "error-title", got %v`, dt)
}
if dt, ok := data["status"].(float64); !ok || dt != 500 {
t.Fatalf(`Expected key "status" as 500, got %v`, dt)
}
if dt, ok := data["detail"].(string); !ok || dt != "error-details" {
t.Fatalf(`Expected key "detail" as "error-details", got %v`, dt)
}
}
func TestProblemDetailsWithDetailsWithExtras(t *testing.T) {
recorder := httptest.NewRecorder()
err := webutils.ProblemDetails(
recorder,
500,
"error-type",
"error-title",
other.IntoPointer("error-details"),
map[string]any{"foo": "bar", "type": "should not be set in the end"},
)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
res := recorder.Result()
if ct := res.Header.Get("Content-Type"); ct != "application/problem+json" {
t.Fatalf("Expected content type to be \"application/problem+json\" got %v", ct)
}
body := string(other.Must(io.ReadAll(res.Body)))
data := map[string]any{}
err = json.Unmarshal([]byte(body), &data)
if err != nil {
t.Fatalf("response body is not json: %v", err)
}
expectedFields := []string{"type", "title", "status", "detail", "foo"}
gotFields := maputils.KeysFromMap(data)
if !sliceutils.CompareUnordered(gotFields, expectedFields) {
t.Fatalf("Expected fields %v, got %v", expectedFields, gotFields)
}
if dt, ok := data["type"].(string); !ok || dt != "error-type" {
t.Fatalf(`Expected key "type" as "error-type", got %v`, dt)
}
if dt, ok := data["title"].(string); !ok || dt != "error-title" {
t.Fatalf(`Expected key "title" as "error-title", got %v`, dt)
}
if dt, ok := data["status"].(float64); !ok || dt != 500 {
t.Fatalf(`Expected key "status" as 500, got %v`, dt)
}
if dt, ok := data["detail"].(string); !ok || dt != "error-details" {
t.Fatalf(`Expected key "detail" as "error-details", got %v`, dt)
}
if dt, ok := data["foo"].(string); !ok || dt != "bar" {
t.Fatalf(`Expected key "foo" as "bar", got %v`, dt)
}
}