check / check (push) Successful in 3m20s
Each row of the recent events on the webhook page links to the
event's own page, /hook/{id}/events/{eventID}, and expands to show its
body; only the newest starts expanded. The event's page shows its
details, its whole body and every delivery with its attempts.
One renderer, newBodyView with templates/event_body.html, shows a body
in all three places: whole up to 32 KiB, cut there in the lists with a
link to the event's page, JSON pretty-printed, a body of more than 200
lines or 32 KiB in a scrolling box, and a body that is not text left
out beside its download link. A resubmitted copy links to its
original's page.
Model: opus-5-5
177 lines
4.8 KiB
Go
177 lines
4.8 KiB
Go
package handlers_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"sneak.berlin/go/webhooker/internal/handlers"
|
|
)
|
|
|
|
// bodyView is how the pages would show body, stored whole.
|
|
func bodyView(body string) handlers.BodyView {
|
|
return handlers.NewBodyViewForTest([]byte(body), int64(len(body)))
|
|
}
|
|
|
|
// lines is n lines of text, without a newline after the last.
|
|
func lines(n int) string {
|
|
return strings.TrimSuffix(strings.Repeat("line\n", n), "\n")
|
|
}
|
|
|
|
// TestNewBodyView_FormatsValidJSON proves a JSON body is shown
|
|
// pretty-printed, whatever its content type, with its keys in
|
|
// the order they arrived.
|
|
func TestNewBodyView_FormatsValidJSON(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
v := bodyView(`{"b":1,"a":[true,null,"x"],"c":{}}`)
|
|
|
|
assert.Equal(t, []string{
|
|
`{`,
|
|
` "b": 1,`,
|
|
` "a": [`,
|
|
` true,`,
|
|
` null,`,
|
|
` "x"`,
|
|
` ],`,
|
|
` "c": {}`,
|
|
`}`,
|
|
}, strings.Split(v.Text, "\n"))
|
|
assert.False(t, v.Scroll)
|
|
}
|
|
|
|
// TestNewBodyView_FormatsNestedJSON proves a small document with a
|
|
// few levels of nesting is pretty-printed.
|
|
func TestNewBodyView_FormatsNestedJSON(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
v := bodyView(`{"data":[[1,2,3],[4,5,6]]}`)
|
|
|
|
assert.Equal(t, []string{
|
|
`{`,
|
|
` "data": [`,
|
|
` [`,
|
|
` 1,`,
|
|
` 2,`,
|
|
` 3`,
|
|
` ],`,
|
|
` [`,
|
|
` 4,`,
|
|
` 5,`,
|
|
` 6`,
|
|
` ]`,
|
|
` ]`,
|
|
`}`,
|
|
}, strings.Split(v.Text, "\n"))
|
|
}
|
|
|
|
// TestNewBodyView_InvalidJSONAsReceived proves a body that is not
|
|
// a JSON document is shown exactly as it arrived.
|
|
func TestNewBodyView_InvalidJSONAsReceived(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, body := range []string{
|
|
`{"a":1,`,
|
|
`{"a":1} {"b":2}`,
|
|
"plain text\n indented",
|
|
} {
|
|
assert.Equal(t, body, bodyView(body).Text)
|
|
}
|
|
}
|
|
|
|
// TestNewBodyView_DeepJSONAsReceived proves a JSON body nested
|
|
// more than 16 levels deep is shown as it arrived. 10 KB of nested
|
|
// arrays would indent to some 50 MB.
|
|
func TestNewBodyView_DeepJSONAsReceived(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
nested := func(depth int) string {
|
|
return strings.Repeat("[", depth) + "1" + strings.Repeat("]", depth)
|
|
}
|
|
|
|
assert.NotEqual(t, nested(16), bodyView(nested(16)).Text)
|
|
assert.Equal(t, nested(17), bodyView(nested(17)).Text)
|
|
|
|
body := strings.Repeat("[", 5000) + strings.Repeat("]", 5000)
|
|
|
|
assert.Equal(t, body, bodyView(body).Text)
|
|
}
|
|
|
|
// TestNewBodyView_GrowingJSONAsReceived proves a JSON body that
|
|
// pretty-printing would make more than four times its size is shown
|
|
// as it arrived, however shallow: each short element eight levels
|
|
// deep gets a line indented sixteen spaces.
|
|
func TestNewBodyView_GrowingJSONAsReceived(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
numbers := func(n int) string {
|
|
return strings.Repeat("[", 8) +
|
|
strings.TrimSuffix(strings.Repeat("1,", n), ",") +
|
|
strings.Repeat("]", 8)
|
|
}
|
|
|
|
assert.NotEqual(t, numbers(10), bodyView(numbers(10)).Text)
|
|
assert.Equal(t, numbers(1000), bodyView(numbers(1000)).Text)
|
|
}
|
|
|
|
// TestNewBodyView_ScrollsPast200Lines proves a body is shown at
|
|
// its full height up to 200 lines and in the scrolling box past
|
|
// them, counting the lines after formatting.
|
|
func TestNewBodyView_ScrollsPast200Lines(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assert.False(t, bodyView(lines(200)).Scroll)
|
|
assert.True(t, bodyView(lines(201)).Scroll)
|
|
|
|
// A final newline ends the last line rather than starting another.
|
|
assert.False(t, bodyView(lines(200)+"\n").Scroll)
|
|
assert.True(t, bodyView(lines(201)+"\n").Scroll)
|
|
|
|
// The page shows a carriage return, a line feed, or the two
|
|
// together as one line break.
|
|
assert.True(t, bodyView(strings.Repeat("line\r", 400)).Scroll)
|
|
assert.False(t, bodyView(strings.Repeat("line\r\n", 200)).Scroll)
|
|
|
|
// One line as received, 201 once formatted: the brackets and
|
|
// 199 elements.
|
|
numbers := "[" + strings.TrimSuffix(strings.Repeat("1,", 199), ",") + "]"
|
|
|
|
assert.NotContains(t, numbers, "\n")
|
|
assert.True(t, bodyView(numbers).Scroll)
|
|
}
|
|
|
|
// TestNewBodyView_LargeBodyScrolls proves a body larger than the
|
|
// cap of the lists of events is shown in the scrolling box
|
|
// however few lines it has, on the event's own page as in the
|
|
// lists.
|
|
func TestNewBodyView_LargeBodyScrolls(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
assert.False(t, bodyView(strings.Repeat("x", bodyCap)).Scroll)
|
|
assert.True(t, bodyView(strings.Repeat("x", bodyCap+1)).Scroll)
|
|
}
|
|
|
|
// TestNewBodyView_BinaryNotShown proves a body that is not text
|
|
// is never shown: one that is not valid UTF-8, or that holds a
|
|
// control character other than tab, line feed and carriage return.
|
|
func TestNewBodyView_BinaryNotShown(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, body := range []string{
|
|
"\xff\xfe\xfd",
|
|
"a\x00b",
|
|
// A small protobuf message: valid UTF-8, but control bytes.
|
|
"\x08\x01\x12\x03abc",
|
|
"\x1b[31mred\x1b[0m",
|
|
"a\x7fb",
|
|
} {
|
|
v := bodyView(body)
|
|
|
|
assert.True(t, v.Binary, "%q", body)
|
|
assert.Empty(t, v.Text)
|
|
}
|
|
|
|
assert.False(t, bodyView("snow "+snowman).Binary)
|
|
assert.False(t, bodyView("a\tb\r\nc\n").Binary)
|
|
}
|