Adding upstream version 0.8.9.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
3b2c48b5e4
commit
c0c4addb85
285 changed files with 25880 additions and 0 deletions
193
pkg/util/partition_message_test.go
Normal file
193
pkg/util/partition_message_test.go
Normal file
|
@ -0,0 +1,193 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
"github.com/onsi/gomega"
|
||||
|
||||
"github.com/nicholas-fedor/shoutrrr/pkg/types"
|
||||
)
|
||||
|
||||
var _ = ginkgo.Describe("Partition Message", func() {
|
||||
limits := types.MessageLimit{
|
||||
ChunkSize: 2000,
|
||||
TotalChunkSize: 6000,
|
||||
ChunkCount: 10,
|
||||
}
|
||||
ginkgo.When("given a message that exceeds the max length", func() {
|
||||
ginkgo.When("not splitting by lines", func() {
|
||||
ginkgo.It("should return a payload with chunked messages", func() {
|
||||
items, _ := testPartitionMessage(42)
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(1994))
|
||||
gomega.Expect(items[1].Text).To(gomega.HaveLen(1999))
|
||||
gomega.Expect(items[2].Text).To(gomega.HaveLen(205))
|
||||
})
|
||||
ginkgo.It("omit characters above total max", func() {
|
||||
items, _ := testPartitionMessage(62)
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(1994))
|
||||
gomega.Expect(items[1].Text).To(gomega.HaveLen(1999))
|
||||
gomega.Expect(items[2].Text).To(gomega.HaveLen(1999))
|
||||
gomega.Expect(items[3].Text).To(gomega.HaveLen(5))
|
||||
})
|
||||
ginkgo.It("should handle messages with a size modulus of chunksize", func() {
|
||||
items, _ := testPartitionMessage(20)
|
||||
// Last word fits in the chunk size
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(2000))
|
||||
|
||||
items, _ = testPartitionMessage(40)
|
||||
// Now the last word of the first chunk will be concatenated with
|
||||
// the first word of the second chunk, and so it does not fit in the chunk anymore
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(1994))
|
||||
gomega.Expect(items[1].Text).To(gomega.HaveLen(1999))
|
||||
gomega.Expect(items[2].Text).To(gomega.HaveLen(5))
|
||||
})
|
||||
ginkgo.When("the message is empty", func() {
|
||||
ginkgo.It("should return no items", func() {
|
||||
items, _ := testPartitionMessage(0)
|
||||
gomega.Expect(items).To(gomega.BeEmpty())
|
||||
})
|
||||
})
|
||||
ginkgo.When("given an input without whitespace", func() {
|
||||
ginkgo.It("should not crash, regardless of length", func() {
|
||||
unalignedLimits := types.MessageLimit{
|
||||
ChunkSize: 1997,
|
||||
ChunkCount: 11,
|
||||
TotalChunkSize: 5631,
|
||||
}
|
||||
|
||||
testString := ""
|
||||
for inputLen := 1; inputLen < 8000; inputLen++ {
|
||||
// add a rune to the string using a repeatable pattern (single digit hex of position)
|
||||
testString += strconv.FormatInt(int64(inputLen%16), 16)
|
||||
items, omitted := PartitionMessage(testString, unalignedLimits, 7)
|
||||
included := 0
|
||||
for ii, item := range items {
|
||||
expectedSize := unalignedLimits.ChunkSize
|
||||
|
||||
// The last chunk might be smaller than the preceding chunks
|
||||
if ii == len(items)-1 {
|
||||
// the chunk size is the remainder of, the total size,
|
||||
// or the max size, whatever is smallest,
|
||||
// and the previous chunk sizes
|
||||
chunkSize := Min(
|
||||
inputLen,
|
||||
unalignedLimits.TotalChunkSize,
|
||||
) % unalignedLimits.ChunkSize
|
||||
// if the "rest" of the runes needs another chunk
|
||||
if chunkSize > 0 {
|
||||
// expect the chunk to contain the "rest" of the runes
|
||||
expectedSize = chunkSize
|
||||
}
|
||||
// the last chunk should never be empty, so treat it as one of the full ones
|
||||
}
|
||||
|
||||
// verify the data, but only on the last chunk to reduce test time
|
||||
if ii == len(items)-1 {
|
||||
for ri, r := range item.Text {
|
||||
runeOffset := (len(item.Text) - ri) - 1
|
||||
runeVal, err := strconv.ParseInt(string(r), 16, 64)
|
||||
expectedLen := Min(inputLen, unalignedLimits.TotalChunkSize)
|
||||
expectedVal := (expectedLen - runeOffset) % 16
|
||||
|
||||
gomega.Expect(err).ToNot(gomega.HaveOccurred())
|
||||
gomega.Expect(runeVal).To(gomega.Equal(int64(expectedVal)))
|
||||
}
|
||||
}
|
||||
|
||||
included += len(item.Text)
|
||||
gomega.Expect(item.Text).To(gomega.HaveLen(expectedSize))
|
||||
}
|
||||
gomega.Expect(omitted + included).To(gomega.Equal(inputLen))
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
ginkgo.When("splitting by lines", func() {
|
||||
ginkgo.It("should return a payload with chunked messages", func() {
|
||||
batches := testMessageItemsFromLines(18, limits, 2)
|
||||
items := batches[0]
|
||||
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(200))
|
||||
gomega.Expect(items[8].Text).To(gomega.HaveLen(200))
|
||||
})
|
||||
ginkgo.When("the message items exceed the limits", func() {
|
||||
ginkgo.It("should split items into multiple batches", func() {
|
||||
batches := testMessageItemsFromLines(21, limits, 2)
|
||||
|
||||
for b, chunks := range batches {
|
||||
fmt.Fprintf(ginkgo.GinkgoWriter, "Batch #%v: (%v chunks)\n", b, len(chunks))
|
||||
for c, chunk := range chunks {
|
||||
fmt.Fprintf(
|
||||
ginkgo.GinkgoWriter,
|
||||
" - Chunk #%v: (%v runes)\n",
|
||||
c,
|
||||
len(chunk.Text),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
gomega.Expect(batches).To(gomega.HaveLen(2))
|
||||
})
|
||||
})
|
||||
ginkgo.It("should trim characters above chunk size", func() {
|
||||
hundreds := 42
|
||||
repeat := 21
|
||||
batches := testMessageItemsFromLines(hundreds, limits, repeat)
|
||||
items := batches[0]
|
||||
|
||||
gomega.Expect(items[0].Text).To(gomega.HaveLen(limits.ChunkSize))
|
||||
gomega.Expect(items[1].Text).To(gomega.HaveLen(limits.ChunkSize))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
const hundredChars = "this string is exactly (to the letter) a hundred characters long which will make the send func error"
|
||||
|
||||
// testMessageItemsFromLines generates message item batches from repeated text with line breaks.
|
||||
func testMessageItemsFromLines(
|
||||
hundreds int,
|
||||
limits types.MessageLimit,
|
||||
repeat int,
|
||||
) [][]types.MessageItem {
|
||||
builder := strings.Builder{}
|
||||
ri := 0
|
||||
|
||||
for range hundreds {
|
||||
builder.WriteString(hundredChars)
|
||||
|
||||
ri++
|
||||
if ri == repeat {
|
||||
builder.WriteRune('\n')
|
||||
|
||||
ri = 0
|
||||
}
|
||||
}
|
||||
|
||||
return MessageItemsFromLines(builder.String(), limits)
|
||||
}
|
||||
|
||||
// testPartitionMessage partitions repeated text into message items.
|
||||
func testPartitionMessage(hundreds int) ([]types.MessageItem, int) {
|
||||
limits := types.MessageLimit{
|
||||
ChunkSize: 2000,
|
||||
TotalChunkSize: 6000,
|
||||
ChunkCount: 10,
|
||||
}
|
||||
builder := strings.Builder{}
|
||||
|
||||
for range hundreds {
|
||||
builder.WriteString(hundredChars)
|
||||
}
|
||||
|
||||
items, omitted := PartitionMessage(builder.String(), limits, 100)
|
||||
contentSize := Min(hundreds*100, limits.TotalChunkSize)
|
||||
expectedOmitted := Max(0, (hundreds*100)-contentSize)
|
||||
|
||||
gomega.ExpectWithOffset(0, omitted).To(gomega.Equal(expectedOmitted))
|
||||
|
||||
return items, omitted
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue