Add new unit tests for diff/prune

This commit is contained in:
Arda Güçlü 2021-09-24 09:40:26 +03:00
parent 56c19f1056
commit 17de414905
6 changed files with 205 additions and 312 deletions

View File

@ -21,6 +21,8 @@ import (
"io"
"net/http"
"k8s.io/kubectl/pkg/util/prune"
"github.com/spf13/cobra"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@ -60,7 +62,7 @@ type ApplyFlags struct {
FieldManager string
Selector string
Prune bool
PruneResources []pruneResource
PruneResources []prune.Resource
All bool
Overwrite bool
OpenAPIPatch bool
@ -85,7 +87,7 @@ type ApplyOptions struct {
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.DryRunVerifier
Prune bool
PruneResources []pruneResource
PruneResources []prune.Resource
cmdBaseName string
All bool
Overwrite bool
@ -278,7 +280,7 @@ func (flags *ApplyFlags) ToOptions(cmd *cobra.Command, baseName string, args []s
}
if flags.Prune {
flags.PruneResources, err = parsePruneResources(mapper, flags.PruneWhitelist)
flags.PruneResources, err = prune.ParseResources(mapper, flags.PruneWhitelist)
if err != nil {
return nil, err
}

View File

@ -20,12 +20,12 @@ import (
"context"
"fmt"
"io"
"strings"
"k8s.io/kubectl/pkg/util/prune"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/client-go/dynamic"
@ -71,7 +71,7 @@ func newPruner(o *ApplyOptions) pruner {
func (p *pruner) pruneAll(o *ApplyOptions) error {
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(o.Mapper, &(o.PruneResources))
namespacedRESTMappings, nonNamespacedRESTMappings, err := prune.GetRESTMappings(o.Mapper, &(o.PruneResources))
if err != nil {
return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
}
@ -158,83 +158,3 @@ func asDeleteOptions(cascadingStrategy metav1.DeletionPropagation, gracePeriod i
options.PropagationPolicy = &cascadingStrategy
return options
}
type pruneResource struct {
group string
version string
kind string
namespaced bool
}
func (pr pruneResource) String() string {
return fmt.Sprintf("%v/%v, Kind=%v, Namespaced=%v", pr.group, pr.version, pr.kind, pr.namespaced)
}
func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (namespaced, nonNamespaced []*meta.RESTMapping, err error) {
if len(*pruneResources) == 0 {
// default allowlist
*pruneResources = []pruneResource{
{"", "v1", "ConfigMap", true},
{"", "v1", "Endpoints", true},
{"", "v1", "Namespace", false},
{"", "v1", "PersistentVolumeClaim", true},
{"", "v1", "PersistentVolume", false},
{"", "v1", "Pod", true},
{"", "v1", "ReplicationController", true},
{"", "v1", "Secret", true},
{"", "v1", "Service", true},
{"batch", "v1", "Job", true},
{"batch", "v1", "CronJob", true},
{"networking.k8s.io", "v1", "Ingress", true},
{"apps", "v1", "DaemonSet", true},
{"apps", "v1", "Deployment", true},
{"apps", "v1", "ReplicaSet", true},
{"apps", "v1", "StatefulSet", true},
}
}
for _, resource := range *pruneResources {
addedMapping, err := mapper.RESTMapping(schema.GroupKind{Group: resource.group, Kind: resource.kind}, resource.version)
if err != nil {
return nil, nil, fmt.Errorf("invalid resource %v: %v", resource, err)
}
if resource.namespaced {
namespaced = append(namespaced, addedMapping)
} else {
nonNamespaced = append(nonNamespaced, addedMapping)
}
}
return namespaced, nonNamespaced, nil
}
func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource, error) {
pruneResources := []pruneResource{}
for _, groupVersionKind := range gvks {
gvk := strings.Split(groupVersionKind, "/")
if len(gvk) != 3 {
return nil, fmt.Errorf("invalid GroupVersionKind format: %v, please follow <group/version/kind>", groupVersionKind)
}
if gvk[0] == "core" {
gvk[0] = ""
}
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk[0], Kind: gvk[2]}, gvk[1])
if err != nil {
return pruneResources, err
}
var namespaced bool
namespaceScope := mapping.Scope.Name()
switch namespaceScope {
case meta.RESTScopeNameNamespace:
namespaced = true
case meta.RESTScopeNameRoot:
namespaced = false
default:
return pruneResources, fmt.Errorf("Unknown namespace scope: %q", namespaceScope)
}
pruneResources = append(pruneResources, pruneResource{gvk[0], gvk[1], gvk[2], namespaced})
}
return pruneResources, nil
}

View File

@ -25,8 +25,7 @@ import (
"regexp"
"strings"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/kubectl/pkg/util/prune"
"github.com/jonboulle/clockwork"
"github.com/spf13/cobra"
@ -36,6 +35,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/discovery"
@ -110,25 +110,18 @@ type DiffOptions struct {
FieldManager string
ForceConflicts bool
Selector string
OpenAPISchema openapi.Resources
DiscoveryClient discovery.DiscoveryInterface
DynamicClient dynamic.Interface
DryRunVerifier *resource.DryRunVerifier
CmdNamespace string
EnforceNamespace bool
Builder *resource.Builder
Diff *DiffProgram
Mapper meta.RESTMapper
Prune bool
PruneResources []pruneResource
VisitedUids sets.String
VisitedNamespaces sets.String
ToPrinter func(string) (printers.ResourcePrinter, error)
PrintFlags *genericclioptions.PrintFlags
All bool
PruneWhitelist []string
genericclioptions.IOStreams
Selector string
OpenAPISchema openapi.Resources
DiscoveryClient discovery.DiscoveryInterface
DynamicClient dynamic.Interface
DryRunVerifier *resource.DryRunVerifier
CmdNamespace string
EnforceNamespace bool
Builder *resource.Builder
Diff *DiffProgram
Prune bool
PruneWhitelist []string
pruner *pruner
}
func validateArgs(cmd *cobra.Command, args []string) error {
@ -144,10 +137,10 @@ func NewDiffOptions(ioStreams genericclioptions.IOStreams) *DiffOptions {
Exec: exec.New(),
IOStreams: ioStreams,
},
VisitedUids: sets.NewString(),
VisitedNamespaces: sets.NewString(),
PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
IOStreams: ioStreams,
pruner: &pruner{
visitedUids: sets.NewString(),
visitedNamespaces: sets.NewString(),
},
}
}
@ -162,7 +155,6 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckDiffErr(options.Complete(f, cmd))
cmdutil.CheckDiffErr(validateArgs(cmd, args))
cmdutil.CheckErr(validatePruneAll(options.Prune, options.All, options.Selector))
// `kubectl diff` propagates the error code from
// diff or `KUBECTL_EXTERNAL_DIFF`. Also, we
// don't want to print an error if diff returns
@ -189,8 +181,7 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
usage := "contains the configuration to diff"
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().StringArrayVar(&options.PruneWhitelist, "prune-whitelist", options.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
cmd.Flags().BoolVar(&options.Prune, "prune", options.Prune, "Automatically diff for possibly will be deleted resource objects, Should be used with either -l or --all.")
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types.")
cmd.Flags().BoolVar(&options.Prune, "prune", options.Prune, "Automatically diff for possibly will be deleted resource objects, Should be used with either -l or --prune-all.")
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmdutil.AddServerSideApplyFlags(cmd)
cmdutil.AddFieldManagerFlagVar(cmd, &options.FieldManager, apply.FieldManagerClientSideApply)
@ -198,16 +189,6 @@ func NewCmdDiff(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
return cmd
}
func validatePruneAll(prune, all bool, selector string) error {
if all && len(selector) > 0 {
return fmt.Errorf("cannot set --all and --selector at the same time")
}
if prune && !all && selector == "" {
return fmt.Errorf("all resources selected for prune without explicitly passing --all. To prune all resources, pass the --all flag. If you did not mean to prune all resources, specify a label selector")
}
return nil
}
// DiffProgram finds and run the diff program. The value of
// KUBECTL_EXTERNAL_DIFF environment variable will be used a diff
// program. By default, `diff(1)` will be used.
@ -649,12 +630,6 @@ func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return fmt.Errorf("--force-conflicts only works with --server-side")
}
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
o.PrintFlags.NamePrintFlags.Operation = operation
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, cmdutil.DryRunServer)
return o.PrintFlags.ToPrinter()
}
if !o.ServerSideApply {
o.OpenAPISchema, err = f.OpenAPISchema()
if err != nil {
@ -680,12 +655,13 @@ func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
}
if o.Prune {
o.Mapper, err = f.ToRESTMapper()
o.pruner.dynamicClient = o.DynamicClient
o.pruner.mapper, err = f.ToRESTMapper()
if err != nil {
return err
}
o.PruneResources, err = parsePruneResources(o.Mapper, o.PruneWhitelist)
o.pruner.resources, err = prune.ParseResources(o.pruner.mapper, o.PruneWhitelist)
if err != nil {
return err
}
@ -756,9 +732,9 @@ func (o *DiffOptions) Run() error {
IOStreams: o.Diff.IOStreams,
}
o.markVisited(info)
err = differ.Diff(obj, printer)
o.MarkNamespaceVisited(info)
o.MarkObjectVisited(info)
if !isConflict(err) {
break
}
@ -770,8 +746,18 @@ func (o *DiffOptions) Run() error {
})
if o.Prune {
prune := newPruner(o)
prune.pruneAll(o)
prunedObjs, err := o.pruner.pruneAll()
if err != nil {
klog.Warningf("pruning failed and could not be evaluated err: %v", err)
}
// Print pruned objects into old file and thus, diff
// command will show them as pruned.
for _, p := range prunedObjs {
if err := differ.From.Print(o.pruner.GetObjectName(p), p, printer); err != nil {
return err
}
}
}
if err != nil {
@ -781,21 +767,14 @@ func (o *DiffOptions) Run() error {
return differ.Run(o.Diff)
}
// MarkObjectVisited keeps track of UIDs of the applied
// objects. Used for pruning.
func (o *DiffOptions) MarkObjectVisited(info *resource.Info) error {
func (o *DiffOptions) markVisited(info *resource.Info) {
if info.Namespaced() {
o.pruner.visitedNamespaces.Insert(info.Namespace)
}
metadata, err := meta.Accessor(info.Object)
if err != nil {
return err
}
o.VisitedUids.Insert(string(metadata.GetUID()))
return nil
}
// MarkNamespaceVisited keeps track of which namespaces the applied
// objects belong to. Used for pruning.
func (o *DiffOptions) MarkNamespaceVisited(info *resource.Info) {
if info.Namespaced() {
o.VisitedNamespaces.Insert(info.Namespace)
return
}
o.pruner.visitedUids.Insert(string(metadata.GetUID()))
}

View File

@ -19,15 +19,17 @@ package diff
import (
"context"
"fmt"
"io"
"strings"
"k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubectl/pkg/util/prune"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/client-go/dynamic"
)
@ -38,199 +40,73 @@ type pruner struct {
visitedUids sets.String
visitedNamespaces sets.String
labelSelector string
fieldSelector string
cascadingStrategy metav1.DeletionPropagation
gracePeriod int
toPrinter func(string) (printers.ResourcePrinter, error)
out io.Writer
resources []prune.Resource
}
func newPruner(o *DiffOptions) pruner {
return pruner{
mapper: o.Mapper,
dynamicClient: o.DynamicClient,
labelSelector: o.Selector,
visitedUids: o.VisitedUids,
visitedNamespaces: o.VisitedNamespaces,
toPrinter: o.ToPrinter,
cascadingStrategy: metav1.DeletePropagationBackground,
gracePeriod: -1,
out: o.ErrOut,
}
}
func (p *pruner) pruneAll(o *DiffOptions) error {
namespacedRESTMappings, nonNamespacedRESTMappings, err := getRESTMappings(o.Mapper, &(o.PruneResources))
func (p *pruner) pruneAll() ([]runtime.Object, error) {
var allPruned []runtime.Object
namespacedRESTMappings, nonNamespacedRESTMappings, err := prune.GetRESTMappings(p.mapper, &(p.resources))
if err != nil {
return fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
return allPruned, fmt.Errorf("error retrieving RESTMappings to prune: %v", err)
}
for n := range p.visitedNamespaces {
for _, m := range namespacedRESTMappings {
if err := p.prune(n, m); err != nil {
return fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
if pobjs, err := p.prune(n, m); err != nil {
return pobjs, fmt.Errorf("error pruning namespaced object %v: %v", m.GroupVersionKind, err)
} else {
allPruned = append(allPruned, pobjs...)
}
}
}
for _, m := range nonNamespacedRESTMappings {
if err := p.prune(metav1.NamespaceNone, m); err != nil {
return fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
if pobjs, err := p.prune(metav1.NamespaceNone, m); err != nil {
return allPruned, fmt.Errorf("error pruning nonNamespaced object %v: %v", m.GroupVersionKind, err)
} else {
allPruned = append(allPruned, pobjs...)
}
}
return nil
return allPruned, nil
}
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping) error {
func (p *pruner) prune(namespace string, mapping *meta.RESTMapping) ([]runtime.Object, error) {
objList, err := p.dynamicClient.Resource(mapping.Resource).
Namespace(namespace).
List(context.TODO(), metav1.ListOptions{
LabelSelector: p.labelSelector,
FieldSelector: p.fieldSelector,
})
if err != nil {
return err
return nil, err
}
objs, err := meta.ExtractList(objList)
if err != nil {
return err
return nil, err
}
var pobjs []runtime.Object
for _, obj := range objs {
metadata, err := meta.Accessor(obj)
if err != nil {
return err
return pobjs, err
}
annots := metadata.GetAnnotations()
if _, ok := annots[corev1.LastAppliedConfigAnnotation]; !ok {
// don't prune resources not created with apply
continue
}
uid := metadata.GetUID()
if p.visitedUids.Has(string(uid)) {
continue
}
name := metadata.GetName()
if err := p.delete(namespace, name, mapping); err != nil {
return err
}
printer, err := p.toPrinter("pruned")
if err != nil {
return err
}
printer.PrintObj(obj, p.out)
pobjs = append(pobjs, obj)
}
return nil
return pobjs, nil
}
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping) error {
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascadingStrategy, p.gracePeriod, true)
}
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascadingStrategy metav1.DeletionPropagation, gracePeriod int, serverDryRun bool) error {
options := asDeleteOptions(cascadingStrategy, gracePeriod)
if serverDryRun {
options.DryRun = []string{metav1.DryRunAll}
}
return c.Resource(mapping.Resource).Namespace(namespace).Delete(context.TODO(), name, options)
}
func asDeleteOptions(cascadingStrategy metav1.DeletionPropagation, gracePeriod int) metav1.DeleteOptions {
options := metav1.DeleteOptions{}
if gracePeriod >= 0 {
options = *metav1.NewDeleteOptions(int64(gracePeriod))
}
options.PropagationPolicy = &cascadingStrategy
return options
}
type pruneResource struct {
group string
version string
kind string
namespaced bool
}
func (pr pruneResource) String() string {
return fmt.Sprintf("%v/%v, Kind=%v, Namespaced=%v", pr.group, pr.version, pr.kind, pr.namespaced)
}
func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (namespaced, nonNamespaced []*meta.RESTMapping, err error) {
if len(*pruneResources) == 0 {
// default allowlist
*pruneResources = []pruneResource{
{"", "v1", "ConfigMap", true},
{"", "v1", "Endpoints", true},
{"", "v1", "Namespace", false},
{"", "v1", "PersistentVolumeClaim", true},
{"", "v1", "PersistentVolume", false},
{"", "v1", "Pod", true},
{"", "v1", "ReplicationController", true},
{"", "v1", "Secret", true},
{"", "v1", "Service", true},
{"batch", "v1", "Job", true},
{"batch", "v1", "CronJob", true},
{"networking.k8s.io", "v1", "Ingress", true},
{"apps", "v1", "DaemonSet", true},
{"apps", "v1", "Deployment", true},
{"apps", "v1", "ReplicaSet", true},
{"apps", "v1", "StatefulSet", true},
}
}
for _, resource := range *pruneResources {
addedMapping, err := mapper.RESTMapping(schema.GroupKind{Group: resource.group, Kind: resource.kind}, resource.version)
if err != nil {
return nil, nil, fmt.Errorf("invalid resource %v: %v", resource, err)
}
if resource.namespaced {
namespaced = append(namespaced, addedMapping)
} else {
nonNamespaced = append(nonNamespaced, addedMapping)
}
}
return namespaced, nonNamespaced, nil
}
func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource, error) {
pruneResources := []pruneResource{}
for _, groupVersionKind := range gvks {
gvk := strings.Split(groupVersionKind, "/")
if len(gvk) != 3 {
return nil, fmt.Errorf("invalid GroupVersionKind format: %v, please follow <group/version/kind>", groupVersionKind)
}
if gvk[0] == "core" {
gvk[0] = ""
}
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk[0], Kind: gvk[2]}, gvk[1])
if err != nil {
return pruneResources, err
}
var namespaced bool
namespaceScope := mapping.Scope.Name()
switch namespaceScope {
case meta.RESTScopeNameNamespace:
namespaced = true
case meta.RESTScopeNameRoot:
namespaced = false
default:
return pruneResources, fmt.Errorf("Unknown namespace scope: %q", namespaceScope)
}
pruneResources = append(pruneResources, pruneResource{gvk[0], gvk[1], gvk[2], namespaced})
}
return pruneResources, nil
func (p *pruner) GetObjectName(obj runtime.Object) string {
// Not compare anything, it is safe to assign random
// object name.
return string(uuid.NewUUID())
}

View File

@ -0,0 +1,89 @@
package prune
import (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
)
type Resource struct {
group string
version string
kind string
namespaced bool
}
func (pr Resource) String() string {
return fmt.Sprintf("%v/%v, Kind=%v, Namespaced=%v", pr.group, pr.version, pr.kind, pr.namespaced)
}
func GetRESTMappings(mapper meta.RESTMapper, pruneResources *[]Resource) (namespaced, nonNamespaced []*meta.RESTMapping, err error) {
if len(*pruneResources) == 0 {
// default allowlist
*pruneResources = []Resource{
{"", "v1", "ConfigMap", true},
{"", "v1", "Endpoints", true},
{"", "v1", "Namespace", false},
{"", "v1", "PersistentVolumeClaim", true},
{"", "v1", "PersistentVolume", false},
{"", "v1", "Pod", true},
{"", "v1", "ReplicationController", true},
{"", "v1", "Secret", true},
{"", "v1", "Service", true},
{"batch", "v1", "Job", true},
{"batch", "v1", "CronJob", true},
{"networking.k8s.io", "v1", "Ingress", true},
{"apps", "v1", "DaemonSet", true},
{"apps", "v1", "Deployment", true},
{"apps", "v1", "ReplicaSet", true},
{"apps", "v1", "StatefulSet", true},
}
}
for _, resource := range *pruneResources {
addedMapping, err := mapper.RESTMapping(schema.GroupKind{Group: resource.group, Kind: resource.kind}, resource.version)
if err != nil {
return nil, nil, fmt.Errorf("invalid resource %v: %v", resource, err)
}
if resource.namespaced {
namespaced = append(namespaced, addedMapping)
} else {
nonNamespaced = append(nonNamespaced, addedMapping)
}
}
return namespaced, nonNamespaced, nil
}
func ParseResources(mapper meta.RESTMapper, gvks []string) ([]Resource, error) {
pruneResources := []Resource{}
for _, groupVersionKind := range gvks {
gvk := strings.Split(groupVersionKind, "/")
if len(gvk) != 3 {
return nil, fmt.Errorf("invalid GroupVersionKind format: %v, please follow <group/version/kind>", groupVersionKind)
}
if gvk[0] == "core" {
gvk[0] = ""
}
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: gvk[0], Kind: gvk[2]}, gvk[1])
if err != nil {
return pruneResources, err
}
var namespaced bool
namespaceScope := mapping.Scope.Name()
switch namespaceScope {
case meta.RESTScopeNameNamespace:
namespaced = true
case meta.RESTScopeNameRoot:
namespaced = false
default:
return pruneResources, fmt.Errorf("Unknown namespace scope: %q", namespaceScope)
}
pruneResources = append(pruneResources, Resource{gvk[0], gvk[1], gvk[2], namespaced})
}
return pruneResources, nil
}

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package diff
package prune
import (
"testing"
@ -46,11 +46,38 @@ func (m *testRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*
}, nil
}
func TestGetRESTMappings(t *testing.T) {
tests := []struct {
mapper *testRESTMapper
pr *[]Resource
expectedns int
expectednns int
expectederr error
}{
{
mapper: &testRESTMapper{},
pr: &[]Resource{},
expectedns: 14,
expectednns: 2,
expectederr: nil,
},
}
for _, tc := range tests {
actualns, actualnns, actualerr := GetRESTMappings(tc.mapper, tc.pr)
if tc.expectederr != nil {
assert.NotEmptyf(t, actualerr, "getRESTMappings error expected but not fired")
}
assert.Equal(t, len(actualns), tc.expectedns, "getRESTMappings failed expected number namespaced %d actual %d", tc.expectedns, len(actualns))
assert.Equal(t, len(actualnns), tc.expectednns, "getRESTMappings failed expected number nonnamespaced %d actual %d", tc.expectednns, len(actualnns))
}
}
func TestParsePruneResources(t *testing.T) {
tests := []struct {
mapper *testRESTMapper
gvks []string
expected []pruneResource
expected []Resource
err bool
}{
{
@ -58,7 +85,7 @@ func TestParsePruneResources(t *testing.T) {
scope: meta.RESTScopeNamespace,
},
gvks: nil,
expected: []pruneResource{},
expected: []Resource{},
err: false,
},
{
@ -66,7 +93,7 @@ func TestParsePruneResources(t *testing.T) {
scope: meta.RESTScopeNamespace,
},
gvks: []string{"group/kind/version/test"},
expected: []pruneResource{},
expected: []Resource{},
err: true,
},
{
@ -74,7 +101,7 @@ func TestParsePruneResources(t *testing.T) {
scope: meta.RESTScopeNamespace,
},
gvks: []string{"group/kind/version"},
expected: []pruneResource{{group: "group", version: "kind", kind: "version", namespaced: true}},
expected: []Resource{{group: "group", version: "kind", kind: "version", namespaced: true}},
err: false,
},
{
@ -82,13 +109,13 @@ func TestParsePruneResources(t *testing.T) {
scope: meta.RESTScopeRoot,
},
gvks: []string{"group/kind/version"},
expected: []pruneResource{{group: "group", version: "kind", kind: "version", namespaced: false}},
expected: []Resource{{group: "group", version: "kind", kind: "version", namespaced: false}},
err: false,
},
}
for _, tc := range tests {
actual, err := parsePruneResources(tc.mapper, tc.gvks)
actual, err := ParseResources(tc.mapper, tc.gvks)
if tc.err {
assert.NotEmptyf(t, err, "parsePruneResources error expected but not fired")
} else {