mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-24 14:00:19 +00:00
473 lines
8.7 KiB
Go
473 lines
8.7 KiB
Go
/*
|
|
Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package fuzz
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFuzz_basic(t *testing.T) {
|
|
obj := &struct {
|
|
I int
|
|
I8 int8
|
|
I16 int16
|
|
I32 int32
|
|
I64 int64
|
|
U uint
|
|
U8 uint8
|
|
U16 uint16
|
|
U32 uint32
|
|
U64 uint64
|
|
Uptr uintptr
|
|
S string
|
|
B bool
|
|
T time.Time
|
|
}{}
|
|
|
|
failed := map[string]int{}
|
|
for i := 0; i < 10; i++ {
|
|
New().Fuzz(obj)
|
|
|
|
if n, v := "i", obj.I; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "i8", obj.I8; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "i16", obj.I16; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "i32", obj.I32; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "i64", obj.I64; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "u", obj.U; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "u8", obj.U8; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "u16", obj.U16; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "u32", obj.U32; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "u64", obj.U64; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "uptr", obj.Uptr; v == 0 {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "s", obj.S; v == "" {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "b", obj.B; v == false {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "t", obj.T; v.IsZero() {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
}
|
|
checkFailed(t, failed)
|
|
}
|
|
|
|
func checkFailed(t *testing.T, failed map[string]int) {
|
|
for k, v := range failed {
|
|
if v > 8 {
|
|
t.Errorf("%v seems to not be getting set, was zero value %v times", k, v)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFuzz_structptr(t *testing.T) {
|
|
obj := &struct {
|
|
A *struct {
|
|
S string
|
|
}
|
|
}{}
|
|
|
|
f := New().NilChance(.5)
|
|
failed := map[string]int{}
|
|
for i := 0; i < 10; i++ {
|
|
f.Fuzz(obj)
|
|
|
|
if n, v := "a not nil", obj.A; v == nil {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "a nil", obj.A; v != nil {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
if n, v := "as", obj.A; v == nil || v.S == "" {
|
|
failed[n] = failed[n] + 1
|
|
}
|
|
}
|
|
checkFailed(t, failed)
|
|
}
|
|
|
|
// tryFuzz tries fuzzing up to 20 times. Fail if check() never passes, report the highest
|
|
// stage it ever got to.
|
|
func tryFuzz(t *testing.T, f *Fuzzer, obj interface{}, check func() (stage int, passed bool)) {
|
|
maxStage := 0
|
|
for i := 0; i < 20; i++ {
|
|
f.Fuzz(obj)
|
|
stage, passed := check()
|
|
if stage > maxStage {
|
|
maxStage = stage
|
|
}
|
|
if passed {
|
|
return
|
|
}
|
|
}
|
|
t.Errorf("Only ever got to stage %v", maxStage)
|
|
}
|
|
|
|
func TestFuzz_structmap(t *testing.T) {
|
|
obj := &struct {
|
|
A map[struct {
|
|
S string
|
|
}]struct {
|
|
S2 string
|
|
}
|
|
B map[string]string
|
|
}{}
|
|
|
|
tryFuzz(t, New(), obj, func() (int, bool) {
|
|
if obj.A == nil {
|
|
return 1, false
|
|
}
|
|
if len(obj.A) == 0 {
|
|
return 2, false
|
|
}
|
|
for k, v := range obj.A {
|
|
if k.S == "" {
|
|
return 3, false
|
|
}
|
|
if v.S2 == "" {
|
|
return 4, false
|
|
}
|
|
}
|
|
|
|
if obj.B == nil {
|
|
return 5, false
|
|
}
|
|
if len(obj.B) == 0 {
|
|
return 6, false
|
|
}
|
|
for k, v := range obj.B {
|
|
if k == "" {
|
|
return 7, false
|
|
}
|
|
if v == "" {
|
|
return 8, false
|
|
}
|
|
}
|
|
return 9, true
|
|
})
|
|
}
|
|
|
|
func TestFuzz_structslice(t *testing.T) {
|
|
obj := &struct {
|
|
A []struct {
|
|
S string
|
|
}
|
|
B []string
|
|
}{}
|
|
|
|
tryFuzz(t, New(), obj, func() (int, bool) {
|
|
if obj.A == nil {
|
|
return 1, false
|
|
}
|
|
if len(obj.A) == 0 {
|
|
return 2, false
|
|
}
|
|
for _, v := range obj.A {
|
|
if v.S == "" {
|
|
return 3, false
|
|
}
|
|
}
|
|
|
|
if obj.B == nil {
|
|
return 4, false
|
|
}
|
|
if len(obj.B) == 0 {
|
|
return 5, false
|
|
}
|
|
for _, v := range obj.B {
|
|
if v == "" {
|
|
return 6, false
|
|
}
|
|
}
|
|
return 7, true
|
|
})
|
|
}
|
|
|
|
func TestFuzz_structarray(t *testing.T) {
|
|
obj := &struct {
|
|
A [3]struct {
|
|
S string
|
|
}
|
|
B [2]int
|
|
}{}
|
|
|
|
tryFuzz(t, New(), obj, func() (int, bool) {
|
|
for _, v := range obj.A {
|
|
if v.S == "" {
|
|
return 1, false
|
|
}
|
|
}
|
|
|
|
for _, v := range obj.B {
|
|
if v == 0 {
|
|
return 2, false
|
|
}
|
|
}
|
|
return 3, true
|
|
})
|
|
}
|
|
|
|
func TestFuzz_custom(t *testing.T) {
|
|
obj := &struct {
|
|
A string
|
|
B *string
|
|
C map[string]string
|
|
D *map[string]string
|
|
}{}
|
|
|
|
testPhrase := "gotcalled"
|
|
testMap := map[string]string{"C": "D"}
|
|
f := New().Funcs(
|
|
func(s *string, c Continue) {
|
|
*s = testPhrase
|
|
},
|
|
func(m map[string]string, c Continue) {
|
|
m["C"] = "D"
|
|
},
|
|
)
|
|
|
|
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
|
|
})
|
|
}
|
|
|
|
type SelfFuzzer string
|
|
|
|
// Implement fuzz.Interface.
|
|
func (sf *SelfFuzzer) Fuzz(c Continue) {
|
|
*sf = selfFuzzerTestPhrase
|
|
}
|
|
|
|
const selfFuzzerTestPhrase = "was fuzzed"
|
|
|
|
func TestFuzz_interface(t *testing.T) {
|
|
f := New()
|
|
|
|
var obj1 SelfFuzzer
|
|
tryFuzz(t, f, &obj1, func() (int, bool) {
|
|
if obj1 != selfFuzzerTestPhrase {
|
|
return 1, false
|
|
}
|
|
return 1, true
|
|
})
|
|
|
|
var obj2 map[int]SelfFuzzer
|
|
tryFuzz(t, f, &obj2, func() (int, bool) {
|
|
for _, v := range obj2 {
|
|
if v != selfFuzzerTestPhrase {
|
|
return 1, false
|
|
}
|
|
}
|
|
return 1, true
|
|
})
|
|
}
|
|
|
|
func TestFuzz_interfaceAndFunc(t *testing.T) {
|
|
const privateTestPhrase = "private phrase"
|
|
f := New().Funcs(
|
|
// This should take precedence over SelfFuzzer.Fuzz().
|
|
func(s *SelfFuzzer, c Continue) {
|
|
*s = privateTestPhrase
|
|
},
|
|
)
|
|
|
|
var obj1 SelfFuzzer
|
|
tryFuzz(t, f, &obj1, func() (int, bool) {
|
|
if obj1 != privateTestPhrase {
|
|
return 1, false
|
|
}
|
|
return 1, true
|
|
})
|
|
|
|
var obj2 map[int]SelfFuzzer
|
|
tryFuzz(t, f, &obj2, func() (int, bool) {
|
|
for _, v := range obj2 {
|
|
if v != privateTestPhrase {
|
|
return 1, false
|
|
}
|
|
}
|
|
return 1, true
|
|
})
|
|
}
|
|
|
|
func TestFuzz_noCustom(t *testing.T) {
|
|
type Inner struct {
|
|
Str string
|
|
}
|
|
type Outer struct {
|
|
Str string
|
|
In Inner
|
|
}
|
|
|
|
testPhrase := "gotcalled"
|
|
f := New().Funcs(
|
|
func(outer *Outer, c Continue) {
|
|
outer.Str = testPhrase
|
|
c.Fuzz(&outer.In)
|
|
},
|
|
func(inner *Inner, c Continue) {
|
|
inner.Str = testPhrase
|
|
},
|
|
)
|
|
c := Continue{fc: &fuzzerContext{fuzzer: f}, Rand: f.r}
|
|
|
|
// Fuzzer.Fuzz()
|
|
obj1 := Outer{}
|
|
f.Fuzz(&obj1)
|
|
if obj1.Str != testPhrase {
|
|
t.Errorf("expected Outer custom function to have been called")
|
|
}
|
|
if obj1.In.Str != testPhrase {
|
|
t.Errorf("expected Inner custom function to have been called")
|
|
}
|
|
|
|
// Continue.Fuzz()
|
|
obj2 := Outer{}
|
|
c.Fuzz(&obj2)
|
|
if obj2.Str != testPhrase {
|
|
t.Errorf("expected Outer custom function to have been called")
|
|
}
|
|
if obj2.In.Str != testPhrase {
|
|
t.Errorf("expected Inner custom function to have been called")
|
|
}
|
|
|
|
// Fuzzer.FuzzNoCustom()
|
|
obj3 := Outer{}
|
|
f.FuzzNoCustom(&obj3)
|
|
if obj3.Str == testPhrase {
|
|
t.Errorf("expected Outer custom function to not have been called")
|
|
}
|
|
if obj3.In.Str != testPhrase {
|
|
t.Errorf("expected Inner custom function to have been called")
|
|
}
|
|
|
|
// Continue.FuzzNoCustom()
|
|
obj4 := Outer{}
|
|
c.FuzzNoCustom(&obj4)
|
|
if obj4.Str == testPhrase {
|
|
t.Errorf("expected Outer custom function to not have been called")
|
|
}
|
|
if obj4.In.Str != testPhrase {
|
|
t.Errorf("expected Inner custom function to have been called")
|
|
}
|
|
}
|
|
|
|
func TestFuzz_NumElements(t *testing.T) {
|
|
f := New().NilChance(0).NumElements(0, 1)
|
|
obj := &struct {
|
|
A []int
|
|
}{}
|
|
|
|
tryFuzz(t, f, obj, func() (int, bool) {
|
|
if obj.A == nil {
|
|
return 1, false
|
|
}
|
|
return 2, len(obj.A) == 0
|
|
})
|
|
tryFuzz(t, f, obj, func() (int, bool) {
|
|
if obj.A == nil {
|
|
return 3, false
|
|
}
|
|
return 4, len(obj.A) == 1
|
|
})
|
|
}
|
|
|
|
func TestFuzz_Maxdepth(t *testing.T) {
|
|
type S struct {
|
|
S *S
|
|
}
|
|
|
|
f := New().NilChance(0)
|
|
|
|
f.MaxDepth(1)
|
|
for i := 0; i < 100; i++ {
|
|
obj := S{}
|
|
f.Fuzz(&obj)
|
|
|
|
if obj.S != nil {
|
|
t.Errorf("Expected nil")
|
|
}
|
|
}
|
|
|
|
f.MaxDepth(3) // field, ptr
|
|
for i := 0; i < 100; i++ {
|
|
obj := S{}
|
|
f.Fuzz(&obj)
|
|
|
|
if obj.S == nil {
|
|
t.Errorf("Expected obj.S not nil")
|
|
} else if obj.S.S != nil {
|
|
t.Errorf("Expected obj.S.S nil")
|
|
}
|
|
}
|
|
|
|
f.MaxDepth(5) // field, ptr, field, ptr
|
|
for i := 0; i < 100; i++ {
|
|
obj := S{}
|
|
f.Fuzz(&obj)
|
|
|
|
if obj.S == nil {
|
|
t.Errorf("Expected obj.S not nil")
|
|
} else if obj.S.S == nil {
|
|
t.Errorf("Expected obj.S.S not nil")
|
|
} else if obj.S.S.S != nil {
|
|
t.Errorf("Expected obj.S.S.S nil")
|
|
}
|
|
}
|
|
}
|