mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
apiextensions: add conversion pruning tests
This commit is contained in:
parent
26366255fc
commit
33e95bc185
@ -28,6 +28,7 @@ go_test(
|
||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
|
||||
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -80,7 +80,7 @@ func testWebhookConverter(t *testing.T, pruning bool) {
|
||||
{
|
||||
group: "nontrivial-converter",
|
||||
handler: NewObjectConverterWebhookHandler(t, nontrivialConverter),
|
||||
checks: checks(validateStorageVersion, validateServed, validateMixedStorageVersions("v1alpha1", "v1beta1", "v1beta2"), validateNonTrivialConverted, validateNonTrivialConvertedList),
|
||||
checks: checks(validateStorageVersion, validateServed, validateMixedStorageVersions("v1alpha1", "v1beta1", "v1beta2"), validateNonTrivialConverted, validateNonTrivialConvertedList, validateStoragePruning),
|
||||
},
|
||||
{
|
||||
group: "empty-response",
|
||||
@ -275,10 +275,24 @@ func validateNonTrivialConverted(t *testing.T, ctc *conversionTestContext) {
|
||||
t.Run(fmt.Sprintf("getting objects created as %s", createVersion.Name), func(t *testing.T) {
|
||||
name := "converted-" + createVersion.Name
|
||||
client := ctc.versionedClient(ns, createVersion.Name)
|
||||
if _, err := client.Create(newConversionMultiVersionFixture(ns, name, createVersion.Name), metav1.CreateOptions{}); err != nil {
|
||||
|
||||
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
|
||||
if !*ctc.crd.Spec.PreserveUnknownFields {
|
||||
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if _, err := client.Create(fixture, metav1.CreateOptions{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// verify that the right, pruned version is in storage
|
||||
obj, err := ctc.etcdObjectReader.GetStoredCustomResource(ns, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyMultiVersionObject(t, "v1beta1", obj)
|
||||
|
||||
for _, getVersion := range ctc.crd.Spec.Versions {
|
||||
client := ctc.versionedClient(ns, getVersion.Name)
|
||||
obj, err := client.Get(name, metav1.GetOptions{})
|
||||
@ -298,7 +312,14 @@ func validateNonTrivialConvertedList(t *testing.T, ctc *conversionTestContext) {
|
||||
for _, createVersion := range ctc.crd.Spec.Versions {
|
||||
name := "converted-" + createVersion.Name
|
||||
client := ctc.versionedClient(ns, createVersion.Name)
|
||||
if _, err := client.Create(newConversionMultiVersionFixture(ns, name, createVersion.Name), metav1.CreateOptions{}); err != nil {
|
||||
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
|
||||
if !*ctc.crd.Spec.PreserveUnknownFields {
|
||||
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
_, err := client.Create(fixture, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
names.Insert(name)
|
||||
@ -326,6 +347,67 @@ func validateNonTrivialConvertedList(t *testing.T, ctc *conversionTestContext) {
|
||||
}
|
||||
}
|
||||
|
||||
func validateStoragePruning(t *testing.T, ctc *conversionTestContext) {
|
||||
if *ctc.crd.Spec.PreserveUnknownFields {
|
||||
return
|
||||
}
|
||||
|
||||
ns := ctc.namespace
|
||||
|
||||
for _, createVersion := range ctc.crd.Spec.Versions {
|
||||
t.Run(fmt.Sprintf("getting objects created as %s", createVersion.Name), func(t *testing.T) {
|
||||
name := "storagepruning-" + createVersion.Name
|
||||
client := ctc.versionedClient(ns, createVersion.Name)
|
||||
|
||||
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
|
||||
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err := client.Create(fixture, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// verify that the right, pruned version is in storage
|
||||
obj, err := ctc.etcdObjectReader.GetStoredCustomResource(ns, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyMultiVersionObject(t, "v1beta1", obj)
|
||||
|
||||
// add garbage and set a label
|
||||
if err := unstructured.SetNestedField(obj.Object, "foo", "garbage"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
labels := obj.GetLabels()
|
||||
if labels == nil {
|
||||
labels = map[string]string{}
|
||||
}
|
||||
labels["mutated"] = "true"
|
||||
obj.SetLabels(labels)
|
||||
if err := ctc.etcdObjectReader.SetStoredCustomResource(ns, name, obj); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, getVersion := range ctc.crd.Spec.Versions {
|
||||
client := ctc.versionedClient(ns, getVersion.Name)
|
||||
obj, err := client.Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// check that the direct mutation in etcd worked
|
||||
labels := obj.GetLabels()
|
||||
if labels["mutated"] != "true" {
|
||||
t.Errorf("expected object %s in version %s to have label 'mutated=true'", name, getVersion.Name)
|
||||
}
|
||||
|
||||
verifyMultiVersionObject(t, getVersion.Name, obj)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func expectConversionFailureMessage(id, message string) func(t *testing.T, ctc *conversionTestContext) {
|
||||
return func(t *testing.T, ctc *conversionTestContext) {
|
||||
ns := ctc.namespace
|
||||
@ -763,11 +845,11 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
||||
}
|
||||
|
||||
delete(j, "metadata")
|
||||
delete(j, "apiVersion")
|
||||
delete(j, "kind")
|
||||
|
||||
var expected = map[string]map[string]interface{}{
|
||||
"v1alpha1": {
|
||||
"apiVersion": "stable.example.com/v1alpha1",
|
||||
"kind": "MultiVersion",
|
||||
"content": map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
@ -777,6 +859,8 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
||||
},
|
||||
},
|
||||
"v1beta1": {
|
||||
"apiVersion": "stable.example.com/v1beta1",
|
||||
"kind": "MultiVersion",
|
||||
"content": map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
@ -786,6 +870,8 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
||||
},
|
||||
},
|
||||
"v1beta2": {
|
||||
"apiVersion": "stable.example.com/v1beta2",
|
||||
"kind": "MultiVersion",
|
||||
"contentv2": map[string]interface{}{
|
||||
"key": "value",
|
||||
},
|
||||
|
@ -84,6 +84,20 @@ func (s *EtcdObjectReader) GetStoredCustomResource(ns, name string) (*unstructur
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// SetStoredCustomResource writes the storage representation of a custom resource to etcd.
|
||||
func (s *EtcdObjectReader) SetStoredCustomResource(ns, name string, obj *unstructured.Unstructured) error {
|
||||
bs, err := obj.MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := path.Join("/", s.storagePrefix, s.crd.Spec.Group, s.crd.Spec.Names.Plural, ns, name)
|
||||
if _, err := s.etcdClient.KV.Put(context.Background(), key, string(bs)); err != nil {
|
||||
return fmt.Errorf("error setting storage object %s, %s from etcd at key %s: %v", ns, name, key, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEtcdClients returns an initialized clientv3.Client and clientv3.KV.
|
||||
func GetEtcdClients(config storagebackend.TransportConfig) (*clientv3.Client, clientv3.KV, error) {
|
||||
tlsInfo := transport.TLSInfo{
|
||||
|
Loading…
Reference in New Issue
Block a user