diff --git a/cmd/clusterctl/client/cluster/cert_manager.go b/cmd/clusterctl/client/cluster/cert_manager.go index c5366c64dc33..c3679424fd10 100644 --- a/cmd/clusterctl/client/cluster/cert_manager.go +++ b/cmd/clusterctl/client/cluster/cert_manager.go @@ -27,6 +27,7 @@ import ( manifests "sigs.k8s.io/cluster-api/cmd/clusterctl/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -180,7 +181,7 @@ func (cm *certManagerClient) getManifestObjs() ([]unstructured.Unstructured, err return nil, err } - objs, err := util.ToUnstructured(yaml) + objs, err := utilyaml.ToUnstructured(yaml) if err != nil { return nil, errors.Wrap(err, "failed to parse yaml for cert-manager manifest") } diff --git a/cmd/clusterctl/client/cluster/inventory.go b/cmd/clusterctl/client/cluster/inventory.go index 67f8663d970f..3b6a0ae7bf99 100644 --- a/cmd/clusterctl/client/cluster/inventory.go +++ b/cmd/clusterctl/client/cluster/inventory.go @@ -27,8 +27,8 @@ import ( "k8s.io/apimachinery/pkg/util/sets" clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/config" - "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" logf "sigs.k8s.io/cluster-api/cmd/clusterctl/log" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -129,7 +129,7 @@ func (p *inventoryClient) EnsureCustomResourceDefinitions() error { } // Transform the yaml in a list of objects. - objs, err := util.ToUnstructured(yaml) + objs, err := utilyaml.ToUnstructured(yaml) if err != nil { return errors.Wrap(err, "failed to parse yaml for clusterctl inventory CRDs") } diff --git a/cmd/clusterctl/client/init_test.go b/cmd/clusterctl/client/init_test.go index 3847ae1e6aab..018012c0e487 100644 --- a/cmd/clusterctl/client/init_test.go +++ b/cmd/clusterctl/client/init_test.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/cluster-api/cmd/clusterctl/client/cluster" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" - "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" ) func Test_clusterctlClient_InitImages(t *testing.T) { @@ -618,7 +618,7 @@ func componentsYAML(ns string) []byte { "metadata:\n" + " name: manager") - return util.JoinYaml(namespaceYaml, podYaml) + return utilyaml.JoinYaml(namespaceYaml, podYaml) } func templateYAML(ns string, clusterName string) []byte { diff --git a/cmd/clusterctl/client/repository/components.go b/cmd/clusterctl/client/repository/components.go index 422fb66fff9c..32afee0c0629 100644 --- a/cmd/clusterctl/client/repository/components.go +++ b/cmd/clusterctl/client/repository/components.go @@ -33,6 +33,7 @@ import ( "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/scheme" "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" ) const ( @@ -171,7 +172,7 @@ func (c *components) Yaml() ([]byte, error) { objs = append(objs, c.sharedObjs...) objs = append(objs, c.instanceObjs...) - return util.FromUnstructured(objs) + return utilyaml.FromUnstructured(objs) } // ComponentsOptions is the inputs needed by the NewComponents @@ -204,7 +205,7 @@ func NewComponents(provider config.Provider, configClient config.Client, rawyaml } // Transform the yaml in a list of objects, so following transformation can work on typed objects (instead of working on a string/slice of bytes) - objs, err := util.ToUnstructured(yaml) + objs, err := utilyaml.ToUnstructured(yaml) if err != nil { return nil, errors.Wrap(err, "failed to parse yaml") } diff --git a/cmd/clusterctl/client/repository/components_client_test.go b/cmd/clusterctl/client/repository/components_client_test.go index 6ab6bd734917..ced53933a272 100644 --- a/cmd/clusterctl/client/repository/components_client_test.go +++ b/cmd/clusterctl/client/repository/components_client_test.go @@ -26,7 +26,7 @@ import ( clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" - "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" ) const ( @@ -96,7 +96,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), }, args: args{ version: "v1.0.0", @@ -119,7 +119,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), }, args: args{ version: "v1.0.0", @@ -142,7 +142,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(namespaceYaml, controllerYaml, configMapYaml)), }, args: args{ version: "v1.0.0", @@ -180,7 +180,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(controllerYaml, configMapYaml)), }, args: args{ version: "v1.0.0", @@ -196,7 +196,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(controllerYaml, configMapYaml)), }, args: args{ version: "v1.0.0", @@ -219,7 +219,7 @@ func Test_componentsClient_Get(t *testing.T) { repository: test.NewFakeRepository(). WithPaths("root", "components.yaml"). WithDefaultVersion("v1.0.0"). - WithFile("v1.0.0", "components.yaml", util.JoinYaml(controllerYaml, configMapYaml)), + WithFile("v1.0.0", "components.yaml", utilyaml.JoinYaml(controllerYaml, configMapYaml)), }, args: args{ version: "v2.0.0", diff --git a/cmd/clusterctl/client/repository/template.go b/cmd/clusterctl/client/repository/template.go index 08d08f49d265..19ddc6142367 100644 --- a/cmd/clusterctl/client/repository/template.go +++ b/cmd/clusterctl/client/repository/template.go @@ -20,7 +20,7 @@ import ( "github.com/pkg/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" - "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/util" + utilyaml "sigs.k8s.io/cluster-api/util/yaml" ) // Template wraps a YAML file that defines the cluster objects (Cluster, Machines etc.). @@ -66,7 +66,7 @@ func (t *template) Objs() []unstructured.Unstructured { } func (t *template) Yaml() ([]byte, error) { - return util.FromUnstructured(t.objs) + return utilyaml.FromUnstructured(t.objs) } // NewTemplate returns a new objects embedding a cluster template YAML file. @@ -86,7 +86,7 @@ func NewTemplate(rawYaml []byte, configVariablesClient config.VariablesClient, t } // Transform the yaml in a list of objects, so following transformation can work on typed objects (instead of working on a string/slice of bytes). - objs, err := util.ToUnstructured(yaml) + objs, err := utilyaml.ToUnstructured(yaml) if err != nil { return nil, errors.Wrap(err, "failed to parse yaml") } diff --git a/cmd/clusterctl/internal/util/yaml.go b/cmd/clusterctl/internal/util/yaml.go deleted file mode 100644 index 53f78a555bce..000000000000 --- a/cmd/clusterctl/internal/util/yaml.go +++ /dev/null @@ -1,108 +0,0 @@ -/* -Copyright 2019 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "bufio" - "bytes" - "io" - - "github.com/pkg/errors" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - utilyaml "k8s.io/apimachinery/pkg/util/yaml" - "sigs.k8s.io/cluster-api/util" - "sigs.k8s.io/yaml" -) - -var yamlSeparator = []byte("---") - -// JoinYaml takes a list of YAML files and join them ensuring -// each YAML that the yaml separator goes on a new line by adding \n where necessary -func JoinYaml(yamls ...[]byte) []byte { - var cr = []byte("\n") - var b [][]byte //nolint - for _, y := range yamls { - if !bytes.HasPrefix(y, cr) { - y = append(cr, y...) - } - if !bytes.HasSuffix(y, cr) { - - y = append(y, cr...) - } - b = append(b, y) - } - - r := bytes.Join(b, yamlSeparator) - r = bytes.TrimPrefix(r, cr) - r = bytes.TrimSuffix(r, cr) - - return r -} - -// ToUnstructured takes a YAML and converts it to a list of Unstructured objects -func ToUnstructured(rawyaml []byte) ([]unstructured.Unstructured, error) { - var ret []unstructured.Unstructured - - reader := utilyaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(rawyaml))) - count := 1 - for { - // Read one YAML document at a time, until io.EOF is returned - b, err := reader.Read() - if err != nil { - if err == io.EOF { - break - } - return nil, errors.Wrapf(err, "failed to read yaml") - } - if len(b) == 0 { - break - } - - var m map[string]interface{} - if err := yaml.Unmarshal(b, &m); err != nil { - return nil, errors.Wrapf(err, "failed to unmarshal the %s yaml document: %q", util.Ordinalize(count), string(b)) - } - - var u unstructured.Unstructured - u.SetUnstructuredContent(m) - - // Ignore empty objects. - // Empty objects are generated if there are weird things in manifest files like e.g. two --- in a row without a yaml doc in the middle - if u.Object == nil { - continue - } - - ret = append(ret, u) - count++ - } - - return ret, nil -} - -// FromUnstructured takes a list of Unstructured objects and converts it into a YAML -func FromUnstructured(objs []unstructured.Unstructured) ([]byte, error) { - var ret [][]byte //nolint - for _, o := range objs { - content, err := yaml.Marshal(o.UnstructuredContent()) - if err != nil { - return nil, errors.Wrapf(err, "failed to marshal yaml for %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName()) - } - ret = append(ret, content) - } - - return JoinYaml(ret...), nil -} diff --git a/cmd/clusterctl/internal/util/yaml_test.go b/cmd/clusterctl/internal/util/yaml_test.go deleted file mode 100644 index f08026a1c014..000000000000 --- a/cmd/clusterctl/internal/util/yaml_test.go +++ /dev/null @@ -1,157 +0,0 @@ -/* -Copyright 2020 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package util - -import ( - "testing" - - . "github.com/onsi/gomega" -) - -func TestToUnstructured(t *testing.T) { - type args struct { - rawyaml []byte - } - tests := []struct { - name string - args args - wantObjsCount int - wantErr bool - err string - }{ - { - name: "single object", - args: args{ - rawyaml: []byte("apiVersion: v1\n" + - "kind: ConfigMap\n"), - }, - wantObjsCount: 1, - wantErr: false, - }, - { - name: "multiple objects are detected", - args: args{ - rawyaml: []byte("apiVersion: v1\n" + - "kind: ConfigMap\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Secret\n"), - }, - wantObjsCount: 2, - wantErr: false, - }, - { - name: "empty object are dropped", - args: args{ - rawyaml: []byte("---\n" + //empty objects before - "---\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: ConfigMap\n" + - "---\n" + // empty objects in the middle - "---\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Secret\n" + - "---\n" + //empty objects after - "---\n" + - "---\n"), - }, - wantObjsCount: 2, - wantErr: false, - }, - { - name: "--- in the middle of objects are ignored", - args: args{ - []byte("apiVersion: v1\n" + - "kind: ConfigMap\n" + - "data: \n" + - " key: |\n" + - " ··Several lines of text,\n" + - " ··with some --- \n" + - " ---\n" + - " ··in the middle\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Secret\n"), - }, - wantObjsCount: 2, - wantErr: false, - }, - { - name: "returns error for invalid yaml", - args: args{ - rawyaml: []byte("apiVersion: v1\n" + - "kind: ConfigMap\n" + - "---\n" + - "apiVersion: v1\n" + - "foobar\n" + - "kind: Secret\n"), - }, - wantErr: true, - err: "failed to unmarshal the 2nd yaml document", - }, - { - name: "returns error for invalid yaml", - args: args{ - rawyaml: []byte("apiVersion: v1\n" + - "kind: ConfigMap\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Pod\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Deployment\n" + - "---\n" + - "apiVersion: v1\n" + - "foobar\n" + - "kind: ConfigMap\n"), - }, - wantErr: true, - err: "failed to unmarshal the 4th yaml document", - }, - { - name: "returns error for invalid yaml", - args: args{ - rawyaml: []byte("apiVersion: v1\n" + - "foobar\n" + - "kind: ConfigMap\n" + - "---\n" + - "apiVersion: v1\n" + - "kind: Secret\n"), - }, - wantErr: true, - err: "failed to unmarshal the 1st yaml document", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - g := NewWithT(t) - - got, err := ToUnstructured(tt.args.rawyaml) - if tt.wantErr { - g.Expect(err).To(HaveOccurred()) - if len(tt.err) != 0 { - g.Expect(err.Error()).To(ContainSubstring(tt.err)) - } - return - } - g.Expect(err).ToNot(HaveOccurred()) - g.Expect(got).To(HaveLen(tt.wantObjsCount)) - }) - } -} diff --git a/util/yaml/yaml.go b/util/yaml/yaml.go index d897d1dd91b2..72961122ad5d 100644 --- a/util/yaml/yaml.go +++ b/util/yaml/yaml.go @@ -28,9 +28,11 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer/streaming" - "k8s.io/apimachinery/pkg/util/yaml" + apiyaml "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes/scheme" clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3" + "sigs.k8s.io/cluster-api/util" + "sigs.k8s.io/yaml" ) func ExtractClusterReferences(out *ParseOutput, c *clusterv1.Cluster) (res []*unstructured.Unstructured) { @@ -151,7 +153,7 @@ func Parse(input ParseInput) (*ParseOutput, error) { } type yamlDecoder struct { - reader *yaml.YAMLReader + reader *apiyaml.YAMLReader decoder runtime.Decoder close func() error } @@ -179,8 +181,87 @@ func (d *yamlDecoder) Close() error { func NewYAMLDecoder(r io.ReadCloser) streaming.Decoder { return &yamlDecoder{ - reader: yaml.NewYAMLReader(bufio.NewReader(r)), + reader: apiyaml.NewYAMLReader(bufio.NewReader(r)), decoder: scheme.Codecs.UniversalDeserializer(), close: r.Close, } } + +// ToUnstructured takes a YAML and converts it to a list of Unstructured objects +func ToUnstructured(rawyaml []byte) ([]unstructured.Unstructured, error) { + var ret []unstructured.Unstructured + + reader := apiyaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(rawyaml))) + count := 1 + for { + // Read one YAML document at a time, until io.EOF is returned + b, err := reader.Read() + if err != nil { + if err == io.EOF { + break + } + return nil, errors.Wrapf(err, "failed to read yaml") + } + if len(b) == 0 { + break + } + + var m map[string]interface{} + if err := yaml.Unmarshal(b, &m); err != nil { + return nil, errors.Wrapf(err, "failed to unmarshal the %s yaml document: %q", util.Ordinalize(count), string(b)) + } + + var u unstructured.Unstructured + u.SetUnstructuredContent(m) + + // Ignore empty objects. + // Empty objects are generated if there are weird things in manifest files like e.g. two --- in a row without a yaml doc in the middle + if u.Object == nil { + continue + } + + ret = append(ret, u) + count++ + } + + return ret, nil +} + +// JoinYaml takes a list of YAML files and join them ensuring +// each YAML that the yaml separator goes on a new line by adding \n where necessary +func JoinYaml(yamls ...[]byte) []byte { + var yamlSeparator = []byte("---") + + var cr = []byte("\n") + var b [][]byte //nolint + for _, y := range yamls { + if !bytes.HasPrefix(y, cr) { + y = append(cr, y...) + } + if !bytes.HasSuffix(y, cr) { + + y = append(y, cr...) + } + b = append(b, y) + } + + r := bytes.Join(b, yamlSeparator) + r = bytes.TrimPrefix(r, cr) + r = bytes.TrimSuffix(r, cr) + + return r +} + +// FromUnstructured takes a list of Unstructured objects and converts it into a YAML +func FromUnstructured(objs []unstructured.Unstructured) ([]byte, error) { + var ret [][]byte //nolint + for _, o := range objs { + content, err := yaml.Marshal(o.UnstructuredContent()) + if err != nil { + return nil, errors.Wrapf(err, "failed to marshal yaml for %s, %s/%s", o.GroupVersionKind(), o.GetNamespace(), o.GetName()) + } + ret = append(ret, content) + } + + return JoinYaml(ret...), nil +} diff --git a/util/yaml/yaml_test.go b/util/yaml/yaml_test.go index 83cd979567c7..65e91ab6fd7c 100644 --- a/util/yaml/yaml_test.go +++ b/util/yaml/yaml_test.go @@ -18,11 +18,13 @@ package yaml import ( "io/ioutil" - kerrors "k8s.io/apimachinery/pkg/util/errors" "os" "testing" . "github.com/onsi/gomega" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + kerrors "k8s.io/apimachinery/pkg/util/errors" ) const validCluster = ` @@ -314,3 +316,154 @@ func createTempFile(contents string) (filename string, reterr error) { _, _ = f.WriteString(contents) return f.Name(), nil } + +func TestToUnstructured(t *testing.T) { + type args struct { + rawyaml []byte + } + tests := []struct { + name string + args args + wantObjsCount int + wantErr bool + err string + }{ + { + name: "single object", + args: args{ + rawyaml: []byte("apiVersion: v1\n" + + "kind: ConfigMap\n"), + }, + wantObjsCount: 1, + wantErr: false, + }, + { + name: "multiple objects are detected", + args: args{ + rawyaml: []byte("apiVersion: v1\n" + + "kind: ConfigMap\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Secret\n"), + }, + wantObjsCount: 2, + wantErr: false, + }, + { + name: "empty object are dropped", + args: args{ + rawyaml: []byte("---\n" + //empty objects before + "---\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: ConfigMap\n" + + "---\n" + // empty objects in the middle + "---\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Secret\n" + + "---\n" + //empty objects after + "---\n" + + "---\n"), + }, + wantObjsCount: 2, + wantErr: false, + }, + { + name: "--- in the middle of objects are ignored", + args: args{ + []byte("apiVersion: v1\n" + + "kind: ConfigMap\n" + + "data: \n" + + " key: |\n" + + " ··Several lines of text,\n" + + " ··with some --- \n" + + " ---\n" + + " ··in the middle\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Secret\n"), + }, + wantObjsCount: 2, + wantErr: false, + }, + { + name: "returns error for invalid yaml", + args: args{ + rawyaml: []byte("apiVersion: v1\n" + + "kind: ConfigMap\n" + + "---\n" + + "apiVersion: v1\n" + + "foobar\n" + + "kind: Secret\n"), + }, + wantErr: true, + err: "failed to unmarshal the 2nd yaml document", + }, + { + name: "returns error for invalid yaml", + args: args{ + rawyaml: []byte("apiVersion: v1\n" + + "kind: ConfigMap\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Pod\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Deployment\n" + + "---\n" + + "apiVersion: v1\n" + + "foobar\n" + + "kind: ConfigMap\n"), + }, + wantErr: true, + err: "failed to unmarshal the 4th yaml document", + }, + { + name: "returns error for invalid yaml", + args: args{ + rawyaml: []byte("apiVersion: v1\n" + + "foobar\n" + + "kind: ConfigMap\n" + + "---\n" + + "apiVersion: v1\n" + + "kind: Secret\n"), + }, + wantErr: true, + err: "failed to unmarshal the 1st yaml document", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + + got, err := ToUnstructured(tt.args.rawyaml) + if tt.wantErr { + g.Expect(err).To(HaveOccurred()) + if len(tt.err) != 0 { + g.Expect(err.Error()).To(ContainSubstring(tt.err)) + } + return + } + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(HaveLen(tt.wantObjsCount)) + }) + } +} + +func TestFromUnstructured(t *testing.T) { + rawyaml := []byte("apiVersion: v1\n" + + "kind: ConfigMap") + + unstructuredObj := unstructured.Unstructured{ + Object: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + }, + } + + convertedyaml, err := FromUnstructured([]unstructured.Unstructured{unstructuredObj}) + g := NewWithT(t) + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(string(rawyaml)).To(Equal(string(convertedyaml))) +}