Value generator initial commit

This commit is contained in:
Aykhan Shahsuvarov 2025-05-30 10:40:20 +04:00
parent 924bd819ee
commit f248c2af96
5 changed files with 81 additions and 50 deletions

1
go.mod
View File

@ -5,6 +5,7 @@ go 1.24.2
require (
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/valyala/fasthttp v1.62.0
github.com/brianvoe/gofakeit/v7 v7.2.1
gopkg.in/yaml.v3 v3.0.1
)

2
go.sum
View File

@ -1,5 +1,7 @@
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/brianvoe/gofakeit/v7 v7.2.1 h1:AGojgaaCdgq4Adzrd2uWdbGNDyX6MWNhHdQBraNfOHI=
github.com/brianvoe/gofakeit/v7 v7.2.1/go.mod h1:QXuPeBw164PJCzCUZVmgpgHJ3Llj49jSLVkKPMtxtxA=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=

View File

@ -1,14 +1,18 @@
package requests
import (
"bytes"
"context"
"math/rand"
"net/url"
"strings"
"text/template"
"time"
"github.com/aykhans/dodo/config"
"github.com/aykhans/dodo/types"
"github.com/aykhans/dodo/utils"
"github.com/brianvoe/gofakeit/v7"
"github.com/valyala/fasthttp"
)
@ -21,6 +25,11 @@ type Request struct {
getRequest RequestGeneratorFunc
}
type keyValueGenerator struct {
key func() string
value func() string
}
// Send sends the HTTP request using the fasthttp client with a specified timeout.
// It returns the HTTP response or an error if the request fails or times out.
func (r *Request) Send(ctx context.Context, timeout time.Duration) (*fasthttp.Response, error) {
@ -101,17 +110,10 @@ func getRequestGeneratorFunc(
bodies []string,
localRand *rand.Rand,
) RequestGeneratorFunc {
bodiesLen := len(bodies)
getBody := func() string { return "" }
if bodiesLen == 1 {
getBody = func() string { return bodies[0] }
} else if bodiesLen > 1 {
getBody = utils.RandomValueCycle(bodies, localRand)
}
getParams := getKeyValueGeneratorFunc(params, localRand)
getHeaders := getKeyValueGeneratorFunc(headers, localRand)
getCookies := getKeyValueGeneratorFunc(cookies, localRand)
getBody := getValueFunc(bodies, newFuncMap(localRand), localRand)
return func() *fasthttp.Request {
return newFasthttpRequest(
@ -199,45 +201,75 @@ func getKeyValueGeneratorFunc[
keyValueSlice []types.KeyValue[string, []string],
localRand *rand.Rand,
) func() T {
getKeyValueSlice := []map[string]func() string{}
isRandom := false
keyValueGenerators := make([]keyValueGenerator, len(keyValueSlice))
for _, kv := range keyValueSlice {
if valuesLen := len(kv.Value); valuesLen > 1 {
isRandom = true
funcMap := newFuncMap(localRand)
for i, kv := range keyValueSlice {
keyValueGenerators[i] = keyValueGenerator{
key: getKeyFunc(kv.Key, funcMap),
value: getValueFunc(kv.Value, funcMap, localRand),
}
getKeyValueSlice = append(
getKeyValueSlice,
map[string]func() string{
kv.Key: utils.RandomValueCycle(kv.Value, localRand),
},
)
}
if isRandom {
return func() T {
keyValues := make(T, len(getKeyValueSlice))
for i, keyValue := range getKeyValueSlice {
for key, value := range keyValue {
keyValues[i] = types.KeyValue[string, string]{
Key: key,
Value: value(),
}
}
}
return keyValues
}
} else {
keyValues := make(T, len(getKeyValueSlice))
for i, keyValue := range getKeyValueSlice {
for key, value := range keyValue {
keyValues[i] = types.KeyValue[string, string]{
Key: key,
Value: value(),
}
return func() T {
keyValues := make(T, len(keyValueGenerators))
for i, keyValue := range keyValueGenerators {
keyValues[i] = types.KeyValue[string, string]{
Key: keyValue.key(),
Value: keyValue.value(),
}
}
return func() T { return keyValues }
return keyValues
}
}
func getKeyFunc(key string, funcMap template.FuncMap) func() string {
t, err := template.New("default").Funcs(funcMap).Parse(key)
if err != nil {
panic(err)
}
return func() string {
var buf bytes.Buffer
_ = t.Execute(&buf, nil)
return buf.String()
}
}
func getValueFunc(
values []string,
funcMap template.FuncMap,
localRand *rand.Rand,
) func() string {
templates := make([]*template.Template, len(values))
for i, value := range values {
t, err := template.New("default").Funcs(funcMap).Parse(value)
if err != nil {
panic(err)
}
templates[i] = t
}
randomTemplateFunc := utils.RandomValueCycle(templates, localRand)
return func() string {
if tmpl := randomTemplateFunc(); tmpl == nil {
return ""
} else {
var buf bytes.Buffer
_ = tmpl.Execute(&buf, nil)
return buf.String()
}
}
}
func newFuncMap(localRand *rand.Rand) template.FuncMap {
localFaker := gofakeit.NewFaker(localRand, false)
return template.FuncMap{
"upper": strings.ToUpper,
"fakeit_Name": localFaker.Name,
}
}

View File

@ -72,7 +72,7 @@ func releaseDodos(
wg.Add(int(dodosCount))
streamWG.Add(1)
streamCtx, streamCtxCancel := context.WithCancel(context.Background())
streamCtx, streamCtxCancel := context.WithCancel(ctx)
go streamProgress(streamCtx, &streamWG, requestConfig.RequestCount, "Dodos Working🔥", increase)

View File

@ -19,19 +19,15 @@ func Flatten[T any](nested [][]*T) []*T {
// reset and start cycling through the values in a random order again.
// The returned function isn't thread-safe and should be used in a single-threaded context.
func RandomValueCycle[T any](values []T, localRand *rand.Rand) func() T {
var (
valuesLen = len(values)
currentIndex = localRand.Intn(valuesLen)
stopIndex = currentIndex
)
switch valuesLen {
switch valuesLen := len(values); valuesLen {
case 0:
var zero T
return func() T { return zero }
case 1:
return func() T { return values[0] }
default:
currentIndex := localRand.Intn(valuesLen)
stopIndex := currentIndex
return func() T {
value := values[currentIndex]
currentIndex++