mirror of
https://github.com/kubernetes/client-go.git
synced 2025-09-20 18:48:02 +00:00
Add field tracker support to client fake fixtures
Kubernetes-commit: 75d6f024326dadc13807b8221bedd8da7924c2ba
This commit is contained in:
committed by
Kubernetes Publisher
parent
96f66e9159
commit
2c866525dd
@@ -17,22 +17,31 @@ limitations under the License.
|
||||
package testing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/managedfields"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
"k8s.io/utils/ptr"
|
||||
)
|
||||
|
||||
func getArbitraryResource(s schema.GroupVersionResource, name, namespace string) *unstructured.Unstructured {
|
||||
@@ -275,6 +284,137 @@ func TestPatchWithMissingObject(t *testing.T) {
|
||||
assert.EqualError(t, err, `nodes "node-1" not found`)
|
||||
}
|
||||
|
||||
func TestApplyCreate(t *testing.T) {
|
||||
cmResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configMaps"}
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypes(cmResource.GroupVersion(), &v1.ConfigMap{})
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
o := NewFieldManagedObjectTracker(scheme, codecs.UniversalDecoder(), fakeTypeConverter)
|
||||
|
||||
reaction := ObjectReaction(o)
|
||||
patch := []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k": "v"}}`)
|
||||
action := NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager"})
|
||||
handled, configMap, err := reaction(action)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create a resource with apply: %v", err)
|
||||
}
|
||||
cm := configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, cm.Data, map[string]string{"k": "v"})
|
||||
}
|
||||
|
||||
func TestApplyUpdateMultipleFieldManagers(t *testing.T) {
|
||||
cmResource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "configMaps"}
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddKnownTypes(cmResource.GroupVersion(), &v1.ConfigMap{})
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
o := NewFieldManagedObjectTracker(scheme, codecs.UniversalDecoder(), fakeTypeConverter)
|
||||
|
||||
reaction := ObjectReaction(o)
|
||||
action := NewCreateAction(cmResource, "default", &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cm-1",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"k0": "v0",
|
||||
},
|
||||
})
|
||||
handled, _, err := reaction(action)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to create resource: %v", err)
|
||||
}
|
||||
|
||||
// Apply with test-manager-1
|
||||
// Expect data to be shared with initial create
|
||||
patch := []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k1": "v1"}}`)
|
||||
applyAction := NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager-1"})
|
||||
handled, configMap, err := reaction(applyAction)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to apply resource: %v", err)
|
||||
}
|
||||
cm := configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, map[string]string{"k0": "v0", "k1": "v1"}, cm.Data)
|
||||
|
||||
// Apply conflicting with test-manager-2, expect apply to fail
|
||||
patch = []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k1": "xyz"}}`)
|
||||
applyAction = NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager-2"})
|
||||
handled, _, err = reaction(applyAction)
|
||||
assert.True(t, handled)
|
||||
if assert.Error(t, err) {
|
||||
assert.Equal(t, "Apply failed with 1 conflict: conflict with \"test-manager-1\": .data.k1", err.Error())
|
||||
}
|
||||
|
||||
// Apply with test-manager-2
|
||||
// Expect data to be shared with initial create and test-manager-1
|
||||
patch = []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k2": "v2"}}`)
|
||||
applyAction = NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager-2"})
|
||||
handled, configMap, err = reaction(applyAction)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to apply resource: %v", err)
|
||||
}
|
||||
cm = configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, map[string]string{"k0": "v0", "k1": "v1", "k2": "v2"}, cm.Data)
|
||||
|
||||
// Apply with test-manager-1
|
||||
// Expect owned data to be updated
|
||||
patch = []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k1": "v101"}}`)
|
||||
applyAction = NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager-1"})
|
||||
handled, configMap, err = reaction(applyAction)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to apply resource: %v", err)
|
||||
}
|
||||
cm = configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, map[string]string{"k0": "v0", "k1": "v101", "k2": "v2"}, cm.Data)
|
||||
|
||||
// Force apply with test-manager-2
|
||||
// Expect data owned by test-manager-1 to be updated, expect data already owned but not in apply configuration to be removed
|
||||
patch = []byte(`{"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "cm-1"}, "data": {"k1": "v202"}}`)
|
||||
applyAction = NewPatchActionWithOptions(cmResource, "default", "cm-1", types.ApplyPatchType, patch,
|
||||
metav1.PatchOptions{FieldManager: "test-manager-2", Force: ptr.To(true)})
|
||||
handled, configMap, err = reaction(applyAction)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to apply resource: %v", err)
|
||||
}
|
||||
cm = configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, map[string]string{"k0": "v0", "k1": "v202"}, cm.Data)
|
||||
|
||||
// Update with test-manager-1 to perform a force update of the entire resource
|
||||
reaction = ObjectReaction(o)
|
||||
updateAction := NewUpdateActionWithOptions(cmResource, "default", &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "cm-1",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"k99": "v99",
|
||||
},
|
||||
}, metav1.UpdateOptions{FieldManager: "test-manager-1"})
|
||||
handled, configMap, err = reaction(updateAction)
|
||||
assert.True(t, handled)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to apply resource: %v", err)
|
||||
}
|
||||
typedCm := configMap.(*v1.ConfigMap)
|
||||
assert.Equal(t, map[string]string{"k99": "v99"}, typedCm.Data)
|
||||
}
|
||||
|
||||
func TestGetWithExactMatch(t *testing.T) {
|
||||
scheme := runtime.NewScheme()
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
@@ -408,3 +548,25 @@ func Test_resourceCovers(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var fakeTypeConverter = func() managedfields.TypeConverter {
|
||||
data, err := os.ReadFile(filepath.Join(strings.Repeat(".."+string(filepath.Separator), 5),
|
||||
"api", "openapi-spec", "swagger.json"))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
swag := spec.Swagger{}
|
||||
if err := json.Unmarshal(data, &swag); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
convertedDefs := map[string]*spec.Schema{}
|
||||
for k, v := range swag.Definitions {
|
||||
vCopy := v
|
||||
convertedDefs[k] = &vCopy
|
||||
}
|
||||
typeConverter, err := managedfields.NewTypeConverter(convertedDefs, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return typeConverter
|
||||
}()
|
||||
|
Reference in New Issue
Block a user