diff options
Diffstat (limited to 'pkg/state/tests')
-rw-r--r-- | pkg/state/tests/BUILD | 43 | ||||
-rw-r--r-- | pkg/state/tests/array.go | 35 | ||||
-rw-r--r-- | pkg/state/tests/array_test.go | 134 | ||||
-rw-r--r-- | pkg/state/tests/bench.go | 24 | ||||
-rw-r--r-- | pkg/state/tests/bench_test.go | 153 | ||||
-rw-r--r-- | pkg/state/tests/bool_test.go | 31 | ||||
-rw-r--r-- | pkg/state/tests/float_test.go | 118 | ||||
-rw-r--r-- | pkg/state/tests/integer.go | 163 | ||||
-rw-r--r-- | pkg/state/tests/integer_test.go | 94 | ||||
-rw-r--r-- | pkg/state/tests/load.go | 61 | ||||
-rw-r--r-- | pkg/state/tests/load_test.go | 78 | ||||
-rw-r--r-- | pkg/state/tests/map.go | 28 | ||||
-rw-r--r-- | pkg/state/tests/map_test.go | 90 | ||||
-rw-r--r-- | pkg/state/tests/register.go | 21 | ||||
-rw-r--r-- | pkg/state/tests/register_test.go | 178 | ||||
-rw-r--r-- | pkg/state/tests/string_test.go | 34 | ||||
-rw-r--r-- | pkg/state/tests/struct.go | 100 | ||||
-rw-r--r-- | pkg/state/tests/struct_test.go | 100 | ||||
-rw-r--r-- | pkg/state/tests/tests.go | 215 |
19 files changed, 0 insertions, 1700 deletions
diff --git a/pkg/state/tests/BUILD b/pkg/state/tests/BUILD deleted file mode 100644 index 9297cafbe..000000000 --- a/pkg/state/tests/BUILD +++ /dev/null @@ -1,43 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -package(licenses = ["notice"]) - -go_library( - name = "tests", - srcs = [ - "array.go", - "bench.go", - "integer.go", - "load.go", - "map.go", - "register.go", - "struct.go", - "tests.go", - ], - deps = [ - "//pkg/state", - "//pkg/state/pretty", - ], -) - -go_test( - name = "tests_test", - size = "small", - srcs = [ - "array_test.go", - "bench_test.go", - "bool_test.go", - "float_test.go", - "integer_test.go", - "load_test.go", - "map_test.go", - "register_test.go", - "string_test.go", - "struct_test.go", - ], - library = ":tests", - deps = [ - "//pkg/state", - "//pkg/state/wire", - ], -) diff --git a/pkg/state/tests/array.go b/pkg/state/tests/array.go deleted file mode 100644 index 0972a80e7..000000000 --- a/pkg/state/tests/array.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -// +stateify savable -type arrayContainer struct { - v [1]interface{} -} - -// +stateify savable -type arrayPtrContainer struct { - v *[1]interface{} -} - -// +stateify savable -type sliceContainer struct { - v []interface{} -} - -// +stateify savable -type slicePtrContainer struct { - v *[]interface{} -} diff --git a/pkg/state/tests/array_test.go b/pkg/state/tests/array_test.go deleted file mode 100644 index a347b2947..000000000 --- a/pkg/state/tests/array_test.go +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "reflect" - "testing" -) - -var allArrayPrimitives = []interface{}{ - [1]bool{}, - [1]bool{true}, - [2]bool{false, true}, - [1]int{}, - [1]int{1}, - [2]int{0, 1}, - [1]int8{}, - [1]int8{1}, - [2]int8{0, 1}, - [1]int16{}, - [1]int16{1}, - [2]int16{0, 1}, - [1]int32{}, - [1]int32{1}, - [2]int32{0, 1}, - [1]int64{}, - [1]int64{1}, - [2]int64{0, 1}, - [1]uint{}, - [1]uint{1}, - [2]uint{0, 1}, - [1]uintptr{}, - [1]uintptr{1}, - [2]uintptr{0, 1}, - [1]uint8{}, - [1]uint8{1}, - [2]uint8{0, 1}, - [1]uint16{}, - [1]uint16{1}, - [2]uint16{0, 1}, - [1]uint32{}, - [1]uint32{1}, - [2]uint32{0, 1}, - [1]uint64{}, - [1]uint64{1}, - [2]uint64{0, 1}, - [1]string{}, - [1]string{""}, - [1]string{nonEmptyString}, - [2]string{"", nonEmptyString}, -} - -func TestArrayPrimitives(t *testing.T) { - runTestCases(t, false, "plain", flatten(allArrayPrimitives)) - runTestCases(t, false, "pointers", pointersTo(flatten(allArrayPrimitives))) - runTestCases(t, false, "interfaces", interfacesTo(flatten(allArrayPrimitives))) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(flatten(allArrayPrimitives)))) -} - -func TestSlices(t *testing.T) { - var allSlices = flatten( - filter(allArrayPrimitives, func(o interface{}) (interface{}, bool) { - v := reflect.New(reflect.TypeOf(o)).Elem() - v.Set(reflect.ValueOf(o)) - return v.Slice(0, v.Len()).Interface(), true - }), - filter(allArrayPrimitives, func(o interface{}) (interface{}, bool) { - v := reflect.New(reflect.TypeOf(o)).Elem() - v.Set(reflect.ValueOf(o)) - if v.Len() == 0 { - // Return the pure "nil" value for the slice. - return reflect.New(v.Slice(0, 0).Type()).Elem().Interface(), true - } - return v.Slice(1, v.Len()).Interface(), true - }), - filter(allArrayPrimitives, func(o interface{}) (interface{}, bool) { - v := reflect.New(reflect.TypeOf(o)).Elem() - v.Set(reflect.ValueOf(o)) - if v.Len() == 0 { - // Return the zero-valued slice. - return reflect.MakeSlice(v.Slice(0, 0).Type(), 0, 0).Interface(), true - } - return v.Slice(0, v.Len()-1).Interface(), true - }), - ) - runTestCases(t, false, "plain", allSlices) - runTestCases(t, false, "pointers", pointersTo(allSlices)) - runTestCases(t, false, "interfaces", interfacesTo(allSlices)) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(allSlices))) -} - -func TestArrayContainers(t *testing.T) { - var ( - emptyArray [1]interface{} - fullArray [1]interface{} - ) - fullArray[0] = &emptyArray - runTestCases(t, false, "", []interface{}{ - arrayContainer{v: emptyArray}, - arrayContainer{v: fullArray}, - arrayPtrContainer{v: nil}, - arrayPtrContainer{v: &emptyArray}, - arrayPtrContainer{v: &fullArray}, - }) -} - -func TestSliceContainers(t *testing.T) { - var ( - nilSlice []interface{} - emptySlice = make([]interface{}, 0) - fullSlice = []interface{}{nil} - ) - runTestCases(t, false, "", []interface{}{ - sliceContainer{v: nilSlice}, - sliceContainer{v: emptySlice}, - sliceContainer{v: fullSlice}, - slicePtrContainer{v: nil}, - slicePtrContainer{v: &nilSlice}, - slicePtrContainer{v: &emptySlice}, - slicePtrContainer{v: &fullSlice}, - }) -} diff --git a/pkg/state/tests/bench.go b/pkg/state/tests/bench.go deleted file mode 100644 index 40869cdfb..000000000 --- a/pkg/state/tests/bench.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -// +stateify savable -type benchStruct struct { - B *benchStruct // Must be exported for gob. -} - -func (b *benchStruct) afterLoad() { - // Do nothing, just force scheduling. -} diff --git a/pkg/state/tests/bench_test.go b/pkg/state/tests/bench_test.go deleted file mode 100644 index 7e102c907..000000000 --- a/pkg/state/tests/bench_test.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "bytes" - "context" - "encoding/gob" - "fmt" - "testing" - - "gvisor.dev/gvisor/pkg/state" - "gvisor.dev/gvisor/pkg/state/wire" -) - -// buildPtrObject builds a benchmark object. -func buildPtrObject(n int) interface{} { - b := new(benchStruct) - for i := 0; i < n; i++ { - b = &benchStruct{B: b} - } - return b -} - -// buildMapObject builds a benchmark object. -func buildMapObject(n int) interface{} { - b := new(benchStruct) - m := make(map[int]*benchStruct) - for i := 0; i < n; i++ { - m[i] = b - } - return &m -} - -// buildSliceObject builds a benchmark object. -func buildSliceObject(n int) interface{} { - b := new(benchStruct) - s := make([]*benchStruct, 0, n) - for i := 0; i < n; i++ { - s = append(s, b) - } - return &s -} - -var allObjects = map[string]struct { - New func(int) interface{} -}{ - "ptr": { - New: buildPtrObject, - }, - "map": { - New: buildMapObject, - }, - "slice": { - New: buildSliceObject, - }, -} - -func buildObjects(n int, fn func(int) interface{}) (iters int, v interface{}) { - // maxSize is the maximum size of an individual object below. For an N - // larger than this, we start to return multiple objects. - const maxSize = 1024 - if n <= maxSize { - return 1, fn(n) - } - iters = (n + maxSize - 1) / maxSize - return iters, fn(maxSize) -} - -// gobSave is a version of save using gob (no stats available). -func gobSave(_ context.Context, w wire.Writer, v interface{}) (_ state.Stats, err error) { - enc := gob.NewEncoder(w) - err = enc.Encode(v) - return -} - -// gobLoad is a version of load using gob (no stats available). -func gobLoad(_ context.Context, r wire.Reader, v interface{}) (_ state.Stats, err error) { - dec := gob.NewDecoder(r) - err = dec.Decode(v) - return -} - -var allAlgos = map[string]struct { - Save func(context.Context, wire.Writer, interface{}) (state.Stats, error) - Load func(context.Context, wire.Reader, interface{}) (state.Stats, error) - MaxPtr int -}{ - "state": { - Save: state.Save, - Load: state.Load, - }, - "gob": { - Save: gobSave, - Load: gobLoad, - }, -} - -func BenchmarkEncoding(b *testing.B) { - for objName, objInfo := range allObjects { - for algoName, algoInfo := range allAlgos { - b.Run(fmt.Sprintf("%s/%s", objName, algoName), func(b *testing.B) { - b.StopTimer() - n, v := buildObjects(b.N, objInfo.New) - b.ReportAllocs() - b.StartTimer() - for i := 0; i < n; i++ { - if _, err := algoInfo.Save(context.Background(), discard{}, v); err != nil { - b.Errorf("save failed: %v", err) - } - } - b.StopTimer() - }) - } - } -} - -func BenchmarkDecoding(b *testing.B) { - for objName, objInfo := range allObjects { - for algoName, algoInfo := range allAlgos { - b.Run(fmt.Sprintf("%s/%s", objName, algoName), func(b *testing.B) { - b.StopTimer() - n, v := buildObjects(b.N, objInfo.New) - buf := new(bytes.Buffer) - if _, err := algoInfo.Save(context.Background(), buf, v); err != nil { - b.Errorf("save failed: %v", err) - } - b.ReportAllocs() - b.StartTimer() - var r bytes.Reader - for i := 0; i < n; i++ { - r.Reset(buf.Bytes()) - if _, err := algoInfo.Load(context.Background(), &r, v); err != nil { - b.Errorf("load failed: %v", err) - } - } - b.StopTimer() - }) - } - } -} diff --git a/pkg/state/tests/bool_test.go b/pkg/state/tests/bool_test.go deleted file mode 100644 index e17cfacf9..000000000 --- a/pkg/state/tests/bool_test.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "testing" -) - -var allBools = []bool{ - true, - false, -} - -func TestBool(t *testing.T) { - runTestCases(t, false, "plain", flatten(allBools)) - runTestCases(t, false, "pointers", pointersTo(flatten(allBools))) - runTestCases(t, false, "interfaces", interfacesTo(flatten(allBools))) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(flatten(allBools)))) -} diff --git a/pkg/state/tests/float_test.go b/pkg/state/tests/float_test.go deleted file mode 100644 index 3e89edd9c..000000000 --- a/pkg/state/tests/float_test.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "math" - "testing" -) - -var safeFloat32s = []float32{ - float32(0.0), - float32(1.0), - float32(-1.0), - float32(math.Inf(1)), - float32(math.Inf(-1)), -} - -var allFloat32s = append(safeFloat32s, float32(math.NaN())) - -var safeFloat64s = []float64{ - float64(0.0), - float64(1.0), - float64(-1.0), - math.Inf(1), - math.Inf(-1), -} - -var allFloat64s = append(safeFloat64s, math.NaN()) - -func TestFloat(t *testing.T) { - runTestCases(t, false, "plain", flatten( - allFloat32s, - allFloat64s, - )) - // See checkEqual for why NaNs are missing. - runTestCases(t, false, "pointers", pointersTo(flatten( - safeFloat32s, - safeFloat64s, - ))) - runTestCases(t, false, "interfaces", interfacesTo(flatten( - safeFloat32s, - safeFloat64s, - ))) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(flatten( - safeFloat32s, - safeFloat64s, - )))) -} - -const onlyDouble float64 = 1.0000000000000002 - -func TestFloatTruncation(t *testing.T) { - runTestCases(t, true, "pass", []interface{}{ - truncatingFloat32{save: onlyDouble}, - }) - runTestCases(t, false, "fail", []interface{}{ - truncatingFloat32{save: 1.0}, - }) -} - -var safeComplex64s = combine(safeFloat32s, safeFloat32s, func(i, j interface{}) interface{} { - return complex(i.(float32), j.(float32)) -}) - -var allComplex64s = combine(allFloat32s, allFloat32s, func(i, j interface{}) interface{} { - return complex(i.(float32), j.(float32)) -}) - -var safeComplex128s = combine(safeFloat64s, safeFloat64s, func(i, j interface{}) interface{} { - return complex(i.(float64), j.(float64)) -}) - -var allComplex128s = combine(allFloat64s, allFloat64s, func(i, j interface{}) interface{} { - return complex(i.(float64), j.(float64)) -}) - -func TestComplex(t *testing.T) { - runTestCases(t, false, "plain", flatten( - allComplex64s, - allComplex128s, - )) - // See TestFloat; same issue. - runTestCases(t, false, "pointers", pointersTo(flatten( - safeComplex64s, - safeComplex128s, - ))) - runTestCases(t, false, "interfacse", interfacesTo(flatten( - safeComplex64s, - safeComplex128s, - ))) - runTestCases(t, false, "interfacesTo", interfacesTo(pointersTo(flatten( - safeComplex64s, - safeComplex128s, - )))) -} - -func TestComplexTruncation(t *testing.T) { - runTestCases(t, true, "pass", []interface{}{ - truncatingComplex64{save: complex(onlyDouble, onlyDouble)}, - truncatingComplex64{save: complex(1.0, onlyDouble)}, - truncatingComplex64{save: complex(onlyDouble, 1.0)}, - }) - runTestCases(t, false, "fail", []interface{}{ - truncatingComplex64{save: complex(1.0, 1.0)}, - }) -} diff --git a/pkg/state/tests/integer.go b/pkg/state/tests/integer.go deleted file mode 100644 index ca403eed1..000000000 --- a/pkg/state/tests/integer.go +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "gvisor.dev/gvisor/pkg/state" -) - -// +stateify type -type truncatingUint8 struct { - save uint64 - load uint8 `state:"nosave"` -} - -func (t *truncatingUint8) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingUint8) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = uint64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingUint8)(nil) - -// +stateify type -type truncatingUint16 struct { - save uint64 - load uint16 `state:"nosave"` -} - -func (t *truncatingUint16) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingUint16) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = uint64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingUint16)(nil) - -// +stateify type -type truncatingUint32 struct { - save uint64 - load uint32 `state:"nosave"` -} - -func (t *truncatingUint32) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingUint32) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = uint64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingUint32)(nil) - -// +stateify type -type truncatingInt8 struct { - save int64 - load int8 `state:"nosave"` -} - -func (t *truncatingInt8) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingInt8) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = int64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingInt8)(nil) - -// +stateify type -type truncatingInt16 struct { - save int64 - load int16 `state:"nosave"` -} - -func (t *truncatingInt16) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingInt16) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = int64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingInt16)(nil) - -// +stateify type -type truncatingInt32 struct { - save int64 - load int32 `state:"nosave"` -} - -func (t *truncatingInt32) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingInt32) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = int64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingInt32)(nil) - -// +stateify type -type truncatingFloat32 struct { - save float64 - load float32 `state:"nosave"` -} - -func (t *truncatingFloat32) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingFloat32) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = float64(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingFloat32)(nil) - -// +stateify type -type truncatingComplex64 struct { - save complex128 - load complex64 `state:"nosave"` -} - -func (t *truncatingComplex64) StateSave(m state.Sink) { - m.Save(0, &t.save) -} - -func (t *truncatingComplex64) StateLoad(m state.Source) { - m.Load(0, &t.load) - t.save = complex128(t.load) - t.load = 0 -} - -var _ state.SaverLoader = (*truncatingComplex64)(nil) diff --git a/pkg/state/tests/integer_test.go b/pkg/state/tests/integer_test.go deleted file mode 100644 index 2b1609af0..000000000 --- a/pkg/state/tests/integer_test.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "math" - "testing" -) - -var ( - allBasicInts = []int{-1, 0, 1} - allInt8s = []int8{math.MinInt8, -1, 0, 1, math.MaxInt8} - allInt16s = []int16{math.MinInt16, -1, 0, 1, math.MaxInt16} - allInt32s = []int32{math.MinInt32, -1, 0, 1, math.MaxInt32} - allInt64s = []int64{math.MinInt64, -1, 0, 1, math.MaxInt64} - allBasicUints = []uint{0, 1} - allUintptrs = []uintptr{0, 1, ^uintptr(0)} - allUint8s = []uint8{0, 1, math.MaxUint8} - allUint16s = []uint16{0, 1, math.MaxUint16} - allUint32s = []uint32{0, 1, math.MaxUint32} - allUint64s = []uint64{0, 1, math.MaxUint64} -) - -var allInts = flatten( - allBasicInts, - allInt8s, - allInt16s, - allInt32s, - allInt64s, -) - -var allUints = flatten( - allBasicUints, - allUintptrs, - allUint8s, - allUint16s, - allUint32s, - allUint64s, -) - -func TestInt(t *testing.T) { - runTestCases(t, false, "plain", allInts) - runTestCases(t, false, "pointers", pointersTo(allInts)) - runTestCases(t, false, "interfaces", interfacesTo(allInts)) - runTestCases(t, false, "interfacesTo", interfacesTo(pointersTo(allInts))) -} - -func TestIntTruncation(t *testing.T) { - runTestCases(t, true, "pass", []interface{}{ - truncatingInt8{save: math.MinInt8 - 1}, - truncatingInt16{save: math.MinInt16 - 1}, - truncatingInt32{save: math.MinInt32 - 1}, - truncatingInt8{save: math.MaxInt8 + 1}, - truncatingInt16{save: math.MaxInt16 + 1}, - truncatingInt32{save: math.MaxInt32 + 1}, - }) - runTestCases(t, false, "fail", []interface{}{ - truncatingInt8{save: 1}, - truncatingInt16{save: 1}, - truncatingInt32{save: 1}, - }) -} - -func TestUint(t *testing.T) { - runTestCases(t, false, "plain", allUints) - runTestCases(t, false, "pointers", pointersTo(allUints)) - runTestCases(t, false, "interfaces", interfacesTo(allUints)) - runTestCases(t, false, "interfacesTo", interfacesTo(pointersTo(allUints))) -} - -func TestUintTruncation(t *testing.T) { - runTestCases(t, true, "pass", []interface{}{ - truncatingUint8{save: math.MaxUint8 + 1}, - truncatingUint16{save: math.MaxUint16 + 1}, - truncatingUint32{save: math.MaxUint32 + 1}, - }) - runTestCases(t, false, "fail", []interface{}{ - truncatingUint8{save: 1}, - truncatingUint16{save: 1}, - truncatingUint32{save: 1}, - }) -} diff --git a/pkg/state/tests/load.go b/pkg/state/tests/load.go deleted file mode 100644 index a8350c0f3..000000000 --- a/pkg/state/tests/load.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -// +stateify savable -type genericContainer struct { - v interface{} -} - -// +stateify savable -type afterLoadStruct struct { - v int `state:"nosave"` -} - -func (a *afterLoadStruct) afterLoad() { - a.v++ -} - -// +stateify savable -type valueLoadStruct struct { - v int `state:".(int64)"` -} - -func (v *valueLoadStruct) saveV() int64 { - return int64(v.v) // Save as int64. -} - -func (v *valueLoadStruct) loadV(value int64) { - v.v = int(value) // Load as int. -} - -// +stateify savable -type cycleStruct struct { - c *cycleStruct -} - -// +stateify savable -type badCycleStruct struct { - b *badCycleStruct `state:"wait"` -} - -func (b *badCycleStruct) afterLoad() { - if b.b != b { - // This is not executable, since AfterLoad requires that the - // object and all dependencies are complete. This should cause - // a deadlock error during load. - panic("badCycleStruct.afterLoad called") - } -} diff --git a/pkg/state/tests/load_test.go b/pkg/state/tests/load_test.go deleted file mode 100644 index 3c73ac391..000000000 --- a/pkg/state/tests/load_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "testing" -) - -func TestLoadHooks(t *testing.T) { - runTestCases(t, false, "load-hooks", []interface{}{ - // Root object being a struct. - afterLoadStruct{v: 1}, - valueLoadStruct{v: 1}, - genericContainer{v: &afterLoadStruct{v: 1}}, - genericContainer{v: &valueLoadStruct{v: 1}}, - sliceContainer{v: []interface{}{&afterLoadStruct{v: 1}}}, - sliceContainer{v: []interface{}{&valueLoadStruct{v: 1}}}, - // Root object being a pointer. - &afterLoadStruct{v: 1}, - &valueLoadStruct{v: 1}, - &genericContainer{v: &afterLoadStruct{v: 1}}, - &genericContainer{v: &valueLoadStruct{v: 1}}, - &sliceContainer{v: []interface{}{&afterLoadStruct{v: 1}}}, - &sliceContainer{v: []interface{}{&valueLoadStruct{v: 1}}}, - &mapContainer{v: map[int]interface{}{0: &afterLoadStruct{v: 1}}}, - &mapContainer{v: map[int]interface{}{0: &valueLoadStruct{v: 1}}}, - }) -} - -func TestCycles(t *testing.T) { - // cs is a single object cycle. - cs := cycleStruct{nil} - cs.c = &cs - - // cs1 and cs2 are in a two object cycle. - cs1 := cycleStruct{nil} - cs2 := cycleStruct{nil} - cs1.c = &cs2 - cs2.c = &cs1 - - runTestCases(t, false, "cycles", []interface{}{ - cs, - cs1, - }) -} - -func TestDeadlock(t *testing.T) { - // bs is a single object cycle. This does not cause deadlock because an - // object cannot wait for itself. - bs := badCycleStruct{nil} - bs.b = &bs - - runTestCases(t, false, "self", []interface{}{ - &bs, - }) - - // bs2 and bs2 are in a deadlocking cycle. - bs1 := badCycleStruct{nil} - bs2 := badCycleStruct{nil} - bs1.b = &bs2 - bs2.b = &bs1 - - runTestCases(t, true, "deadlock", []interface{}{ - &bs1, - }) -} diff --git a/pkg/state/tests/map.go b/pkg/state/tests/map.go deleted file mode 100644 index db4e548f1..000000000 --- a/pkg/state/tests/map.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -// +stateify savable -type mapContainer struct { - v map[int]interface{} -} - -// +stateify savable -type mapPtrContainer struct { - v *map[int]interface{} -} - -// +stateify savable -type registeredMapStruct struct{} diff --git a/pkg/state/tests/map_test.go b/pkg/state/tests/map_test.go deleted file mode 100644 index 92bf0fc01..000000000 --- a/pkg/state/tests/map_test.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "reflect" - "testing" -) - -var allMapPrimitives = []interface{}{ - bool(true), - int(1), - int8(1), - int16(1), - int32(1), - int64(1), - uint(1), - uintptr(1), - uint8(1), - uint16(1), - uint32(1), - uint64(1), - string(""), - registeredMapStruct{}, -} - -var allMapKeys = flatten(allMapPrimitives, pointersTo(allMapPrimitives)) - -var allMapValues = flatten(allMapPrimitives, pointersTo(allMapPrimitives), interfacesTo(allMapPrimitives)) - -var emptyMaps = combine(allMapKeys, allMapValues, func(v1, v2 interface{}) interface{} { - m := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(v1), reflect.TypeOf(v2))) - return m.Interface() -}) - -var fullMaps = combine(allMapKeys, allMapValues, func(v1, v2 interface{}) interface{} { - m := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(v1), reflect.TypeOf(v2))) - m.SetMapIndex(reflect.Zero(reflect.TypeOf(v1)), reflect.Zero(reflect.TypeOf(v2))) - return m.Interface() -}) - -func TestMapAliasing(t *testing.T) { - v := make(map[int]int) - ptrToV := &v - aliases := []map[int]int{v, v} - runTestCases(t, false, "", []interface{}{ptrToV, aliases}) -} - -func TestMapsEmpty(t *testing.T) { - runTestCases(t, false, "plain", emptyMaps) - runTestCases(t, false, "pointers", pointersTo(emptyMaps)) - runTestCases(t, false, "interfaces", interfacesTo(emptyMaps)) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(emptyMaps))) -} - -func TestMapsFull(t *testing.T) { - runTestCases(t, false, "plain", fullMaps) - runTestCases(t, false, "pointers", pointersTo(fullMaps)) - runTestCases(t, false, "interfaces", interfacesTo(fullMaps)) - runTestCases(t, false, "interfacesToPointer", interfacesTo(pointersTo(fullMaps))) -} - -func TestMapContainers(t *testing.T) { - var ( - nilMap map[int]interface{} - emptyMap = make(map[int]interface{}) - fullMap = map[int]interface{}{0: nil} - ) - runTestCases(t, false, "", []interface{}{ - mapContainer{v: nilMap}, - mapContainer{v: emptyMap}, - mapContainer{v: fullMap}, - mapPtrContainer{v: nil}, - mapPtrContainer{v: &nilMap}, - mapPtrContainer{v: &emptyMap}, - mapPtrContainer{v: &fullMap}, - }) -} diff --git a/pkg/state/tests/register.go b/pkg/state/tests/register.go deleted file mode 100644 index 074d86315..000000000 --- a/pkg/state/tests/register.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -// +stateify savable -type alreadyRegisteredStruct struct{} - -// +stateify savable -type alreadyRegisteredOther int diff --git a/pkg/state/tests/register_test.go b/pkg/state/tests/register_test.go deleted file mode 100644 index 75bdbfc6e..000000000 --- a/pkg/state/tests/register_test.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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. - -// +build race - -package tests - -import ( - "testing" - - "gvisor.dev/gvisor/pkg/state" -) - -// faker calls itself whatever is in the name field. -type faker struct { - Name string - Fields []string -} - -func (f *faker) StateTypeName() string { - return f.Name -} - -func (f *faker) StateFields() []string { - return f.Fields -} - -// fakerWithSaverLoader has all it needs. -type fakerWithSaverLoader struct { - faker -} - -func (f *fakerWithSaverLoader) StateSave(m state.Sink) {} - -func (f *fakerWithSaverLoader) StateLoad(m state.Source) {} - -// fakerOther calls itself .. uh, itself? -type fakerOther string - -func (f *fakerOther) StateTypeName() string { - return string(*f) -} - -func (f *fakerOther) StateFields() []string { - return nil -} - -func newFakerOther(name string) *fakerOther { - f := fakerOther(name) - return &f -} - -// fakerOtherBadFields returns non-nil fields. -type fakerOtherBadFields string - -func (f *fakerOtherBadFields) StateTypeName() string { - return string(*f) -} - -func (f *fakerOtherBadFields) StateFields() []string { - return []string{string(*f)} -} - -func newFakerOtherBadFields(name string) *fakerOtherBadFields { - f := fakerOtherBadFields(name) - return &f -} - -// fakerOtherSaverLoader implements SaverLoader methods. -type fakerOtherSaverLoader string - -func (f *fakerOtherSaverLoader) StateTypeName() string { - return string(*f) -} - -func (f *fakerOtherSaverLoader) StateFields() []string { - return nil -} - -func (f *fakerOtherSaverLoader) StateSave(m state.Sink) {} - -func (f *fakerOtherSaverLoader) StateLoad(m state.Source) {} - -func newFakerOtherSaverLoader(name string) *fakerOtherSaverLoader { - f := fakerOtherSaverLoader(name) - return &f -} - -func TestRegisterPrimitives(t *testing.T) { - for _, typeName := range []string{ - "int", - "int8", - "int16", - "int32", - "int64", - "uint", - "uintptr", - "uint8", - "uint16", - "uint32", - "uint64", - "float32", - "float64", - "complex64", - "complex128", - "string", - } { - t.Run("struct/"+typeName, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Registering type %q did not panic", typeName) - } - }() - state.Register(&faker{ - Name: typeName, - }) - }) - t.Run("other/"+typeName, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Registering type %q did not panic", typeName) - } - }() - state.Register(newFakerOther(typeName)) - }) - } -} - -func TestRegisterBad(t *testing.T) { - const ( - goodName = "foo" - firstField = "a" - secondField = "b" - ) - for name, object := range map[string]state.Type{ - "non-struct-with-fields": newFakerOtherBadFields(goodName), - "non-struct-with-saverloader": newFakerOtherSaverLoader(goodName), - "struct-without-saverloader": &faker{Name: goodName}, - "non-struct-duplicate-with-struct": newFakerOther((new(alreadyRegisteredStruct)).StateTypeName()), - "non-struct-duplicate-with-non-struct": newFakerOther((new(alreadyRegisteredOther)).StateTypeName()), - "struct-duplicate-with-struct": &fakerWithSaverLoader{faker{Name: (new(alreadyRegisteredStruct)).StateTypeName()}}, - "struct-duplicate-with-non-struct": &fakerWithSaverLoader{faker{Name: (new(alreadyRegisteredOther)).StateTypeName()}}, - "struct-with-empty-field": &fakerWithSaverLoader{faker{Name: goodName, Fields: []string{""}}}, - "struct-with-empty-field-and-non-empty": &fakerWithSaverLoader{faker{Name: goodName, Fields: []string{firstField, ""}}}, - "struct-with-duplicate-field": &fakerWithSaverLoader{faker{Name: goodName, Fields: []string{firstField, firstField}}}, - "struct-with-duplicate-field-and-non-dup": &fakerWithSaverLoader{faker{Name: goodName, Fields: []string{firstField, secondField, firstField}}}, - } { - t.Run(name, func(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Registering object %#v did not panic", object) - } - }() - state.Register(object) - }) - - } -} - -func TestRegisterTypeOnlyStruct(t *testing.T) { - defer func() { - if r := recover(); r == nil { - t.Errorf("Register did not panic") - } - }() - state.Register((*typeOnlyEmptyStruct)(nil)) -} diff --git a/pkg/state/tests/string_test.go b/pkg/state/tests/string_test.go deleted file mode 100644 index 44f5a562c..000000000 --- a/pkg/state/tests/string_test.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "testing" -) - -const nonEmptyString = "hello world" - -var allStrings = []string{ - "", - nonEmptyString, - "\\0", -} - -func TestString(t *testing.T) { - runTestCases(t, false, "plain", flatten(allStrings)) - runTestCases(t, false, "pointers", pointersTo(flatten(allStrings))) - runTestCases(t, false, "interfaces", interfacesTo(flatten(allStrings))) - runTestCases(t, false, "interfacesToPointers", interfacesTo(pointersTo(flatten(allStrings)))) -} diff --git a/pkg/state/tests/struct.go b/pkg/state/tests/struct.go deleted file mode 100644 index 69143d194..000000000 --- a/pkg/state/tests/struct.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -type unregisteredEmptyStruct struct{} - -// typeOnlyEmptyStruct just implements the state.Type interface. -type typeOnlyEmptyStruct struct{} - -func (*typeOnlyEmptyStruct) StateTypeName() string { return "registeredEmptyStruct" } - -func (*typeOnlyEmptyStruct) StateFields() []string { return nil } - -// +stateify savable -type savableEmptyStruct struct{} - -// +stateify savable -type emptyStructPointer struct { - nothing *struct{} -} - -// +stateify savable -type outerSame struct { - inner inner -} - -// +stateify savable -type outerFieldFirst struct { - inner inner - v int64 -} - -// +stateify savable -type outerFieldSecond struct { - v int64 - inner inner -} - -// +stateify savable -type outerArray struct { - inner [2]inner -} - -// +stateify savable -type outerSlice struct { - inner []inner -} - -// +stateify savable -type inner struct { - v int64 -} - -// +stateify savable -type outerFieldValue struct { - inner innerFieldValue -} - -// +stateify savable -type innerFieldValue struct { - v int64 `state:".(*savedFieldValue)"` -} - -// +stateify savable -type savedFieldValue struct { - v int64 -} - -func (ifv *innerFieldValue) saveV() *savedFieldValue { - return &savedFieldValue{ifv.v} -} - -func (ifv *innerFieldValue) loadV(sfv *savedFieldValue) { - ifv.v = sfv.v -} - -// +stateify savable -type system struct { - v1 interface{} - v2 interface{} -} - -// +stateify savable -type system3 struct { - v1 interface{} - v2 interface{} - v3 interface{} -} diff --git a/pkg/state/tests/struct_test.go b/pkg/state/tests/struct_test.go deleted file mode 100644 index 9826f1ee9..000000000 --- a/pkg/state/tests/struct_test.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests - -import ( - "math/rand" - "testing" -) - -func TestEmptyStruct(t *testing.T) { - runTestCases(t, false, "plain", []interface{}{ - unregisteredEmptyStruct{}, - typeOnlyEmptyStruct{}, - savableEmptyStruct{}, - }) - runTestCases(t, false, "pointers", pointersTo([]interface{}{ - unregisteredEmptyStruct{}, - typeOnlyEmptyStruct{}, - savableEmptyStruct{}, - })) - runTestCases(t, false, "interfaces-pass", interfacesTo([]interface{}{ - // Only registered types can be dispatched via interfaces. All - // other types should fail, even if it is the empty struct. - savableEmptyStruct{}, - })) - runTestCases(t, true, "interfaces-fail", interfacesTo([]interface{}{ - unregisteredEmptyStruct{}, - typeOnlyEmptyStruct{}, - })) - runTestCases(t, false, "interfacesToPointers-pass", interfacesTo(pointersTo([]interface{}{ - savableEmptyStruct{}, - }))) - runTestCases(t, true, "interfacesToPointers-fail", interfacesTo(pointersTo([]interface{}{ - unregisteredEmptyStruct{}, - typeOnlyEmptyStruct{}, - }))) - - // Ensuring empty struct aliasing works. - es := emptyStructPointer{new(struct{})} - runTestCases(t, false, "empty-struct-pointers", []interface{}{ - emptyStructPointer{}, - es, - []emptyStructPointer{es, es}, // Same pointer. - }) -} - -func TestEmbeddedPointers(t *testing.T) { - // Give each int64 a random value to prevent Go from using - // runtime.staticuint64s, which confounds tests for struct duplication. - magic := func() int64 { - for { - n := rand.Int63() - if n < 0 || n > 255 { - return n - } - } - } - - ofs := outerSame{inner{magic()}} - of1 := outerFieldFirst{inner{magic()}, magic()} - of2 := outerFieldSecond{magic(), inner{magic()}} - oa := outerArray{[2]inner{{magic()}, {magic()}}} - osl := outerSlice{oa.inner[:]} - ofv := outerFieldValue{innerFieldValue{magic()}} - - runTestCases(t, false, "embedded-pointers", []interface{}{ - system{&ofs, &ofs.inner}, - system{&ofs.inner, &ofs}, - system{&of1, &of1.inner}, - system{&of1.inner, &of1}, - system{&of2, &of2.inner}, - system{&of2.inner, &of2}, - system{&oa, &oa.inner[0]}, - system{&oa, &oa.inner[1]}, - system{&oa.inner[0], &oa}, - system{&oa.inner[1], &oa}, - system3{&oa, &oa.inner[0], &oa.inner[1]}, - system3{&oa, &oa.inner[1], &oa.inner[0]}, - system3{&oa.inner[0], &oa, &oa.inner[1]}, - system3{&oa.inner[1], &oa, &oa.inner[0]}, - system3{&oa.inner[0], &oa.inner[1], &oa}, - system3{&oa.inner[1], &oa.inner[0], &oa}, - system{&oa, &osl}, - system{&osl, &oa}, - system{&ofv, &ofv.inner}, - system{&ofv.inner, &ofv}, - }) -} diff --git a/pkg/state/tests/tests.go b/pkg/state/tests/tests.go deleted file mode 100644 index 435a0e9db..000000000 --- a/pkg/state/tests/tests.go +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// 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 tests tests the state packages. -package tests - -import ( - "bytes" - "context" - "fmt" - "math" - "reflect" - "testing" - - "gvisor.dev/gvisor/pkg/state" - "gvisor.dev/gvisor/pkg/state/pretty" -) - -// discard is an implementation of wire.Writer. -type discard struct{} - -// Write implements wire.Writer.Write. -func (discard) Write(p []byte) (int, error) { return len(p), nil } - -// WriteByte implements wire.Writer.WriteByte. -func (discard) WriteByte(byte) error { return nil } - -// checkEqual checks if two objects are equal. -// -// N.B. This only handles one level of dereferences for NaN. Otherwise we -// would need to fork the entire implementation of reflect.DeepEqual. -func checkEqual(root, loadedValue interface{}) bool { - if reflect.DeepEqual(root, loadedValue) { - return true - } - - // NaN is not equal to itself. We handle the case of raw floating point - // primitives here, but don't handle this case nested. - rf32, ok1 := root.(float32) - lf32, ok2 := loadedValue.(float32) - if ok1 && ok2 && math.IsNaN(float64(rf32)) && math.IsNaN(float64(lf32)) { - return true - } - rf64, ok1 := root.(float64) - lf64, ok2 := loadedValue.(float64) - if ok1 && ok2 && math.IsNaN(rf64) && math.IsNaN(lf64) { - return true - } - - // Same real for complex numbers. - rc64, ok1 := root.(complex64) - lc64, ok2 := root.(complex64) - if ok1 && ok2 { - return checkEqual(real(rc64), real(lc64)) && checkEqual(imag(rc64), imag(lc64)) - } - rc128, ok1 := root.(complex128) - lc128, ok2 := root.(complex128) - if ok1 && ok2 { - return checkEqual(real(rc128), real(lc128)) && checkEqual(imag(rc128), imag(lc128)) - } - - return false -} - -// runTestCases runs a test for each object in objects. -func runTestCases(t *testing.T, shouldFail bool, prefix string, objects []interface{}) { - t.Helper() - for i, root := range objects { - t.Run(fmt.Sprintf("%s%d", prefix, i), func(t *testing.T) { - t.Logf("Original object:\n%#v", root) - - // Save the passed object. - saveBuffer := &bytes.Buffer{} - saveObjectPtr := reflect.New(reflect.TypeOf(root)) - saveObjectPtr.Elem().Set(reflect.ValueOf(root)) - saveStats, err := state.Save(context.Background(), saveBuffer, saveObjectPtr.Interface()) - if err != nil { - if shouldFail { - return - } - t.Fatalf("Save failed unexpectedly: %v", err) - } - - // Dump the serialized proto to aid with debugging. - var ppBuf bytes.Buffer - t.Logf("Raw state:\n%v", saveBuffer.Bytes()) - if err := pretty.PrintText(&ppBuf, bytes.NewReader(saveBuffer.Bytes())); err != nil { - // We don't count this as a test failure if we - // have shouldFail set, but we will count as a - // failure if we were not expecting to fail. - if !shouldFail { - t.Errorf("PrettyPrint(html=false) failed unexpected: %v", err) - } - } - if err := pretty.PrintHTML(discard{}, bytes.NewReader(saveBuffer.Bytes())); err != nil { - // See above. - if !shouldFail { - t.Errorf("PrettyPrint(html=true) failed unexpected: %v", err) - } - } - t.Logf("Encoded state:\n%s", ppBuf.String()) - t.Logf("Save stats:\n%s", saveStats.String()) - - // Load a new copy of the object. - loadObjectPtr := reflect.New(reflect.TypeOf(root)) - loadStats, err := state.Load(context.Background(), bytes.NewReader(saveBuffer.Bytes()), loadObjectPtr.Interface()) - if err != nil { - if shouldFail { - return - } - t.Fatalf("Load failed unexpectedly: %v", err) - } - - // Compare the values. - loadedValue := loadObjectPtr.Elem().Interface() - if !checkEqual(root, loadedValue) { - if shouldFail { - return - } - t.Fatalf("Objects differ:\n\toriginal: %#v\n\tloaded: %#v\n", root, loadedValue) - } - - // Everything went okay. Is that good? - if shouldFail { - t.Fatalf("This test was expected to fail, but didn't.") - } - t.Logf("Load stats:\n%s", loadStats.String()) - - // Truncate half the bytes in the byte stream, - // and ensure that we can't restore. Then - // truncate only the final byte and ensure that - // we can't restore. - l := saveBuffer.Len() - halfReader := bytes.NewReader(saveBuffer.Bytes()[:l/2]) - if _, err := state.Load(context.Background(), halfReader, loadObjectPtr.Interface()); err == nil { - t.Errorf("Load with half bytes succeeded unexpectedly.") - } - missingByteReader := bytes.NewReader(saveBuffer.Bytes()[:l-1]) - if _, err := state.Load(context.Background(), missingByteReader, loadObjectPtr.Interface()); err == nil { - t.Errorf("Load with missing byte succeeded unexpectedly.") - } - }) - } -} - -// convert converts the slice to an []interface{}. -func convert(v interface{}) (r []interface{}) { - s := reflect.ValueOf(v) // Must be slice. - for i := 0; i < s.Len(); i++ { - r = append(r, s.Index(i).Interface()) - } - return r -} - -// flatten flattens multiple slices. -func flatten(vs ...interface{}) (r []interface{}) { - for _, v := range vs { - r = append(r, convert(v)...) - } - return r -} - -// filter maps from one slice to another. -func filter(vs interface{}, fn func(interface{}) (interface{}, bool)) (r []interface{}) { - s := reflect.ValueOf(vs) - for i := 0; i < s.Len(); i++ { - v, ok := fn(s.Index(i).Interface()) - if ok { - r = append(r, v) - } - } - return r -} - -// combine combines objects in two slices as specified. -func combine(v1, v2 interface{}, fn func(_, _ interface{}) interface{}) (r []interface{}) { - s1 := reflect.ValueOf(v1) - s2 := reflect.ValueOf(v2) - for i := 0; i < s1.Len(); i++ { - for j := 0; j < s2.Len(); j++ { - // Combine using the given function. - r = append(r, fn(s1.Index(i).Interface(), s2.Index(j).Interface())) - } - } - return r -} - -// pointersTo is a filter function that returns pointers. -func pointersTo(vs interface{}) []interface{} { - return filter(vs, func(o interface{}) (interface{}, bool) { - v := reflect.New(reflect.TypeOf(o)) - v.Elem().Set(reflect.ValueOf(o)) - return v.Interface(), true - }) -} - -// interfacesTo is a filter function that returns interface objects. -func interfacesTo(vs interface{}) []interface{} { - return filter(vs, func(o interface{}) (interface{}, bool) { - var v [1]interface{} - v[0] = o - return v, true - }) -} |