aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/testutil
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-11-07 16:01:03 +0100
committerDmitry Vyukov <dvyukov@google.com>2024-11-07 16:17:12 +0000
commit64907ecc42ea17acbd68ccdd4b32d560e0c673e0 (patch)
tree748f19217dca4725b4d56ce41103cff258ff7800 /pkg/testutil
parent0e71cd2515586d7118198754ab664db6bc70f47a (diff)
pkg/manager: add test for all HTTP templates
It's easy to make mistakes in templates that lead to runtime panics. Catch them during testing. This required to convert some pointers to values for things that must not be nil. Otherwise the randomized test can pass nil for the objects and templates fail.
Diffstat (limited to 'pkg/testutil')
-rw-r--r--pkg/testutil/testutil.go49
1 files changed, 49 insertions, 0 deletions
diff --git a/pkg/testutil/testutil.go b/pkg/testutil/testutil.go
index 67dee7ddf..153584dd5 100644
--- a/pkg/testutil/testutil.go
+++ b/pkg/testutil/testutil.go
@@ -6,8 +6,10 @@ package testutil
import (
"math/rand"
"os"
+ "reflect"
"strconv"
"testing"
+ "testing/quick"
"time"
)
@@ -41,3 +43,50 @@ func RandMountImage(r *rand.Rand) []byte {
r.Read(slice)
return slice
}
+
+// RandValue creates a random value of the same type as the argument typ.
+// It recursively fills structs/slices/maps similar to testing/quick.Value,
+// but it handles time.Time as well w/o panicing (unfortunately testing/quick panics on time.Time).
+func RandValue(t *testing.T, typ any) any {
+ return randValue(t, rand.New(RandSource(t)), reflect.TypeOf(typ)).Interface()
+}
+
+func randValue(t *testing.T, rnd *rand.Rand, typ reflect.Type) reflect.Value {
+ v := reflect.New(typ).Elem()
+ switch typ.Kind() {
+ default:
+ ok := false
+ v, ok = quick.Value(typ, rnd)
+ if !ok {
+ t.Fatalf("failed to generate random value of type %v", typ)
+ }
+ case reflect.Slice:
+ size := rand.Intn(4)
+ v.Set(reflect.MakeSlice(typ, size, size))
+ fallthrough
+ case reflect.Array:
+ for i := 0; i < v.Len(); i++ {
+ v.Index(i).Set(randValue(t, rnd, typ.Elem()))
+ }
+ case reflect.Struct:
+ if typ.String() == "time.Time" {
+ v = reflect.ValueOf(time.UnixMilli(rnd.Int63()))
+ } else {
+ for i := 0; i < v.NumField(); i++ {
+ v.Field(i).Set(randValue(t, rnd, typ.Field(i).Type))
+ }
+ }
+ case reflect.Pointer:
+ v.SetZero()
+ if rand.Intn(2) == 0 {
+ v.Set(reflect.New(typ.Elem()))
+ v.Elem().Set(randValue(t, rnd, typ.Elem()))
+ }
+ case reflect.Map:
+ v.Set(reflect.MakeMap(typ))
+ for i := rand.Intn(4); i > 0; i-- {
+ v.SetMapIndex(randValue(t, rnd, typ.Key()), randValue(t, rnd, typ.Elem()))
+ }
+ }
+ return v
+}