mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 09:22:44 +00:00
Add TODOs, clean up, clarify comments, and add one more test.
This commit is contained in:
parent
aa92dd7fb2
commit
d09b164e67
@ -28,12 +28,21 @@ type Fuzzer struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFuzzer returns a new Fuzzer with the given custom fuzzing functions.
|
// NewFuzzer returns a new Fuzzer with the given custom fuzzing functions.
|
||||||
|
//
|
||||||
// Each entry in fuzzFuncs must be a function with one parameter, which will
|
// Each entry in fuzzFuncs must be a function with one parameter, which will
|
||||||
// be the variable we wish that function to fill with random data. For this
|
// be the variable we wish that function to fill with random data. For this
|
||||||
// to be effective, the variable type should be either a pointer, map, slice,
|
// to be effective, the variable type should be either a pointer or a map.
|
||||||
// etc. These functions are called sensibly, e.g., if you wanted custom string
|
//
|
||||||
|
// These functions are called sensibly, e.g., if you wanted custom string
|
||||||
// fuzzing, the function `func(s *string)` would get called and passed the
|
// fuzzing, the function `func(s *string)` would get called and passed the
|
||||||
// address of strings.
|
// address of strings. Maps and pointers will be made/new'd for you. For
|
||||||
|
// slices, it doesn't make much sense to pre-create them--Fuzzer doesn't
|
||||||
|
// know how long you want your slice--so take a pointer to a slice, and
|
||||||
|
// make it yourself. (If you don't want your map/pointer type pre-made,
|
||||||
|
// take a pointer to it, and make it yourself.)
|
||||||
|
//
|
||||||
|
// TODO: Take a source of randomness for deterministic, repeatable fuzzing.
|
||||||
|
// TODO: Make probability of getting a nil customizable.
|
||||||
func NewFuzzer(fuzzFuncs ...interface{}) *Fuzzer {
|
func NewFuzzer(fuzzFuncs ...interface{}) *Fuzzer {
|
||||||
f := &Fuzzer{
|
f := &Fuzzer{
|
||||||
map[reflect.Type]func(reflect.Value){},
|
map[reflect.Type]func(reflect.Value){},
|
||||||
@ -48,7 +57,11 @@ func NewFuzzer(fuzzFuncs ...interface{}) *Fuzzer {
|
|||||||
panic("Need 1 in and 0 out params!")
|
panic("Need 1 in and 0 out params!")
|
||||||
}
|
}
|
||||||
argT := t.In(0)
|
argT := t.In(0)
|
||||||
// fmt.Printf("Making entry for thing with '%v' type\n", argT)
|
switch argT.Kind() {
|
||||||
|
case reflect.Ptr, reflect.Map:
|
||||||
|
default:
|
||||||
|
panic("fuzzFunc must take pointer or map type")
|
||||||
|
}
|
||||||
f.customFuzz[argT] = func(toFuzz reflect.Value) {
|
f.customFuzz[argT] = func(toFuzz reflect.Value) {
|
||||||
if toFuzz.Type().AssignableTo(argT) {
|
if toFuzz.Type().AssignableTo(argT) {
|
||||||
v.Call([]reflect.Value{toFuzz})
|
v.Call([]reflect.Value{toFuzz})
|
||||||
@ -96,9 +109,6 @@ func (f *Fuzzer) doFuzz(v reflect.Value) {
|
|||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if rand.Intn(5) > 0 {
|
if rand.Intn(5) > 0 {
|
||||||
v.Set(reflect.MakeMap(v.Type()))
|
v.Set(reflect.MakeMap(v.Type()))
|
||||||
if f.tryCustom(v) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
n := 1 + rand.Intn(10)
|
n := 1 + rand.Intn(10)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
key := reflect.New(v.Type().Key()).Elem()
|
key := reflect.New(v.Type().Key()).Elem()
|
||||||
@ -121,9 +131,6 @@ func (f *Fuzzer) doFuzz(v reflect.Value) {
|
|||||||
if rand.Intn(5) > 0 {
|
if rand.Intn(5) > 0 {
|
||||||
n := 1 + rand.Intn(10)
|
n := 1 + rand.Intn(10)
|
||||||
v.Set(reflect.MakeSlice(v.Type(), n, n))
|
v.Set(reflect.MakeSlice(v.Type(), n, n))
|
||||||
if f.tryCustom(v) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
f.doFuzz(v.Index(i))
|
f.doFuzz(v.Index(i))
|
||||||
}
|
}
|
||||||
@ -147,15 +154,15 @@ func (f *Fuzzer) doFuzz(v reflect.Value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tryCustom searches for custom handlers and Randomizer implementations, and
|
// tryCustom searches for custom handlers, and returns true iff it finds a match
|
||||||
// returns true if it finds a match and successfully randomizes v.
|
// and successfully randomizes v.
|
||||||
func (f Fuzzer) tryCustom(v reflect.Value) bool {
|
func (f Fuzzer) tryCustom(v reflect.Value) bool {
|
||||||
// fmt.Printf("Trying thing with '%v' type\n", v.Type())
|
doCustom, ok := f.customFuzz[v.Type()]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Slice:
|
|
||||||
if v.IsNil() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
if !v.CanSet() {
|
if !v.CanSet() {
|
||||||
@ -170,12 +177,12 @@ func (f Fuzzer) tryCustom(v reflect.Value) bool {
|
|||||||
}
|
}
|
||||||
v.Set(reflect.MakeMap(v.Type()))
|
v.Set(reflect.MakeMap(v.Type()))
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
if f, ok := f.customFuzz[v.Type()]; ok {
|
|
||||||
f(v)
|
doCustom(v)
|
||||||
return true
|
return true
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fuzzInt(v reflect.Value) {
|
func fuzzInt(v reflect.Value) {
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,11 +114,12 @@ func TestFuzz_structptr(t *testing.T) {
|
|||||||
checkFailed(t, failed)
|
checkFailed(t, failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try fuzzing up to 20 times. Fail if check() never passes.
|
// tryFuzz tries fuzzing up to 20 times. Fail if check() never passes, report the highest
|
||||||
func tryFuzz(t *testing.T, obj interface{}, check func() (stage int, passed bool)) {
|
// stage it ever got to.
|
||||||
|
func tryFuzz(t *testing.T, f *Fuzzer, obj interface{}, check func() (stage int, passed bool)) {
|
||||||
maxStage := 0
|
maxStage := 0
|
||||||
for i := 0; i < 20; i++ {
|
for i := 0; i < 20; i++ {
|
||||||
NewFuzzer().Fuzz(obj)
|
f.Fuzz(obj)
|
||||||
stage, passed := check()
|
stage, passed := check()
|
||||||
if stage > maxStage {
|
if stage > maxStage {
|
||||||
maxStage = stage
|
maxStage = stage
|
||||||
@ -139,7 +141,7 @@ func TestFuzz_structmap(t *testing.T) {
|
|||||||
B map[string]string
|
B map[string]string
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
tryFuzz(t, obj, func() (int, bool) {
|
tryFuzz(t, NewFuzzer(), obj, func() (int, bool) {
|
||||||
if obj.A == nil {
|
if obj.A == nil {
|
||||||
return 1, false
|
return 1, false
|
||||||
}
|
}
|
||||||
@ -181,7 +183,7 @@ func TestFuzz_structslice(t *testing.T) {
|
|||||||
B []string
|
B []string
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
tryFuzz(t, obj, func() (int, bool) {
|
tryFuzz(t, NewFuzzer(), obj, func() (int, bool) {
|
||||||
if obj.A == nil {
|
if obj.A == nil {
|
||||||
return 1, false
|
return 1, false
|
||||||
}
|
}
|
||||||
@ -213,17 +215,40 @@ func TestFuzz_custom(t *testing.T) {
|
|||||||
obj := &struct {
|
obj := &struct {
|
||||||
A string
|
A string
|
||||||
B *string
|
B *string
|
||||||
|
C map[string]string
|
||||||
|
D *map[string]string
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
testPhrase := "gotcalled"
|
testPhrase := "gotcalled"
|
||||||
NewFuzzer(func(s *string) { *s = testPhrase }).Fuzz(obj)
|
testMap := map[string]string{"C": "D"}
|
||||||
if obj.A != testPhrase {
|
f := NewFuzzer(
|
||||||
t.Errorf("A not set")
|
func(s *string) {
|
||||||
}
|
*s = testPhrase
|
||||||
if obj.B == nil {
|
},
|
||||||
t.Fatalf("B is nil")
|
func(m map[string]string) {
|
||||||
}
|
m["C"] = "D"
|
||||||
if *obj.B != testPhrase {
|
},
|
||||||
t.Errorf("B not set")
|
)
|
||||||
}
|
|
||||||
|
tryFuzz(t, f, obj, func() (int, bool) {
|
||||||
|
if obj.A != testPhrase {
|
||||||
|
return 1, false
|
||||||
|
}
|
||||||
|
if obj.B == nil {
|
||||||
|
return 2, false
|
||||||
|
}
|
||||||
|
if *obj.B != testPhrase {
|
||||||
|
return 3, false
|
||||||
|
}
|
||||||
|
if e, a := testMap, obj.C; !reflect.DeepEqual(e, a) {
|
||||||
|
return 4, false
|
||||||
|
}
|
||||||
|
if obj.D == nil {
|
||||||
|
return 5, false
|
||||||
|
}
|
||||||
|
if e, a := testMap, *obj.D; !reflect.DeepEqual(e, a) {
|
||||||
|
return 6, false
|
||||||
|
}
|
||||||
|
return 7, true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user