mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Add tests for resourceVersion precondition failures on patch
This commit is contained in:
parent
fbd6f38084
commit
b526532c8a
@ -266,15 +266,21 @@ type patchTestCase struct {
|
|||||||
|
|
||||||
// startingPod is used as the starting point for the first Update
|
// startingPod is used as the starting point for the first Update
|
||||||
startingPod *example.Pod
|
startingPod *example.Pod
|
||||||
// changedPod is the "destination" pod for the patch. The test will create a patch from the startingPod to the changedPod
|
// changedPod can be set as the "destination" pod for the patch, and the test will compute a patch from the startingPod to the changedPod,
|
||||||
// to use when calling the patch operation
|
// or patches can be set directly using strategicMergePatch, mergePatch, and jsonPatch
|
||||||
changedPod *example.Pod
|
changedPod *example.Pod
|
||||||
|
strategicMergePatch string
|
||||||
|
mergePatch string
|
||||||
|
jsonPatch string
|
||||||
|
|
||||||
// updatePod is the pod that is used for conflict comparison and as the starting point for the second Update
|
// updatePod is the pod that is used for conflict comparison and as the starting point for the second Update
|
||||||
updatePod *example.Pod
|
updatePod *example.Pod
|
||||||
|
|
||||||
// expectedPod is the pod that you expect to get back after the patch is complete
|
// expectedPod is the pod that you expect to get back after the patch is complete
|
||||||
expectedPod *example.Pod
|
expectedPod *example.Pod
|
||||||
expectedError string
|
expectedError string
|
||||||
|
// if set, indicates the number of times patching was expected to be attempted
|
||||||
|
expectedTries int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tc *patchTestCase) Run(t *testing.T) {
|
func (tc *patchTestCase) Run(t *testing.T) {
|
||||||
@ -317,12 +323,13 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
updatePod: tc.updatePod,
|
updatePod: tc.updatePod,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO SUPPORT THIS!
|
|
||||||
if patchType == types.JSONPatchType {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t.Logf("Working with patchType %v", patchType)
|
t.Logf("Working with patchType %v", patchType)
|
||||||
|
|
||||||
|
patch := []byte{}
|
||||||
|
switch patchType {
|
||||||
|
case types.StrategicMergePatchType:
|
||||||
|
patch = []byte(tc.strategicMergePatch)
|
||||||
|
if len(patch) == 0 {
|
||||||
originalObjJS, err := runtime.Encode(codec, tc.startingPod)
|
originalObjJS, err := runtime.Encode(codec, tc.startingPod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
@ -333,23 +340,42 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
patch := []byte{}
|
|
||||||
switch patchType {
|
|
||||||
case types.StrategicMergePatchType:
|
|
||||||
patch, err = strategicpatch.CreateTwoWayMergePatch(originalObjJS, changedJS, schemaReferenceObj)
|
patch, err = strategicpatch.CreateTwoWayMergePatch(originalObjJS, changedJS, schemaReferenceObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
case types.MergePatchType:
|
case types.MergePatchType:
|
||||||
|
patch = []byte(tc.mergePatch)
|
||||||
|
if len(patch) == 0 {
|
||||||
|
originalObjJS, err := runtime.Encode(codec, tc.startingPod)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
changedJS, err := runtime.Encode(codec, tc.changedPod)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
patch, err = jsonpatch.CreateMergePatch(originalObjJS, changedJS)
|
patch, err = jsonpatch.CreateMergePatch(originalObjJS, changedJS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
t.Errorf("%s: unexpected error: %v", tc.name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case types.JSONPatchType:
|
||||||
|
patch = []byte(tc.jsonPatch)
|
||||||
|
if len(patch) == 0 {
|
||||||
|
// TODO SUPPORT THIS!
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
t.Error("unsupported patch type")
|
||||||
}
|
}
|
||||||
|
|
||||||
p := patcher{
|
p := patcher{
|
||||||
@ -391,6 +417,12 @@ func (tc *patchTestCase) Run(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tc.expectedTries > 0 {
|
||||||
|
if tc.expectedTries != testPatcher.numUpdates {
|
||||||
|
t.Errorf("%s: expected %d tries, got %d", tc.expectedTries, testPatcher.numUpdates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if tc.expectedPod == nil {
|
if tc.expectedPod == nil {
|
||||||
if resultObj != nil {
|
if resultObj != nil {
|
||||||
t.Errorf("%s: unexpected result: %v", tc.name, resultObj)
|
t.Errorf("%s: unexpected result: %v", tc.name, resultObj)
|
||||||
@ -552,6 +584,73 @@ func TestPatchResourceWithVersionConflict(t *testing.T) {
|
|||||||
tc.Run(t)
|
tc.Run(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchResourceWithStaleVersionConflict(t *testing.T) {
|
||||||
|
namespace := "bar"
|
||||||
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
|
|
||||||
|
tc := &patchTestCase{
|
||||||
|
name: "TestPatchResourceWithStaleVersionConflict",
|
||||||
|
|
||||||
|
startingPod: &example.Pod{},
|
||||||
|
updatePod: &example.Pod{},
|
||||||
|
|
||||||
|
expectedError: `Operation cannot be fulfilled on pods.example.apiserver.k8s.io "foo": existing 2, new 1`,
|
||||||
|
expectedTries: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// starting pod is at rv=2
|
||||||
|
tc.startingPod.Name = name
|
||||||
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
|
tc.startingPod.ResourceVersion = "2"
|
||||||
|
tc.startingPod.APIVersion = examplev1.SchemeGroupVersion.String()
|
||||||
|
// same pod is still in place when attempting to persist the update
|
||||||
|
tc.updatePod = tc.startingPod
|
||||||
|
|
||||||
|
// patches are submitted with a stale rv=1
|
||||||
|
tc.mergePatch = `{"metadata":{"resourceVersion":"1"},"spec":{"nodeName":"foo"}}`
|
||||||
|
tc.strategicMergePatch = `{"metadata":{"resourceVersion":"1"},"spec":{"nodeName":"foo"}}`
|
||||||
|
|
||||||
|
tc.Run(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPatchResourceWithRacingVersionConflict(t *testing.T) {
|
||||||
|
namespace := "bar"
|
||||||
|
name := "foo"
|
||||||
|
uid := types.UID("uid")
|
||||||
|
|
||||||
|
tc := &patchTestCase{
|
||||||
|
name: "TestPatchResourceWithRacingVersionConflict",
|
||||||
|
|
||||||
|
startingPod: &example.Pod{},
|
||||||
|
updatePod: &example.Pod{},
|
||||||
|
|
||||||
|
expectedError: `Operation cannot be fulfilled on pods.example.apiserver.k8s.io "foo": existing 3, new 2`,
|
||||||
|
expectedTries: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// starting pod is at rv=2
|
||||||
|
tc.startingPod.Name = name
|
||||||
|
tc.startingPod.Namespace = namespace
|
||||||
|
tc.startingPod.UID = uid
|
||||||
|
tc.startingPod.ResourceVersion = "2"
|
||||||
|
tc.startingPod.APIVersion = examplev1.SchemeGroupVersion.String()
|
||||||
|
|
||||||
|
// pod with rv=3 is found when attempting to persist the update
|
||||||
|
tc.updatePod.Name = name
|
||||||
|
tc.updatePod.Namespace = namespace
|
||||||
|
tc.updatePod.UID = uid
|
||||||
|
tc.updatePod.ResourceVersion = "3"
|
||||||
|
tc.updatePod.APIVersion = examplev1.SchemeGroupVersion.String()
|
||||||
|
|
||||||
|
// patches are submitted with a rv=2
|
||||||
|
tc.mergePatch = `{"metadata":{"resourceVersion":"2"},"spec":{"nodeName":"foo"}}`
|
||||||
|
tc.strategicMergePatch = `{"metadata":{"resourceVersion":"2"},"spec":{"nodeName":"foo"}}`
|
||||||
|
|
||||||
|
tc.Run(t)
|
||||||
|
}
|
||||||
|
|
||||||
func TestPatchResourceWithConflict(t *testing.T) {
|
func TestPatchResourceWithConflict(t *testing.T) {
|
||||||
namespace := "bar"
|
namespace := "bar"
|
||||||
name := "foo"
|
name := "foo"
|
||||||
|
Loading…
Reference in New Issue
Block a user