Skip to content

Commit e9173f4

Browse files
author
Antoine Pelisse
committed
Allow eager deserialization in tests
YAML can now be decoded only once and then the same test run multiple times without having to re-deserialize. This is very useful to write benchmarks that don't test yaml performance.
1 parent 960c3cc commit e9173f4

File tree

4 files changed

+138
-11
lines changed

4 files changed

+138
-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++ {

0 commit comments

Comments
 (0)