Skip to content

Commit f88d189

Browse files
authored
Merge pull request #104 from apelisse/improve-tests
Various benchmarks improvements
2 parents ef97d8f + 13c65a2 commit f88d189

File tree

6 files changed

+268
-11
lines changed

6 files changed

+268
-11
lines changed

internal/fixture/state.go

Lines changed: 128 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,11 @@ func (s *State) checkInit() error {
8080
return nil
8181
}
8282

83-
// Update the current state with the passed in object
84-
func (s *State) Update(obj typed.YAMLObject, version fieldpath.APIVersion, manager string) error {
85-
obj = FixTabsOrDie(obj)
86-
if err := s.checkInit(); err != nil {
83+
func (s *State) UpdateObject(tv *typed.TypedValue, version fieldpath.APIVersion, manager string) error {
84+
err := s.checkInit()
85+
if err != nil {
8786
return err
8887
}
89-
tv, err := s.Parser.FromYAML(obj)
9088
s.Live, err = s.Updater.Converter.Convert(s.Live, version)
9189
if err != nil {
9290
return err
@@ -101,13 +99,17 @@ func (s *State) Update(obj typed.YAMLObject, version fieldpath.APIVersion, manag
10199
return nil
102100
}
103101

104-
// Apply the passed in object to the current state
105-
func (s *State) Apply(obj typed.YAMLObject, version fieldpath.APIVersion, manager string, force bool) error {
106-
obj = FixTabsOrDie(obj)
107-
if err := s.checkInit(); err != nil {
102+
// Update the current state with the passed in object
103+
func (s *State) Update(obj typed.YAMLObject, version fieldpath.APIVersion, manager string) error {
104+
tv, err := s.Parser.FromYAML(FixTabsOrDie(obj))
105+
if err != nil {
108106
return err
109107
}
110-
tv, err := s.Parser.FromYAML(obj)
108+
return s.UpdateObject(tv, version, manager)
109+
}
110+
111+
func (s *State) ApplyObject(tv *typed.TypedValue, version fieldpath.APIVersion, manager string, force bool) error {
112+
err := s.checkInit()
111113
if err != nil {
112114
return err
113115
}
@@ -125,6 +127,15 @@ func (s *State) Apply(obj typed.YAMLObject, version fieldpath.APIVersion, manage
125127
return nil
126128
}
127129

130+
// Apply the passed in object to the current state
131+
func (s *State) Apply(obj typed.YAMLObject, version fieldpath.APIVersion, manager string, force bool) error {
132+
tv, err := s.Parser.FromYAML(FixTabsOrDie(obj))
133+
if err != nil {
134+
return err
135+
}
136+
return s.ApplyObject(tv, version, manager, force)
137+
}
138+
128139
// CompareLive takes a YAML string and returns the comparison with the
129140
// current live object or an error.
130141
func (s *State) CompareLive(obj typed.YAMLObject) (*typed.Comparison, error) {
@@ -159,6 +170,7 @@ func (dummyConverter) IsMissingVersionError(err error) bool {
159170
// Operation is a step that will run when building a table-driven test.
160171
type Operation interface {
161172
run(*State) error
173+
preprocess(typed.ParseableType) (Operation, error)
162174
}
163175

164176
func hasConflict(conflicts merge.Conflicts, conflict merge.Conflict) bool {
@@ -194,7 +206,37 @@ type Apply struct {
194206
var _ Operation = &Apply{}
195207

196208
func (a Apply) run(state *State) error {
197-
err := state.Apply(a.Object, a.APIVersion, a.Manager, false)
209+
p, err := a.preprocess(state.Parser)
210+
if err != nil {
211+
return err
212+
}
213+
return p.run(state)
214+
}
215+
216+
func (a Apply) preprocess(parser typed.ParseableType) (Operation, error) {
217+
tv, err := parser.FromYAML(FixTabsOrDie(a.Object))
218+
if err != nil {
219+
return nil, err
220+
}
221+
return ApplyObject{
222+
Manager: a.Manager,
223+
APIVersion: a.APIVersion,
224+
Object: tv,
225+
Conflicts: a.Conflicts,
226+
}, nil
227+
}
228+
229+
type ApplyObject struct {
230+
Manager string
231+
APIVersion fieldpath.APIVersion
232+
Object *typed.TypedValue
233+
Conflicts merge.Conflicts
234+
}
235+
236+
var _ Operation = &ApplyObject{}
237+
238+
func (a ApplyObject) run(state *State) error {
239+
err := state.ApplyObject(a.Object, a.APIVersion, a.Manager, false)
198240
if err != nil {
199241
if _, ok := err.(merge.Conflicts); !ok || a.Conflicts == nil {
200242
return err
@@ -215,7 +257,10 @@ func (a Apply) run(state *State) error {
215257
}
216258
}
217259
return nil
260+
}
218261

262+
func (a ApplyObject) preprocess(parser typed.ParseableType) (Operation, error) {
263+
return a, nil
219264
}
220265

221266
// ForceApply is a type of operation. It is a forced-apply run by a
@@ -232,6 +277,36 @@ func (f ForceApply) run(state *State) error {
232277
return state.Apply(f.Object, f.APIVersion, f.Manager, true)
233278
}
234279

280+
func (f ForceApply) preprocess(parser typed.ParseableType) (Operation, error) {
281+
tv, err := parser.FromYAML(FixTabsOrDie(f.Object))
282+
if err != nil {
283+
return nil, err
284+
}
285+
return ForceApplyObject{
286+
Manager: f.Manager,
287+
APIVersion: f.APIVersion,
288+
Object: tv,
289+
}, nil
290+
}
291+
292+
// ForceApplyObject is a type of operation. It is a forced-apply run by
293+
// a manager with a given object. Any error will be returned.
294+
type ForceApplyObject struct {
295+
Manager string
296+
APIVersion fieldpath.APIVersion
297+
Object *typed.TypedValue
298+
}
299+
300+
var _ Operation = &ForceApplyObject{}
301+
302+
func (f ForceApplyObject) run(state *State) error {
303+
return state.ApplyObject(f.Object, f.APIVersion, f.Manager, true)
304+
}
305+
306+
func (f ForceApplyObject) preprocess(parser typed.ParseableType) (Operation, error) {
307+
return f, nil
308+
}
309+
235310
// Update is a type of operation. It is a controller type of
236311
// update. Errors are passed along.
237312
type Update struct {
@@ -246,6 +321,36 @@ func (u Update) run(state *State) error {
246321
return state.Update(u.Object, u.APIVersion, u.Manager)
247322
}
248323

324+
func (u Update) preprocess(parser typed.ParseableType) (Operation, error) {
325+
tv, err := parser.FromYAML(FixTabsOrDie(u.Object))
326+
if err != nil {
327+
return nil, err
328+
}
329+
return UpdateObject{
330+
Manager: u.Manager,
331+
APIVersion: u.APIVersion,
332+
Object: tv,
333+
}, nil
334+
}
335+
336+
// UpdateObject is a type of operation. It is a controller type of
337+
// update. Errors are passed along.
338+
type UpdateObject struct {
339+
Manager string
340+
APIVersion fieldpath.APIVersion
341+
Object *typed.TypedValue
342+
}
343+
344+
var _ Operation = &Update{}
345+
346+
func (u UpdateObject) run(state *State) error {
347+
return state.UpdateObject(u.Object, u.APIVersion, u.Manager)
348+
}
349+
350+
func (f UpdateObject) preprocess(parser typed.ParseableType) (Operation, error) {
351+
return f, nil
352+
}
353+
249354
// TestCase is the list of operations that need to be run, as well as
250355
// the object/managedfields as they are supposed to look like after all
251356
// the operations have been successfully performed. If Object/Managed is
@@ -276,6 +381,18 @@ func (tc TestCase) Bench(parser typed.ParseableType) error {
276381
return tc.BenchWithConverter(parser, &dummyConverter{})
277382
}
278383

384+
// Preprocess all the operations by parsing the yaml before-hand.
385+
func (tc TestCase) PreprocessOperations(parser typed.ParseableType) error {
386+
for i := range tc.Ops {
387+
op, err := tc.Ops[i].preprocess(parser)
388+
if err != nil {
389+
return err
390+
}
391+
tc.Ops[i] = op
392+
}
393+
return nil
394+
}
395+
279396
// BenchWithConverter runs the test-case using the given parser and converter,
280397
// but doesn't do any comparison operations aftewards; you should probably run
281398
// TestWithConverter once and reset the benchmark, to make sure the test case

merge/deduced_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ func BenchmarkDeducedSimple(b *testing.B) {
603603
b.Fatal(err)
604604
}
605605

606+
test.PreprocessOperations(typed.DeducedParseableType)
607+
606608
b.ReportAllocs()
607609
b.ResetTimer()
608610
for n := 0; n < b.N; n++ {
@@ -712,6 +714,8 @@ func BenchmarkDeducedNested(b *testing.B) {
712714
b.Fatal(err)
713715
}
714716

717+
test.PreprocessOperations(typed.DeducedParseableType)
718+
715719
b.ReportAllocs()
716720
b.ResetTimer()
717721
for n := 0; n < b.N; n++ {
@@ -821,6 +825,8 @@ func BenchmarkDeducedNestedAcrossVersion(b *testing.B) {
821825
b.Fatal(err)
822826
}
823827

828+
test.PreprocessOperations(typed.DeducedParseableType)
829+
824830
b.ReportAllocs()
825831
b.ResetTimer()
826832
for n := 0; n < b.N; n++ {

merge/leaf_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,8 @@ func BenchmarkLeafConflictAcrossVersion(b *testing.B) {
536536
b.Fatal(err)
537537
}
538538

539+
test.PreprocessOperations(leafFieldsParser)
540+
539541
b.ReportAllocs()
540542
b.ResetTimer()
541543
for n := 0; n < b.N; n++ {

merge/multiple_appliers_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,8 @@ func BenchmarkMultipleApplierRecursiveRealConversion(b *testing.B) {
11081108
b.Fatal(err)
11091109
}
11101110

1111+
test.PreprocessOperations(nestedTypeParser)
1112+
11111113
b.ReportAllocs()
11121114
b.ResetTimer()
11131115
for n := 0; n < b.N; n++ {

merge/pod_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package merge_test
18+
19+
import (
20+
"io/ioutil"
21+
"path/filepath"
22+
"testing"
23+
24+
. "sigs.k8s.io/structured-merge-diff/internal/fixture"
25+
"sigs.k8s.io/structured-merge-diff/typed"
26+
)
27+
28+
func testdata(file string) string {
29+
return filepath.Join("..", "internal", "testdata", file)
30+
}
31+
32+
func read(file string) []byte {
33+
s, err := ioutil.ReadFile(file)
34+
if err != nil {
35+
panic(err)
36+
}
37+
return s
38+
}
39+
40+
var podParser = func() typed.ParseableType {
41+
s := read(testdata("k8s-schema.yaml"))
42+
parser, err := typed.NewParser(typed.YAMLObject(s))
43+
if err != nil {
44+
panic(err)
45+
}
46+
return parser.Type("io.k8s.api.core.v1.Pod")
47+
}()
48+
49+
func BenchmarkPodUpdates(b *testing.B) {
50+
test := TestCase{
51+
Ops: []Operation{
52+
Update{
53+
Manager: "controller",
54+
APIVersion: "v1",
55+
Object: typed.YAMLObject(read(testdata("pod.yaml"))),
56+
},
57+
},
58+
}
59+
60+
test.PreprocessOperations(podParser)
61+
62+
b.ReportAllocs()
63+
b.ResetTimer()
64+
for n := 0; n < b.N; n++ {
65+
if err := test.Bench(podParser); err != nil {
66+
b.Fatal(err)
67+
}
68+
}
69+
}

typed/parser_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package typed_test
18+
19+
import (
20+
"io/ioutil"
21+
"path/filepath"
22+
"testing"
23+
24+
yaml "gopkg.in/yaml.v2"
25+
"sigs.k8s.io/structured-merge-diff/typed"
26+
)
27+
28+
func testdata(file string) string {
29+
return filepath.Join("..", "internal", "testdata", file)
30+
}
31+
32+
func BenchmarkFromUnstructured(b *testing.B) {
33+
pod, err := ioutil.ReadFile(testdata("pod.yaml"))
34+
if err != nil {
35+
b.Fatal(err)
36+
}
37+
38+
s, err := ioutil.ReadFile(testdata("k8s-schema.yaml"))
39+
if err != nil {
40+
b.Fatal(err)
41+
}
42+
parser, err := typed.NewParser(typed.YAMLObject(s))
43+
if err != nil {
44+
b.Fatal(err)
45+
}
46+
pt := parser.Type("io.k8s.api.core.v1.Pod")
47+
48+
obj := map[string]interface{}{}
49+
if err := yaml.Unmarshal([]byte(pod), &obj); err != nil {
50+
b.Fatal(err)
51+
}
52+
53+
b.ReportAllocs()
54+
b.ResetTimer()
55+
for n := 0; n < b.N; n++ {
56+
if _, err := pt.FromUnstructured(obj); err != nil {
57+
b.Fatal(err)
58+
}
59+
}
60+
61+
}

0 commit comments

Comments
 (0)