github.com/oam-dev/kubevela@v1.9.11/pkg/controller/core.oam.dev/v1beta1/application/generator_test.go (about) 1 /*Copyright 2021 The KubeVela Authors. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package application 17 18 import ( 19 "context" 20 "encoding/json" 21 "strconv" 22 "time" 23 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 corev1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime" 29 "sigs.k8s.io/yaml" 30 31 monitorContext "github.com/kubevela/pkg/monitor/context" 32 workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1" 33 34 "github.com/oam-dev/kubevela/apis/core.oam.dev/common" 35 oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" 36 "github.com/oam-dev/kubevela/pkg/oam/util" 37 ) 38 39 var _ = Describe("Test Application workflow generator", func() { 40 var namespaceName string 41 var ns corev1.Namespace 42 var ctx context.Context 43 44 BeforeEach(func() { 45 namespaceName = "generate-test-" + strconv.Itoa(time.Now().Second()) + "-" + strconv.Itoa(time.Now().Nanosecond()) 46 ctx = context.WithValue(context.TODO(), util.AppDefinitionNamespace, namespaceName) 47 ns = corev1.Namespace{ 48 ObjectMeta: metav1.ObjectMeta{ 49 Name: namespaceName, 50 }, 51 } 52 By("Create the Namespace for test") 53 Expect(k8sClient.Create(ctx, &ns)).Should(Succeed()) 54 55 healthComponentDef := &oamcore.ComponentDefinition{} 56 hCDefJson, _ := yaml.YAMLToJSON([]byte(cdDefWithHealthStatusYaml)) 57 Expect(json.Unmarshal(hCDefJson, healthComponentDef)).Should(BeNil()) 58 healthComponentDef.Name = "worker-with-health" 59 healthComponentDef.Namespace = namespaceName 60 61 By("Create the Component Definition for test") 62 Expect(k8sClient.Create(ctx, healthComponentDef)).Should(Succeed()) 63 }) 64 65 AfterEach(func() { 66 By("[TEST] Clean up resources after an integration test") 67 Expect(k8sClient.Delete(context.TODO(), &ns)).Should(Succeed()) 68 }) 69 70 It("Test generate application workflow with inputs and outputs", func() { 71 app := &oamcore.Application{ 72 TypeMeta: metav1.TypeMeta{ 73 Kind: "Application", 74 APIVersion: "core.oam.dev/v1beta1", 75 }, 76 ObjectMeta: metav1.ObjectMeta{ 77 Name: "app-with-input-output", 78 Namespace: namespaceName, 79 }, 80 Spec: oamcore.ApplicationSpec{ 81 Components: []common.ApplicationComponent{ 82 { 83 Name: "myweb1", 84 Type: "worker-with-health", 85 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 86 Inputs: workflowv1alpha1.StepInputs{ 87 { 88 From: "message", 89 ParameterKey: "properties.enemies", 90 }, 91 { 92 From: "message", 93 ParameterKey: "properties.lives", 94 }, 95 }, 96 }, 97 { 98 Name: "myweb2", 99 Type: "worker-with-health", 100 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, 101 Outputs: workflowv1alpha1.StepOutputs{ 102 { 103 Name: "message", 104 ValueFrom: "output.status.conditions[0].message+\",\"+outputs.gameconfig.data.lives", 105 }, 106 }, 107 }, 108 }, 109 }, 110 } 111 af, err := appParser.GenerateAppFile(ctx, app) 112 Expect(err).Should(BeNil()) 113 _, err = af.GeneratePolicyManifests(context.Background()) 114 Expect(err).Should(BeNil()) 115 116 handler, err := NewAppHandler(ctx, reconciler, app) 117 Expect(err).Should(Succeed()) 118 119 logCtx := monitorContext.NewTraceContext(ctx, "") 120 handler.currentAppRev = &oamcore.ApplicationRevision{} 121 handler.CheckWorkflowRestart(logCtx, app) 122 123 _, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af) 124 Expect(err).To(BeNil()) 125 Expect(len(taskRunner)).Should(BeEquivalentTo(2)) 126 Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1")) 127 Expect(taskRunner[1].Name()).Should(BeEquivalentTo("myweb2")) 128 }) 129 130 It("Test generate application workflow without inputs and outputs", func() { 131 app := &oamcore.Application{ 132 TypeMeta: metav1.TypeMeta{ 133 Kind: "Application", 134 APIVersion: "core.oam.dev/v1beta1", 135 }, 136 ObjectMeta: metav1.ObjectMeta{ 137 Name: "app-without-input-output", 138 Namespace: namespaceName, 139 }, 140 Spec: oamcore.ApplicationSpec{ 141 Components: []common.ApplicationComponent{ 142 { 143 Name: "myweb1", 144 Type: "worker-with-health", 145 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 146 }, 147 { 148 Name: "myweb2", 149 Type: "worker-with-health", 150 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, 151 }, 152 }, 153 }, 154 } 155 af, err := appParser.GenerateAppFile(ctx, app) 156 Expect(err).Should(BeNil()) 157 _, err = af.GeneratePolicyManifests(context.Background()) 158 Expect(err).Should(BeNil()) 159 160 handler, err := NewAppHandler(ctx, reconciler, app) 161 Expect(err).Should(Succeed()) 162 163 logCtx := monitorContext.NewTraceContext(ctx, "") 164 handler.currentAppRev = &oamcore.ApplicationRevision{} 165 handler.CheckWorkflowRestart(logCtx, app) 166 _, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af) 167 Expect(err).To(BeNil()) 168 Expect(len(taskRunner)).Should(BeEquivalentTo(2)) 169 Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1")) 170 Expect(taskRunner[1].Name()).Should(BeEquivalentTo("myweb2")) 171 }) 172 173 It("Test generate application workflow with dependsOn", func() { 174 app := &oamcore.Application{ 175 TypeMeta: metav1.TypeMeta{ 176 Kind: "Application", 177 APIVersion: "core.oam.dev/v1beta1", 178 }, 179 ObjectMeta: metav1.ObjectMeta{ 180 Name: "app-with-input-output", 181 Namespace: namespaceName, 182 }, 183 Spec: oamcore.ApplicationSpec{ 184 Components: []common.ApplicationComponent{ 185 { 186 Name: "myweb1", 187 Type: "worker-with-health", 188 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 189 }, 190 { 191 Name: "myweb2", 192 Type: "worker-with-health", 193 DependsOn: []string{"myweb1"}, 194 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, 195 }, 196 }, 197 }, 198 } 199 af, err := appParser.GenerateAppFile(ctx, app) 200 Expect(err).Should(BeNil()) 201 202 handler, err := NewAppHandler(ctx, reconciler, app) 203 Expect(err).Should(Succeed()) 204 205 logCtx := monitorContext.NewTraceContext(ctx, "") 206 handler.currentAppRev = &oamcore.ApplicationRevision{} 207 handler.CheckWorkflowRestart(logCtx, app) 208 _, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af) 209 Expect(err).To(BeNil()) 210 Expect(len(taskRunner)).Should(BeEquivalentTo(2)) 211 Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1")) 212 Expect(taskRunner[1].Name()).Should(BeEquivalentTo("myweb2")) 213 }) 214 215 It("Test generate application workflow with invalid dependsOn", func() { 216 app := &oamcore.Application{ 217 TypeMeta: metav1.TypeMeta{ 218 Kind: "Application", 219 APIVersion: "core.oam.dev/v1beta1", 220 }, 221 ObjectMeta: metav1.ObjectMeta{ 222 Name: "app-with-input-output", 223 Namespace: namespaceName, 224 }, 225 Spec: oamcore.ApplicationSpec{ 226 Components: []common.ApplicationComponent{ 227 { 228 Name: "myweb1", 229 Type: "worker-with-health", 230 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 231 }, 232 { 233 Name: "myweb2", 234 Type: "worker-with-health", 235 DependsOn: []string{"myweb0"}, 236 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, 237 }, 238 }, 239 }, 240 } 241 af, err := appParser.GenerateAppFile(ctx, app) 242 Expect(err).Should(BeNil()) 243 244 handler, err := NewAppHandler(ctx, reconciler, app) 245 Expect(err).Should(Succeed()) 246 247 logCtx := monitorContext.NewTraceContext(ctx, "") 248 handler.currentAppRev = &oamcore.ApplicationRevision{} 249 handler.CheckWorkflowRestart(logCtx, app) 250 _, _, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af) 251 Expect(err).NotTo(BeNil()) 252 }) 253 254 It("Test generate application workflow with multiple invalid dependsOn", func() { 255 app := &oamcore.Application{ 256 TypeMeta: metav1.TypeMeta{ 257 Kind: "Application", 258 APIVersion: "core.oam.dev/v1beta1", 259 }, 260 ObjectMeta: metav1.ObjectMeta{ 261 Name: "app-with-input-output", 262 Namespace: namespaceName, 263 }, 264 Spec: oamcore.ApplicationSpec{ 265 Components: []common.ApplicationComponent{ 266 { 267 Name: "myweb1", 268 Type: "worker-with-health", 269 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)}, 270 }, 271 { 272 Name: "myweb2", 273 Type: "worker-with-health", 274 DependsOn: []string{"myweb1", "myweb0", "myweb3"}, 275 Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)}, 276 }, 277 }, 278 }, 279 } 280 af, err := appParser.GenerateAppFile(ctx, app) 281 Expect(err).Should(BeNil()) 282 283 handler, err := NewAppHandler(ctx, reconciler, app) 284 Expect(err).Should(Succeed()) 285 286 logCtx := monitorContext.NewTraceContext(ctx, "") 287 handler.currentAppRev = &oamcore.ApplicationRevision{} 288 handler.CheckWorkflowRestart(logCtx, app) 289 _, _, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af) 290 Expect(err).NotTo(BeNil()) 291 }) 292 })