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 ( require (
github.com/jedib0t/go-pretty/v6 v6.6.7 github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/valyala/fasthttp v1.62.0 github.com/valyala/fasthttp v1.62.0
github.com/brianvoe/gofakeit/v7 v7.2.1
gopkg.in/yaml.v3 v3.0.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 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= 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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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= github.com/jedib0t/go-pretty/v6 v6.6.7 h1:m+LbHpm0aIAPLzLbMfn8dc3Ht8MW7lsSO4MPItz/Uuo=

View File

@ -1,14 +1,18 @@
package requests package requests
import ( import (
"bytes"
"context" "context"
"math/rand" "math/rand"
"net/url" "net/url"
"strings"
"text/template"
"time" "time"
"github.com/aykhans/dodo/config" "github.com/aykhans/dodo/config"
"github.com/aykhans/dodo/types" "github.com/aykhans/dodo/types"
"github.com/aykhans/dodo/utils" "github.com/aykhans/dodo/utils"
"github.com/brianvoe/gofakeit/v7"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
) )
@ -21,6 +25,11 @@ type Request struct {
getRequest RequestGeneratorFunc getRequest RequestGeneratorFunc
} }
type keyValueGenerator struct {
key func() string
value func() string
}
// Send sends the HTTP request using the fasthttp client with a specified timeout. // 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. // 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) { func (r *Request) Send(ctx context.Context, timeout time.Duration) (*fasthttp.Response, error) {
@ -101,17 +110,10 @@ func getRequestGeneratorFunc(
bodies []string, bodies []string,
localRand *rand.Rand, localRand *rand.Rand,
) RequestGeneratorFunc { ) 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) getParams := getKeyValueGeneratorFunc(params, localRand)
getHeaders := getKeyValueGeneratorFunc(headers, localRand) getHeaders := getKeyValueGeneratorFunc(headers, localRand)
getCookies := getKeyValueGeneratorFunc(cookies, localRand) getCookies := getKeyValueGeneratorFunc(cookies, localRand)
getBody := getValueFunc(bodies, newFuncMap(localRand), localRand)
return func() *fasthttp.Request { return func() *fasthttp.Request {
return newFasthttpRequest( return newFasthttpRequest(
@ -199,45 +201,75 @@ func getKeyValueGeneratorFunc[
keyValueSlice []types.KeyValue[string, []string], keyValueSlice []types.KeyValue[string, []string],
localRand *rand.Rand, localRand *rand.Rand,
) func() T { ) func() T {
getKeyValueSlice := []map[string]func() string{} keyValueGenerators := make([]keyValueGenerator, len(keyValueSlice))
isRandom := false
for _, kv := range keyValueSlice { funcMap := newFuncMap(localRand)
if valuesLen := len(kv.Value); valuesLen > 1 {
isRandom = true 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 {
return func() T { keyValues := make(T, len(keyValueGenerators))
keyValues := make(T, len(getKeyValueSlice)) for i, keyValue := range keyValueGenerators {
for i, keyValue := range getKeyValueSlice { keyValues[i] = types.KeyValue[string, string]{
for key, value := range keyValue { Key: keyValue.key(),
keyValues[i] = types.KeyValue[string, string]{ Value: keyValue.value(),
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 { 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)) wg.Add(int(dodosCount))
streamWG.Add(1) streamWG.Add(1)
streamCtx, streamCtxCancel := context.WithCancel(context.Background()) streamCtx, streamCtxCancel := context.WithCancel(ctx)
go streamProgress(streamCtx, &streamWG, requestConfig.RequestCount, "Dodos Working🔥", increase) 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. // 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. // 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 { func RandomValueCycle[T any](values []T, localRand *rand.Rand) func() T {
var ( switch valuesLen := len(values); valuesLen {
valuesLen = len(values)
currentIndex = localRand.Intn(valuesLen)
stopIndex = currentIndex
)
switch valuesLen {
case 0: case 0:
var zero T var zero T
return func() T { return zero } return func() T { return zero }
case 1: case 1:
return func() T { return values[0] } return func() T { return values[0] }
default: default:
currentIndex := localRand.Intn(valuesLen)
stopIndex := currentIndex
return func() T { return func() T {
value := values[currentIndex] value := values[currentIndex]
currentIndex++ currentIndex++