github.com/argoproj/argo-cd/v3@v3.2.1/server/deeplinks/deeplinks_test.go (about) 1 package deeplinks 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 8 "github.com/argoproj/gitops-engine/pkg/utils/kube" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 corev1 "k8s.io/api/core/v1" 12 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 14 "k8s.io/utils/ptr" 15 16 "github.com/argoproj/argo-cd/v3/pkg/apiclient/application" 17 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 18 "github.com/argoproj/argo-cd/v3/util/settings" 19 ) 20 21 type deepLinkTC struct { 22 name string 23 appObj *unstructured.Unstructured 24 clusterObj *unstructured.Unstructured 25 resourceObj *unstructured.Unstructured 26 projectObj *unstructured.Unstructured 27 inputLinks []settings.DeepLink 28 outputLinks []*application.LinkInfo 29 error []string 30 } 31 32 func TestDeepLinks(t *testing.T) { 33 t.Parallel() 34 35 appObj, err := kube.ToUnstructured(&v1alpha1.Application{ 36 ObjectMeta: metav1.ObjectMeta{ 37 Name: "test", 38 Namespace: "test", 39 }, 40 Spec: v1alpha1.ApplicationSpec{ 41 Destination: v1alpha1.ApplicationDestination{ 42 Server: "test.example.com", 43 Namespace: "testns", 44 }, 45 }, 46 }) 47 require.NoError(t, err) 48 resourceObj, err := kube.ToUnstructured(&corev1.ConfigMap{ 49 ObjectMeta: metav1.ObjectMeta{ 50 Name: "test-cm", 51 Namespace: "test-cm", 52 Labels: map[string]string{"test-label": "cm-value"}, 53 }, 54 Data: map[string]string{ 55 "key": "value1", 56 }, 57 }) 58 require.NoError(t, err) 59 clusterObj, err := kube.ToUnstructured(&ClusterLinksData{ 60 Server: "test-svc.com", 61 Name: "test-cluster", 62 }) 63 require.NoError(t, err) 64 projectObj, err := kube.ToUnstructured(&v1alpha1.AppProject{ 65 ObjectMeta: metav1.ObjectMeta{ 66 Name: "test-project", 67 Namespace: "test-project", 68 }, 69 Spec: v1alpha1.AppProjectSpec{ 70 SourceRepos: []string{"test-repo.git"}, 71 }, 72 }) 73 require.NoError(t, err) 74 testTable := []deepLinkTC{ 75 { 76 name: "link to git repo per cluster", 77 appObj: appObj, 78 resourceObj: resourceObj, 79 projectObj: projectObj, 80 clusterObj: clusterObj, 81 inputLinks: []settings.DeepLink{{ 82 Title: "link", 83 URL: "http://example.com/{{ .application.metadata.name }}&{{ .resource.data.key }}&{{ index .project.spec.sourceRepos 0}}&{{ .cluster.name }}", 84 Condition: ptr.To(`application.metadata.name == "test" && project.metadata.name == "test-project"`), 85 }}, 86 outputLinks: []*application.LinkInfo{{ 87 Title: ptr.To("link"), 88 Url: ptr.To("http://example.com/test&value1&test-repo.git&test-cluster"), 89 }}, 90 error: []string{}, 91 }, 92 { 93 name: "link to git repo per cluster with abbreviated name", 94 appObj: appObj, 95 resourceObj: resourceObj, 96 projectObj: projectObj, 97 clusterObj: clusterObj, 98 inputLinks: []settings.DeepLink{{ 99 Title: "link", 100 URL: "http://example.com/{{ .app.metadata.name }}&{{ .resource.data.key }}&{{ index .project.spec.sourceRepos 0}}&{{ .cluster.name }}", 101 Condition: ptr.To(`app.metadata.name == "test" && project.metadata.name == "test-project"`), 102 }}, 103 outputLinks: []*application.LinkInfo{{ 104 Title: ptr.To("link"), 105 Url: ptr.To("http://example.com/test&value1&test-repo.git&test-cluster"), 106 }}, 107 error: []string{}, 108 }, 109 { 110 name: "condition on missing key", 111 appObj: appObj, 112 resourceObj: resourceObj, 113 projectObj: projectObj, 114 inputLinks: []settings.DeepLink{ 115 { 116 Title: "link", 117 URL: "http://example.com/{{ .application.metadata.name }}&{{ .application.spec.destination.namespace }}", 118 Condition: ptr.To(`application.metadata.name matches "test"`), 119 }, 120 { 121 Title: "link1", 122 URL: "http://example.com/{{ .application.metadata.name }}&{{ .application.spec.destination.namespace }}", 123 Condition: ptr.To(`application.metadata.name matches "test1"`), 124 }, 125 { 126 Title: "link2", 127 URL: "http://example.com/{{ .application.metadata.name }}&{{ .application.spec.destination.namespace }}", 128 Condition: ptr.To(`application.metadata.test matches "test"`), 129 }, 130 }, 131 outputLinks: []*application.LinkInfo{{ 132 Title: ptr.To("link"), 133 Url: ptr.To("http://example.com/test&testns"), 134 }}, 135 error: []string{}, 136 }, 137 { 138 name: "condition on invalid expression", 139 appObj: appObj, 140 resourceObj: resourceObj, 141 projectObj: projectObj, 142 inputLinks: []settings.DeepLink{ 143 { 144 Title: "link", 145 URL: "http://example.com/{{ .application.metadata.name }}&{{ .application.spec.destination.namespace }}", 146 Condition: ptr.To(`application.metadata.name matches "test"`), 147 }, 148 { 149 Title: "link1", 150 URL: "http://example.com/{{ .application.metadata.name }}&{{ .application.spec.destination.namespace }}", 151 Condition: ptr.To(`1 + 1`), 152 }, 153 }, 154 outputLinks: []*application.LinkInfo{{ 155 Title: ptr.To("link"), 156 Url: ptr.To("http://example.com/test&testns"), 157 }}, 158 error: []string{"link condition '1 + 1' evaluated to non-boolean value for resource test"}, 159 }, 160 { 161 name: "condition on app and project name", 162 appObj: appObj, 163 resourceObj: resourceObj, 164 projectObj: projectObj, 165 clusterObj: clusterObj, 166 inputLinks: []settings.DeepLink{{ 167 Title: "link", 168 URL: "http://example.com/{{ .cluster.name | replace \"-\" \"_\" }}&{{ first .project.spec.sourceRepos }}", 169 Condition: ptr.To(`application.metadata.name == "test" && project.metadata.name == "test-project"`), 170 }}, 171 outputLinks: []*application.LinkInfo{{ 172 Title: ptr.To("link"), 173 Url: ptr.To("http://example.com/test_cluster&test-repo.git"), 174 }}, 175 error: []string{}, 176 }, 177 { 178 name: "evaluate template for valid condition", 179 appObj: appObj, 180 resourceObj: resourceObj, 181 projectObj: projectObj, 182 inputLinks: []settings.DeepLink{ 183 { 184 Title: "link", 185 URL: "http://not-evaluated.com/{{ index \"invalid\" .application.metadata.labels }}", 186 Condition: ptr.To(`false`), 187 }, 188 { 189 Title: "link", 190 URL: "http://evaluated.com/{{ index \"invalid\" .application.metadata.labels }}", 191 Condition: ptr.To(`true`), 192 }, 193 }, 194 outputLinks: []*application.LinkInfo{}, 195 error: []string{ 196 "failed to evaluate link template 'http://evaluated.com/{{ index \"invalid\" .application.metadata.labels }}' with resource test, error=template: deep-link:1:24: executing \"deep-link\" at <index \"invalid\" .application.metadata.labels>: error calling index: cannot index slice/array with nil", 197 }, 198 }, 199 } 200 201 for _, tc := range testTable { 202 tcc := tc 203 t.Run(tc.name, func(t *testing.T) { 204 t.Parallel() 205 objs := CreateDeepLinksObject(tcc.resourceObj, tcc.appObj, tcc.clusterObj, tcc.projectObj) 206 output, err := EvaluateDeepLinksResponse(objs, tcc.appObj.GetName(), tcc.inputLinks) 207 assert.Equal(t, tcc.error, err, strings.Join(err, ",")) 208 assert.True(t, reflect.DeepEqual(output.Items, tcc.outputLinks)) 209 }) 210 } 211 }