2022-09-02 19:23:33 +00:00
|
|
|
package datagen
|
|
|
|
|
|
|
|
import (
|
2023-02-28 11:12:12 +00:00
|
|
|
"bytes"
|
2022-09-02 19:23:33 +00:00
|
|
|
"math/rand"
|
2024-01-11 18:59:36 +00:00
|
|
|
"sync/atomic"
|
2022-09-02 19:23:33 +00:00
|
|
|
"time"
|
|
|
|
|
2023-02-28 11:12:12 +00:00
|
|
|
"github.com/go-loremipsum/loremipsum"
|
2022-09-02 19:23:33 +00:00
|
|
|
"go.k6.io/k6/js/modules"
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// Generator stores buffer of random bytes with some tail and returns data slices with
|
|
|
|
// an increasing offset so that we receive a different set of bytes after each call without
|
|
|
|
// re-generation of the entire buffer from scratch:
|
|
|
|
//
|
|
|
|
// [<----------size----------><-tail->]
|
|
|
|
// [<----------slice0-------->........]
|
|
|
|
// [.<----------slice1-------->.......]
|
|
|
|
// [..<----------slice2-------->......]
|
|
|
|
Generator struct {
|
|
|
|
vu modules.VU
|
|
|
|
size int
|
2023-03-01 14:10:30 +00:00
|
|
|
rand *rand.Rand
|
2022-09-02 19:23:33 +00:00
|
|
|
buf []byte
|
2023-02-28 11:12:12 +00:00
|
|
|
typ string
|
2022-09-02 19:23:33 +00:00
|
|
|
offset int
|
2024-01-11 18:59:36 +00:00
|
|
|
|
|
|
|
streaming bool
|
|
|
|
seed *atomic.Int64
|
2022-09-02 19:23:33 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// TailSize specifies number of extra random bytes in the buffer tail.
|
|
|
|
const TailSize = 1024
|
|
|
|
|
2023-02-28 11:12:12 +00:00
|
|
|
var payloadTypes = []string{
|
|
|
|
"text",
|
|
|
|
"random",
|
|
|
|
"",
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:59:36 +00:00
|
|
|
func NewGenerator(vu modules.VU, size int, typ string, streaming bool) Generator {
|
2022-09-18 15:00:33 +00:00
|
|
|
if size <= 0 {
|
|
|
|
panic("size should be positive")
|
|
|
|
}
|
2023-03-23 15:13:35 +00:00
|
|
|
|
2023-02-28 11:12:12 +00:00
|
|
|
var found bool
|
|
|
|
for i := range payloadTypes {
|
|
|
|
if payloadTypes[i] == typ {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found {
|
|
|
|
vu.InitEnv().Logger.Info("Unknown payload type '%s', random will be used.", typ)
|
|
|
|
}
|
|
|
|
g := Generator{
|
2023-03-01 14:09:26 +00:00
|
|
|
vu: vu,
|
|
|
|
size: size,
|
2023-02-28 11:12:12 +00:00
|
|
|
typ: typ,
|
|
|
|
}
|
2024-01-11 18:59:36 +00:00
|
|
|
|
|
|
|
if streaming {
|
|
|
|
g.streaming = true
|
|
|
|
g.seed = new(atomic.Int64)
|
|
|
|
} else {
|
|
|
|
g.rand = rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
g.buf = make([]byte, size+TailSize)
|
|
|
|
g.fillBuffer()
|
|
|
|
}
|
2023-02-28 11:12:12 +00:00
|
|
|
return g
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Generator) fillBuffer() {
|
|
|
|
switch g.typ {
|
|
|
|
case "text":
|
|
|
|
li := loremipsum.New()
|
|
|
|
b := bytes.NewBuffer(g.buf[:0])
|
|
|
|
for b.Len() < g.size+TailSize {
|
|
|
|
b.WriteString(li.Paragraph())
|
|
|
|
b.WriteRune('\n')
|
|
|
|
}
|
|
|
|
g.buf = b.Bytes()
|
|
|
|
default:
|
2024-01-12 16:28:13 +00:00
|
|
|
g.rand.Read(g.buf) // Per docs, err is always nil here
|
2023-03-01 14:09:26 +00:00
|
|
|
}
|
2022-09-02 19:23:33 +00:00
|
|
|
}
|
|
|
|
|
2024-01-12 14:37:29 +00:00
|
|
|
func (g *Generator) GenPayload() Payload {
|
2024-01-11 18:59:36 +00:00
|
|
|
if g.streaming {
|
|
|
|
return NewStreamPayload(g.size, g.seed.Add(1), g.typ)
|
|
|
|
}
|
|
|
|
|
2022-09-02 19:23:33 +00:00
|
|
|
data := g.nextSlice()
|
2024-01-11 18:46:57 +00:00
|
|
|
return NewFixedPayload(data)
|
2022-09-02 19:23:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *Generator) nextSlice() []byte {
|
2023-02-28 11:12:12 +00:00
|
|
|
if g.offset+g.size >= len(g.buf) {
|
2023-03-01 14:09:26 +00:00
|
|
|
g.offset = 0
|
2023-02-28 11:12:12 +00:00
|
|
|
g.fillBuffer()
|
2022-09-02 19:23:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
result := g.buf[g.offset : g.offset+g.size]
|
|
|
|
|
|
|
|
// Shift the offset for the next call. If we've used our entire tail, then erase
|
|
|
|
// the buffer so that on the next call it is regenerated anew
|
|
|
|
g.offset += 1
|
|
|
|
return result
|
|
|
|
}
|