...

Source file src/sigs.k8s.io/cli-utils/pkg/object/dependson/annotation_test.go

Documentation: sigs.k8s.io/cli-utils/pkg/object/dependson

     1  // Copyright 2021 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  //
     4  
     5  package dependson
     6  
     7  import (
     8  	"testing"
     9  
    10  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    11  )
    12  
    13  var u1 = &unstructured.Unstructured{
    14  	Object: map[string]interface{}{
    15  		"apiVersion": "v1",
    16  		"kind":       "ConfigMap",
    17  		"metadata": map[string]interface{}{
    18  			"name":      "unused",
    19  			"namespace": "unused",
    20  			"annotations": map[string]interface{}{
    21  				Annotation: "test-group/test-kind/cluster-obj",
    22  			},
    23  		},
    24  	},
    25  }
    26  
    27  var u2 = &unstructured.Unstructured{
    28  	Object: map[string]interface{}{
    29  		"apiVersion": "v1",
    30  		"kind":       "ConfigMap",
    31  		"metadata": map[string]interface{}{
    32  			"name":      "unused",
    33  			"namespace": "unused",
    34  			"annotations": map[string]interface{}{
    35  				Annotation: "test-group/namespaces/test-namespace/test-kind/namespaced-obj",
    36  			},
    37  		},
    38  	},
    39  }
    40  
    41  var multipleAnnotations = &unstructured.Unstructured{
    42  	Object: map[string]interface{}{
    43  		"apiVersion": "v1",
    44  		"kind":       "ConfigMap",
    45  		"metadata": map[string]interface{}{
    46  			"name":      "unused",
    47  			"namespace": "unused",
    48  			"annotations": map[string]interface{}{
    49  				Annotation: "test-group/namespaces/test-namespace/test-kind/namespaced-obj," +
    50  					"test-group/test-kind/cluster-obj",
    51  			},
    52  		},
    53  	},
    54  }
    55  
    56  var noAnnotations = &unstructured.Unstructured{
    57  	Object: map[string]interface{}{
    58  		"apiVersion": "v1",
    59  		"kind":       "ConfigMap",
    60  		"metadata": map[string]interface{}{
    61  			"name":      "unused",
    62  			"namespace": "unused",
    63  		},
    64  	},
    65  }
    66  
    67  var badAnnotation = &unstructured.Unstructured{
    68  	Object: map[string]interface{}{
    69  		"apiVersion": "v1",
    70  		"kind":       "ConfigMap",
    71  		"metadata": map[string]interface{}{
    72  			"name":      "unused",
    73  			"namespace": "unused",
    74  			"annotations": map[string]interface{}{
    75  				Annotation: "test-group:namespaces:test-namespace:test-kind:namespaced-obj",
    76  			},
    77  		},
    78  	},
    79  }
    80  
    81  func TestReadAnnotation(t *testing.T) {
    82  	testCases := map[string]struct {
    83  		obj      *unstructured.Unstructured
    84  		expected DependencySet
    85  		isError  bool
    86  	}{
    87  		"nil object is not found": {
    88  			obj:      nil,
    89  			expected: DependencySet{},
    90  		},
    91  		"Object with no annotations returns not found": {
    92  			obj:      noAnnotations,
    93  			expected: DependencySet{},
    94  		},
    95  		"Unparseable depends on annotation returns not found": {
    96  			obj:      badAnnotation,
    97  			expected: DependencySet{},
    98  			isError:  true,
    99  		},
   100  		"Cluster-scoped object depends on annotation": {
   101  			obj:      u1,
   102  			expected: DependencySet{clusterScopedObj},
   103  		},
   104  		"Namespaced object depends on annotation": {
   105  			obj:      u2,
   106  			expected: DependencySet{namespacedObj},
   107  		},
   108  		"Multiple objects specified in annotation": {
   109  			obj:      multipleAnnotations,
   110  			expected: DependencySet{namespacedObj, clusterScopedObj},
   111  		},
   112  	}
   113  
   114  	for tn, tc := range testCases {
   115  		t.Run(tn, func(t *testing.T) {
   116  			actual, err := ReadAnnotation(tc.obj)
   117  			if tc.isError {
   118  				if err == nil {
   119  					t.Fatalf("expected error not received")
   120  				}
   121  			} else {
   122  				if err != nil {
   123  					t.Fatalf("unexpected error received: %s", err)
   124  				}
   125  				if !actual.Equal(tc.expected) {
   126  					t.Errorf("expected (%s), got (%s)", tc.expected, actual)
   127  				}
   128  			}
   129  		})
   130  	}
   131  }
   132  
   133  // getDependsOnAnnotation wraps the depends-on annotation with a pointer.
   134  // Returns nil if the annotation is missing.
   135  func getDependsOnAnnotation(obj *unstructured.Unstructured) *string {
   136  	value, found := obj.GetAnnotations()[Annotation]
   137  	if !found {
   138  		return nil
   139  	}
   140  	return &value
   141  }
   142  
   143  func TestWriteAnnotation(t *testing.T) {
   144  	testCases := map[string]struct {
   145  		obj       *unstructured.Unstructured
   146  		dependson DependencySet
   147  		expected  *string
   148  		isError   bool
   149  	}{
   150  		"nil object": {
   151  			obj:       nil,
   152  			dependson: DependencySet{},
   153  			expected:  nil,
   154  			isError:   true,
   155  		},
   156  		"empty mutation": {
   157  			obj:       &unstructured.Unstructured{},
   158  			dependson: DependencySet{},
   159  			expected:  nil,
   160  			isError:   true,
   161  		},
   162  		"Namespace-scoped object": {
   163  			obj:       &unstructured.Unstructured{},
   164  			dependson: DependencySet{namespacedObj},
   165  			expected:  getDependsOnAnnotation(u2),
   166  		},
   167  		"Cluster-scoped object": {
   168  			obj:       &unstructured.Unstructured{},
   169  			dependson: DependencySet{clusterScopedObj},
   170  			expected:  getDependsOnAnnotation(u1),
   171  		},
   172  		"Multiple objects": {
   173  			obj:       &unstructured.Unstructured{},
   174  			dependson: DependencySet{namespacedObj, clusterScopedObj},
   175  			expected:  getDependsOnAnnotation(multipleAnnotations),
   176  		},
   177  	}
   178  
   179  	for tn, tc := range testCases {
   180  		t.Run(tn, func(t *testing.T) {
   181  			err := WriteAnnotation(tc.obj, tc.dependson)
   182  			if tc.isError {
   183  				if err == nil {
   184  					t.Fatalf("expected error not received")
   185  				}
   186  			} else {
   187  				if err != nil {
   188  					t.Fatalf("unexpected error received: %s", err)
   189  				}
   190  				received := getDependsOnAnnotation(tc.obj)
   191  				if received != tc.expected && (received == nil || tc.expected == nil) {
   192  					t.Errorf("\nexpected:\t%#v\nreceived:\t%#v", tc.expected, received)
   193  				}
   194  				if *received != *tc.expected {
   195  					t.Errorf("\nexpected:\t%#v\nreceived:\t%#v", *tc.expected, *received)
   196  				}
   197  			}
   198  		})
   199  	}
   200  }
   201  

View as plain text