Skip to content

Commit bc70e0d

Browse files
committed
Add test for changing struct from granular to atomic
1 parent b84068c commit bc70e0d

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

internal/fixture/state.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,33 @@ func (f UpdateObject) preprocess(parser Parser) (Operation, error) {
385385
return f, nil
386386
}
387387

388+
// ChangeParser is a type of operation. It simulates making changes a schema without versioning
389+
// the schema. This can be used to test the behavior of making backward compatible schema changes,
390+
// e.g. setting "elementRelationship: atomic" on an existing struct. It also may be used to ensure
391+
// that backward incompatible changes are detected appropriately.
392+
type ChangeParser struct {
393+
Parser *typed.Parser
394+
}
395+
396+
var _ Operation = &ChangeParser{}
397+
398+
func (cs ChangeParser) run(state *State) error {
399+
state.Parser = cs.Parser
400+
// Swap the schema in for use with the live object so it merges.
401+
// If the schema is incompatible, this will fail validation.
402+
403+
liveWithNewSchema, err := typed.AsTyped(state.Live.AsValue(), &cs.Parser.Schema, state.Live.TypeRef())
404+
if err != nil {
405+
return err
406+
}
407+
state.Live = liveWithNewSchema
408+
return nil
409+
}
410+
411+
func (cs ChangeParser) preprocess(_ Parser) (Operation, error) {
412+
return cs, nil
413+
}
414+
388415
// TestCase is the list of operations that need to be run, as well as
389416
// the object/managedfields as they are supposed to look like after all
390417
// the operations have been successfully performed. If Object/Managed is

merge/schema_change_test.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
Copyright 2018 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+
"testing"
21+
22+
"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
23+
. "sigs.k8s.io/structured-merge-diff/v4/internal/fixture"
24+
"sigs.k8s.io/structured-merge-diff/v4/merge"
25+
"sigs.k8s.io/structured-merge-diff/v4/typed"
26+
)
27+
28+
29+
var structParser = func() *typed.Parser {
30+
oldParser, err := typed.NewParser(`types:
31+
- name: v1
32+
map:
33+
fields:
34+
- name: struct
35+
type:
36+
namedType: struct
37+
- name: struct
38+
map:
39+
fields:
40+
- name: numeric
41+
type:
42+
scalar: numeric
43+
- name: string
44+
type:
45+
scalar: string`)
46+
if err != nil {
47+
panic(err)
48+
}
49+
return oldParser
50+
}()
51+
52+
var structWithAtomicParser = func() *typed.Parser {
53+
newParser, err := typed.NewParser( `types:
54+
- name: v1
55+
map:
56+
fields:
57+
- name: struct
58+
type:
59+
namedType: struct
60+
- name: struct
61+
map:
62+
fields:
63+
- name: numeric
64+
type:
65+
scalar: numeric
66+
- name: string
67+
type:
68+
scalar: string
69+
elementRelationship: atomic`)
70+
if err != nil {
71+
panic(err)
72+
}
73+
return newParser
74+
}()
75+
76+
func TestSchemaChanges(t *testing.T) {
77+
tests := map[string]TestCase{
78+
"change-struct-to-atomic": {
79+
Ops: []Operation{
80+
Apply{
81+
Manager: "one",
82+
Object: `
83+
struct:
84+
numeric: 1
85+
`,
86+
APIVersion: "v1",
87+
},
88+
ChangeParser{Parser: structWithAtomicParser},
89+
Apply{
90+
Manager: "two",
91+
Object: `
92+
struct:
93+
string: "string"
94+
`,
95+
APIVersion: "v1",
96+
Conflicts:merge.Conflicts{
97+
merge.Conflict{Manager: "one", Path: _P("struct")},
98+
},
99+
},
100+
ForceApply{
101+
Manager: "two",
102+
Object: `
103+
struct:
104+
string: "string"
105+
`,
106+
APIVersion: "v1",
107+
},
108+
},
109+
Object: `
110+
struct:
111+
string: "string"
112+
`,
113+
APIVersion: "v1",
114+
Managed: fieldpath.ManagedFields{
115+
"two": fieldpath.NewVersionedSet(
116+
_NS(
117+
_P("struct"),
118+
),
119+
"v1",
120+
true,
121+
),
122+
},
123+
},
124+
}
125+
126+
for name, test := range tests {
127+
t.Run(name, func(t *testing.T) {
128+
if err := test.Test(structParser); err != nil {
129+
t.Fatal(err)
130+
}
131+
})
132+
}
133+
}

typed/typed.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ func (tv TypedValue) AsValue() value.Value {
7171
return tv.value
7272
}
7373

74+
// Schema removes the schema from the TypedValue.
75+
func (tv TypedValue) Schema() *schema.Schema {
76+
return tv.schema
77+
}
78+
7479
// Validate returns an error with a list of every spec violation.
7580
func (tv TypedValue) Validate() error {
7681
w := tv.walker()

0 commit comments

Comments
 (0)