| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2021-04-11 21:00:14 +08:00
										 |  |  | Copyright 2021 The KubeVela Authors. | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 appfile | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-07-22 18:53:30 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 	. "github.com/onsi/ginkgo" | 
					
						
							|  |  |  | 	. "github.com/onsi/gomega" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	"github.com/crossplane/crossplane-runtime/pkg/test" | 
					
						
							|  |  |  | 	"github.com/google/go-cmp/cmp" | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 	terraformtypes "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime" | 
					
						
							|  |  |  | 	terraformapi "github.com/oam-dev/terraform-controller/api/v1beta1" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2021-05-13 21:46:45 +08:00
										 |  |  | 	"gotest.tools/assert" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 
					
						
							|  |  |  | 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | 
					
						
							|  |  |  | 	"k8s.io/apimachinery/pkg/runtime" | 
					
						
							|  |  |  | 	"k8s.io/utils/pointer" | 
					
						
							| 
									
										
										
										
											2021-08-15 10:53:05 +08:00
										 |  |  | 	"sigs.k8s.io/yaml" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common" | 
					
						
							| 
									
										
										
										
											2021-07-22 18:53:30 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	oamtypes "github.com/oam-dev/kubevela/apis/types" | 
					
						
							| 
									
										
										
										
											2021-06-02 15:37:06 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/cue/definition" | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/cue/model" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	"github.com/oam-dev/kubevela/pkg/oam/util" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _ = Describe("Test Helm schematic appfile", func() { | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2021-09-23 15:05:25 +08:00
										 |  |  | 		appName      = "test-app" | 
					
						
							|  |  |  | 		compName     = "test-comp" | 
					
						
							|  |  |  | 		workloadName = "test-workload" | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	It("Test generate AppConfig resources from Helm schematic", func() { | 
					
						
							|  |  |  | 		appFile := &Appfile{ | 
					
						
							| 
									
										
										
										
											2021-09-12 10:12:46 +08:00
										 |  |  | 			Name:            appName, | 
					
						
							|  |  |  | 			Namespace:       "default", | 
					
						
							|  |  |  | 			AppRevisionName: appName + "-v1", | 
					
						
							|  |  |  | 			RelatedTraitDefinitions: map[string]*v1beta1.TraitDefinition{ | 
					
						
							|  |  |  | 				"scaler": { | 
					
						
							|  |  |  | 					Spec: v1beta1.TraitDefinitionSpec{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 			Workloads: []*Workload{ | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2021-09-23 15:05:25 +08:00
										 |  |  | 					Name:               workloadName, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 					Type:               "webapp-chart", | 
					
						
							|  |  |  | 					CapabilityCategory: oamtypes.HelmCategory, | 
					
						
							|  |  |  | 					Params: map[string]interface{}{ | 
					
						
							|  |  |  | 						"image": map[string]interface{}{ | 
					
						
							|  |  |  | 							"tag": "5.1.2", | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					engine: definition.NewWorkloadAbstractEngine(compName, pd), | 
					
						
							|  |  |  | 					Traits: []*Trait{ | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							Name: "scaler", | 
					
						
							|  |  |  | 							Params: map[string]interface{}{ | 
					
						
							|  |  |  | 								"replicas": float64(10), | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 							engine: definition.NewTraitAbstractEngine("scaler", pd), | 
					
						
							|  |  |  | 							Template: ` | 
					
						
							|  |  |  |       outputs: scaler: { | 
					
						
							|  |  |  |       	apiVersion: "core.oam.dev/v1alpha2" | 
					
						
							|  |  |  |       	kind:       "ManualScalerTrait" | 
					
						
							|  |  |  |       	spec: { | 
					
						
							|  |  |  |       		replicaCount: parameter.replicas | 
					
						
							|  |  |  |       	} | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       parameter: { | 
					
						
							|  |  |  |       	//+short=r
 | 
					
						
							|  |  |  |       	replicas: *1 | int | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					FullTemplate: &Template{ | 
					
						
							| 
									
										
										
										
											2021-05-24 23:32:02 +08:00
										 |  |  | 						Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 							Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 								APIVersion: "apps/v1", | 
					
						
							|  |  |  | 								Kind:       "Deployment", | 
					
						
							|  |  |  | 							}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 						}, | 
					
						
							|  |  |  | 						Helm: &common.Helm{ | 
					
						
							| 
									
										
										
										
											2021-10-13 16:16:53 +08:00
										 |  |  | 							Release: *util.Object2RawExtension(map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 								"chart": map[string]interface{}{ | 
					
						
							|  |  |  | 									"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 										"chart":   "podinfo", | 
					
						
							|  |  |  | 										"version": "5.1.4", | 
					
						
							|  |  |  | 									}, | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 							}), | 
					
						
							| 
									
										
										
										
											2021-10-13 16:16:53 +08:00
										 |  |  | 							Repository: *util.Object2RawExtension(map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 								"url": "http://oam.dev/catalog/", | 
					
						
							|  |  |  | 							}), | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		By("Generate ApplicationConfiguration and Components") | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		components, err := appFile.GenerateComponentManifests() | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 		Expect(err).To(BeNil()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		expectCompManifest := &oamtypes.ComponentManifest{ | 
					
						
							| 
									
										
										
										
											2021-09-23 15:05:25 +08:00
										 |  |  | 			Name: workloadName, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 			StandardWorkload: &unstructured.Unstructured{ | 
					
						
							|  |  |  | 				Object: map[string]interface{}{ | 
					
						
							|  |  |  | 					"apiVersion": "apps/v1", | 
					
						
							|  |  |  | 					"kind":       "Deployment", | 
					
						
							|  |  |  | 					"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 						"labels": map[string]interface{}{ | 
					
						
							|  |  |  | 							"workload.oam.dev/type":   "webapp-chart", | 
					
						
							|  |  |  | 							"app.oam.dev/component":   compName, | 
					
						
							|  |  |  | 							"app.oam.dev/name":        appName, | 
					
						
							|  |  |  | 							"app.oam.dev/appRevision": appName + "-v1", | 
					
						
							|  |  |  | 						}}}}, | 
					
						
							|  |  |  | 			Traits: []*unstructured.Unstructured{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Object: map[string]interface{}{ | 
					
						
							|  |  |  | 						"apiVersion": "core.oam.dev/v1alpha2", | 
					
						
							|  |  |  | 						"kind":       "ManualScalerTrait", | 
					
						
							|  |  |  | 						"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 							"labels": map[string]interface{}{ | 
					
						
							|  |  |  | 								"app.oam.dev/component":   compName, | 
					
						
							|  |  |  | 								"app.oam.dev/name":        appName, | 
					
						
							|  |  |  | 								"trait.oam.dev/type":      "scaler", | 
					
						
							|  |  |  | 								"trait.oam.dev/resource":  "scaler", | 
					
						
							|  |  |  | 								"app.oam.dev/appRevision": appName + "-v1", | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 							}, | 
					
						
							|  |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 						"spec": map[string]interface{}{"replicaCount": int64(10)}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 			PackagedWorkloadResources: []*unstructured.Unstructured{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Object: map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 						"apiVersion": "helm.toolkit.fluxcd.io/v2beta1", | 
					
						
							|  |  |  | 						"kind":       "HelmRelease", | 
					
						
							|  |  |  | 						"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 							"name":      fmt.Sprintf("%s-%s", appName, compName), | 
					
						
							|  |  |  | 							"namespace": "default", | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 							"chart": map[string]interface{}{ | 
					
						
							|  |  |  | 								"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 									"sourceRef": map[string]interface{}{ | 
					
						
							|  |  |  | 										"kind":      "HelmRepository", | 
					
						
							|  |  |  | 										"name":      fmt.Sprintf("%s-%s", appName, compName), | 
					
						
							|  |  |  | 										"namespace": "default", | 
					
						
							|  |  |  | 									}, | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 							"interval": "5m0s", | 
					
						
							|  |  |  | 							"values": map[string]interface{}{ | 
					
						
							|  |  |  | 								"image": map[string]interface{}{ | 
					
						
							|  |  |  | 									"tag": "5.1.2", | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Object: map[string]interface{}{ | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 						"apiVersion": "source.toolkit.fluxcd.io/v1beta1", | 
					
						
							|  |  |  | 						"kind":       "HelmRepository", | 
					
						
							|  |  |  | 						"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 							"name":      fmt.Sprintf("%s-%s", appName, compName), | 
					
						
							|  |  |  | 							"namespace": "default", | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 						"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 							"url": "http://oam.dev/catalog/", | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		By("Verify expected ComponentManifest") | 
					
						
							|  |  |  | 		diff := cmp.Diff(components[0], expectCompManifest) | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 		Expect(diff).ShouldNot(BeEmpty()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _ = Describe("Test Kube schematic appfile", func() { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		appName  = "test-app" | 
					
						
							|  |  |  | 		compName = "test-comp" | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	var testTemplate = func() runtime.RawExtension { | 
					
						
							|  |  |  | 		yamlStr := `apiVersion: apps/v1 | 
					
						
							|  |  |  | kind: Deployment | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   selector: | 
					
						
							|  |  |  |     matchLabels: | 
					
						
							|  |  |  |       app: nginx | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  |     metadata: | 
					
						
							|  |  |  |       labels: | 
					
						
							|  |  |  |         app: nginx | 
					
						
							|  |  |  |     spec: | 
					
						
							|  |  |  |       containers: | 
					
						
							|  |  |  |       - name: nginx | 
					
						
							|  |  |  |       ports: | 
					
						
							|  |  |  |       - containerPort: 80 ` | 
					
						
							|  |  |  | 		b, _ := yaml.YAMLToJSON([]byte(yamlStr)) | 
					
						
							|  |  |  | 		return runtime.RawExtension{Raw: b} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 	var testAppfile = func() *Appfile { | 
					
						
							|  |  |  | 		return &Appfile{ | 
					
						
							| 
									
										
										
										
											2021-09-12 10:12:46 +08:00
										 |  |  | 			AppRevisionName: appName + "-v1", | 
					
						
							|  |  |  | 			Name:            appName, | 
					
						
							|  |  |  | 			Namespace:       "default", | 
					
						
							|  |  |  | 			RelatedTraitDefinitions: map[string]*v1beta1.TraitDefinition{ | 
					
						
							|  |  |  | 				"scaler": { | 
					
						
							|  |  |  | 					Spec: v1beta1.TraitDefinitionSpec{}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 			Workloads: []*Workload{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Type:               "kube-worker", | 
					
						
							|  |  |  | 					CapabilityCategory: oamtypes.KubeCategory, | 
					
						
							|  |  |  | 					Params: map[string]interface{}{ | 
					
						
							|  |  |  | 						"image": "nginx:1.14.0", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					engine: definition.NewWorkloadAbstractEngine(compName, pd), | 
					
						
							|  |  |  | 					Traits: []*Trait{ | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							Name: "scaler", | 
					
						
							|  |  |  | 							Params: map[string]interface{}{ | 
					
						
							|  |  |  | 								"replicas": float64(10), | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 							engine: definition.NewTraitAbstractEngine("scaler", pd), | 
					
						
							|  |  |  | 							Template: ` | 
					
						
							|  |  |  |       outputs: scaler: { | 
					
						
							|  |  |  |       	apiVersion: "core.oam.dev/v1alpha2" | 
					
						
							|  |  |  |       	kind:       "ManualScalerTrait" | 
					
						
							|  |  |  |       	spec: { | 
					
						
							|  |  |  |       		replicaCount: parameter.replicas | 
					
						
							|  |  |  |       	} | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       parameter: { | 
					
						
							|  |  |  |       	//+short=r
 | 
					
						
							|  |  |  |       	replicas: *1 | int | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					FullTemplate: &Template{ | 
					
						
							|  |  |  | 						Kube: &common.Kube{ | 
					
						
							|  |  |  | 							Template: testTemplate(), | 
					
						
							|  |  |  | 							Parameters: []common.KubeParameter{ | 
					
						
							|  |  |  | 								{ | 
					
						
							|  |  |  | 									Name:       "image", | 
					
						
							|  |  |  | 									ValueType:  common.StringType, | 
					
						
							|  |  |  | 									Required:   pointer.BoolPtr(true), | 
					
						
							|  |  |  | 									FieldPaths: []string{"spec.template.spec.containers[0].image"}, | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 							}, | 
					
						
							|  |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2021-05-24 23:32:02 +08:00
										 |  |  | 						Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 							Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 								APIVersion: "apps/v1", | 
					
						
							|  |  |  | 								Kind:       "Deployment", | 
					
						
							|  |  |  | 							}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	It("Test generate AppConfig resources from Kube schematic", func() { | 
					
						
							|  |  |  | 		By("Generate ApplicationConfiguration and Components") | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		comps, err := testAppfile().GenerateComponentManifests() | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 		Expect(err).To(BeNil()) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		expectWorkload := func() *unstructured.Unstructured { | 
					
						
							|  |  |  | 			yamlStr := `apiVersion: apps/v1 | 
					
						
							|  |  |  | kind: Deployment | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   selector: | 
					
						
							|  |  |  |     matchLabels: | 
					
						
							|  |  |  |       app: nginx | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  |     metadata: | 
					
						
							|  |  |  |       labels: | 
					
						
							|  |  |  |         app: nginx | 
					
						
							|  |  |  |     spec: | 
					
						
							|  |  |  |       containers: | 
					
						
							|  |  |  |       - name: nginx | 
					
						
							|  |  |  |         image: nginx:1.14.0 | 
					
						
							|  |  |  |       ports: | 
					
						
							|  |  |  |       - containerPort: 80 ` | 
					
						
							|  |  |  | 			r := &unstructured.Unstructured{} | 
					
						
							|  |  |  | 			_ = yaml.Unmarshal([]byte(yamlStr), r) | 
					
						
							|  |  |  | 			return r | 
					
						
							|  |  |  | 		}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		expectCompManifest := &oamtypes.ComponentManifest{ | 
					
						
							|  |  |  | 			Name:             compName, | 
					
						
							|  |  |  | 			StandardWorkload: expectWorkload, | 
					
						
							|  |  |  | 			Traits: []*unstructured.Unstructured{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Object: map[string]interface{}{ | 
					
						
							|  |  |  | 						"apiVersion": "core.oam.dev/v1alpha2", | 
					
						
							|  |  |  | 						"kind":       "ManualScalerTrait", | 
					
						
							|  |  |  | 						"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 							"labels": map[string]interface{}{ | 
					
						
							|  |  |  | 								"app.oam.dev/component":   compName, | 
					
						
							|  |  |  | 								"app.oam.dev/name":        appName, | 
					
						
							|  |  |  | 								"app.oam.dev/appRevision": appName + "-v1", | 
					
						
							|  |  |  | 								"trait.oam.dev/type":      "scaler", | 
					
						
							|  |  |  | 								"trait.oam.dev/resource":  "scaler", | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 							}, | 
					
						
							|  |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 						"spec": map[string]interface{}{"replicaCount": int64(10)}, | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		By("Verify expected Component") | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		diff := cmp.Diff(comps[0], expectCompManifest) | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 		Expect(diff).ShouldNot(BeEmpty()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	It("Test missing set required parameter", func() { | 
					
						
							|  |  |  | 		appfile := testAppfile() | 
					
						
							|  |  |  | 		// remove parameter settings
 | 
					
						
							|  |  |  | 		appfile.Workloads[0].Params = nil | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		_, err := appfile.GenerateComponentManifests() | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		expectError := errors.WithMessage(errors.New(`require parameter "image"`), "cannot resolve parameter settings") | 
					
						
							|  |  |  | 		diff := cmp.Diff(expectError, err, test.EquateErrors()) | 
					
						
							|  |  |  | 		Expect(diff).Should(BeEmpty()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-22 18:53:30 +08:00
										 |  |  | var _ = Describe("Test Workflow", func() { | 
					
						
							|  |  |  | 	It("generate workflow task runners", func() { | 
					
						
							|  |  |  | 		workflowStepDef := v1beta1.WorkflowStepDefinition{ | 
					
						
							|  |  |  | 			Spec: v1beta1.WorkflowStepDefinitionSpec{ | 
					
						
							|  |  |  | 				Schematic: &common.Schematic{ | 
					
						
							|  |  |  | 					CUE: &common.CUE{ | 
					
						
							|  |  |  | 						Template: ` | 
					
						
							|  |  |  | wait: op.#ConditionalWait & { | 
					
						
							|  |  |  |   continue: true | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		workflowStepDef.Name = "test-wait" | 
					
						
							|  |  |  | 		workflowStepDef.Namespace = "default" | 
					
						
							|  |  |  | 		err := k8sClient.Create(context.Background(), &workflowStepDef) | 
					
						
							|  |  |  | 		Expect(err).To(BeNil()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		notCueStepDef := v1beta1.WorkflowStepDefinition{ | 
					
						
							|  |  |  | 			Spec: v1beta1.WorkflowStepDefinitionSpec{ | 
					
						
							|  |  |  | 				Schematic: &common.Schematic{}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		notCueStepDef.Name = "not-cue" | 
					
						
							|  |  |  | 		notCueStepDef.Namespace = "default" | 
					
						
							|  |  |  | 		err = k8sClient.Create(context.Background(), ¬CueStepDef) | 
					
						
							|  |  |  | 		Expect(err).To(BeNil()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | var _ = Describe("Test Policy", func() { | 
					
						
							|  |  |  | 	It("test generate Policies", func() { | 
					
						
							|  |  |  | 		testAppfile := &Appfile{ | 
					
						
							|  |  |  | 			Name:      "test-app", | 
					
						
							|  |  |  | 			Namespace: "default", | 
					
						
							|  |  |  | 			Workloads: []*Workload{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Name:               "test-comp", | 
					
						
							|  |  |  | 					Type:               "worker", | 
					
						
							|  |  |  | 					CapabilityCategory: oamtypes.KubeCategory, | 
					
						
							|  |  |  | 					engine:             definition.NewWorkloadAbstractEngine("test-comp", pd), | 
					
						
							|  |  |  | 					FullTemplate: &Template{ | 
					
						
							|  |  |  | 						Kube: &common.Kube{ | 
					
						
							|  |  |  | 							Template: func() runtime.RawExtension { | 
					
						
							|  |  |  | 								yamlStr := `apiVersion: apps/v1 | 
					
						
							|  |  |  | kind: Deployment | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   selector: | 
					
						
							|  |  |  |     matchLabels: | 
					
						
							|  |  |  |       app: nginx | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  |     metadata: | 
					
						
							|  |  |  |       labels: | 
					
						
							|  |  |  |         app: nginx | 
					
						
							|  |  |  |     spec: | 
					
						
							|  |  |  |       containers: | 
					
						
							|  |  |  |       - name: nginx | 
					
						
							|  |  |  |       ports: | 
					
						
							|  |  |  |       - containerPort: 80 ` | 
					
						
							|  |  |  | 								b, _ := yaml.YAMLToJSON([]byte(yamlStr)) | 
					
						
							|  |  |  | 								return runtime.RawExtension{Raw: b} | 
					
						
							|  |  |  | 							}(), | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Policies: []*Workload{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Name: "test-policy", | 
					
						
							|  |  |  | 					Type: "test-policy", | 
					
						
							|  |  |  | 					Params: map[string]interface{}{ | 
					
						
							|  |  |  | 						"boundComponents": []string{"test-comp"}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					FullTemplate: &Template{TemplateStr: `	output: { | 
					
						
							|  |  |  | 		apiVersion: "core.oam.dev/v1alpha2" | 
					
						
							|  |  |  | 		kind:       "HealthScope" | 
					
						
							|  |  |  | 		spec: { | 
					
						
							| 
									
										
										
										
											2021-09-12 10:12:46 +08:00
										 |  |  | 					for k, v in parameter.boundComponents { | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | 						compName: v | 
					
						
							|  |  |  | 						workload: { | 
					
						
							|  |  |  | 							apiVersion: context.artifacts[v].workload.apiVersion | 
					
						
							|  |  |  | 							kind:       context.artifacts[v].workload.kind | 
					
						
							|  |  |  | 							name:       v | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	parameter: { | 
					
						
							|  |  |  | 		boundComponents: [...string] | 
					
						
							|  |  |  | 	}`}, | 
					
						
							|  |  |  | 					engine: definition.NewWorkloadAbstractEngine("test-policy", pd), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-11-08 23:11:50 +08:00
										 |  |  | 			app: &v1beta1.Application{}, | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		_, err := testAppfile.GenerateComponentManifests() | 
					
						
							|  |  |  | 		Expect(err).Should(BeNil()) | 
					
						
							| 
									
										
										
										
											2021-11-24 15:38:13 +08:00
										 |  |  | 		_, gotPolicies, err := testAppfile.PrepareWorkflowAndPolicy() | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | 		Expect(err).Should(BeNil()) | 
					
						
							|  |  |  | 		Expect(len(gotPolicies)).ShouldNot(Equal(0)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		expectPolicy := unstructured.Unstructured{ | 
					
						
							|  |  |  | 			Object: map[string]interface{}{ | 
					
						
							|  |  |  | 				"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 					"compName": "test-comp", | 
					
						
							|  |  |  | 					"workload": map[string]interface{}{ | 
					
						
							|  |  |  | 						"name":       "test-comp", | 
					
						
							|  |  |  | 						"apiVersion": "apps/v1", | 
					
						
							|  |  |  | 						"kind":       "Deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"metadata": map[string]interface{}{ | 
					
						
							|  |  |  | 					"name":      "test-policy", | 
					
						
							|  |  |  | 					"namespace": "default", | 
					
						
							|  |  |  | 					"labels": map[string]interface{}{ | 
					
						
							|  |  |  | 						"app.oam.dev/name":        "test-app", | 
					
						
							|  |  |  | 						"app.oam.dev/component":   "test-policy", | 
					
						
							|  |  |  | 						"app.oam.dev/appRevision": "", | 
					
						
							|  |  |  | 						"workload.oam.dev/type":   "test-policy", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"apiVersion": "core.oam.dev/v1alpha2", | 
					
						
							|  |  |  | 				"kind":       "HealthScope", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		Expect(len(gotPolicies)).ShouldNot(Equal(0)) | 
					
						
							|  |  |  | 		gotPolicy := gotPolicies[0] | 
					
						
							|  |  |  | 		Expect(cmp.Diff(gotPolicy.Object, expectPolicy.Object)).Should(BeEmpty()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | var _ = Describe("Test Terraform schematic appfile", func() { | 
					
						
							|  |  |  | 	It("workload capability is Terraform", func() { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			ns            = "default" | 
					
						
							|  |  |  | 			compName      = "sample-db" | 
					
						
							|  |  |  | 			appName       = "webapp" | 
					
						
							|  |  |  | 			revision      = "v1" | 
					
						
							|  |  |  | 			configuration = ` | 
					
						
							|  |  |  | module "rds" { | 
					
						
							|  |  |  |   source = "terraform-alicloud-modules/rds/alicloud" | 
					
						
							|  |  |  |   engine = "MySQL" | 
					
						
							|  |  |  |   engine_version = "8.0" | 
					
						
							|  |  |  |   instance_type = "rds.mysql.c1.large" | 
					
						
							|  |  |  |   instance_storage = "20" | 
					
						
							|  |  |  |   instance_name = var.instance_name | 
					
						
							|  |  |  |   account_name = var.account_name | 
					
						
							|  |  |  |   password = var.password | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | output "DB_NAME" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_USER" { | 
					
						
							|  |  |  |   value = module.rds.this_db_database_account | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_PORT" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_port | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_HOST" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_connection_string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_PASSWORD" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_port | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "instance_name" { | 
					
						
							|  |  |  |   description = "RDS instance name" | 
					
						
							|  |  |  |   type = string | 
					
						
							|  |  |  |   default = "poc" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "account_name" { | 
					
						
							|  |  |  |   description = "RDS instance user account name" | 
					
						
							|  |  |  |   type = "string" | 
					
						
							|  |  |  |   default = "oam" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "password" { | 
					
						
							|  |  |  |   description = "RDS instance account password" | 
					
						
							|  |  |  |   type = "string" | 
					
						
							|  |  |  |   default = "Xyfff83jfewGGfaked" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ` | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		wl := &Workload{ | 
					
						
							|  |  |  | 			Name: "sample-db", | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Terraform: &common.Terraform{ | 
					
						
							|  |  |  | 					Configuration: configuration, | 
					
						
							|  |  |  | 					Type:          "hcl", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.TerraformCategory, | 
					
						
							|  |  |  | 			Params: map[string]interface{}{ | 
					
						
							|  |  |  | 				"account_name": "oamtest", | 
					
						
							|  |  |  | 				"writeConnectionSecretToRef": map[string]interface{}{ | 
					
						
							|  |  |  | 					"name": "db", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-08-30 11:43:20 +08:00
										 |  |  | 				model.OutputSecretName: "db-conn", | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		af := &Appfile{ | 
					
						
							| 
									
										
										
										
											2021-09-12 10:12:46 +08:00
										 |  |  | 			Workloads:       []*Workload{wl}, | 
					
						
							|  |  |  | 			Name:            appName, | 
					
						
							|  |  |  | 			AppRevisionName: revision, | 
					
						
							|  |  |  | 			Namespace:       ns, | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		variable := map[string]interface{}{"account_name": "oamtest"} | 
					
						
							|  |  |  | 		data, _ := json.Marshal(variable) | 
					
						
							|  |  |  | 		raw := &runtime.RawExtension{} | 
					
						
							|  |  |  | 		raw.Raw = data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		workload := terraformapi.Configuration{ | 
					
						
							|  |  |  | 			TypeMeta: metav1.TypeMeta{ | 
					
						
							|  |  |  | 				APIVersion: "terraform.core.oam.dev/v1beta1", | 
					
						
							|  |  |  | 				Kind:       "Configuration", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			ObjectMeta: metav1.ObjectMeta{ | 
					
						
							|  |  |  | 				Labels: map[string]string{ | 
					
						
							|  |  |  | 					"app.oam.dev/appRevision": "v1", | 
					
						
							|  |  |  | 					"app.oam.dev/component":   "sample-db", | 
					
						
							|  |  |  | 					"app.oam.dev/name":        "webapp", | 
					
						
							|  |  |  | 					"workload.oam.dev/type":   "", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Name:      "sample-db", | 
					
						
							|  |  |  | 				Namespace: "default", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Spec: terraformapi.ConfigurationSpec{ | 
					
						
							|  |  |  | 				HCL:                              configuration, | 
					
						
							|  |  |  | 				Variable:                         raw, | 
					
						
							|  |  |  | 				WriteConnectionSecretToReference: &terraformtypes.SecretReference{Name: "db", Namespace: "default"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Status: terraformapi.ConfigurationStatus{}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		expectCompManifest := &oamtypes.ComponentManifest{ | 
					
						
							|  |  |  | 			Name: compName, | 
					
						
							|  |  |  | 			StandardWorkload: func() *unstructured.Unstructured { | 
					
						
							|  |  |  | 				r, _ := util.Object2Unstructured(workload) | 
					
						
							|  |  |  | 				return r | 
					
						
							|  |  |  | 			}(), | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		comps, err := af.GenerateComponentManifests() | 
					
						
							|  |  |  | 		diff := cmp.Diff(comps[0], expectCompManifest) | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		Expect(diff).ShouldNot(BeEmpty()) | 
					
						
							|  |  |  | 		Expect(err).Should(BeNil()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-11 14:10:16 +08:00
										 |  |  | func TestResolveKubeParameters(t *testing.T) { | 
					
						
							|  |  |  | 	stringParam := &common.KubeParameter{ | 
					
						
							|  |  |  | 		Name:       "strParam", | 
					
						
							|  |  |  | 		ValueType:  common.StringType, | 
					
						
							|  |  |  | 		FieldPaths: []string{"spec"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	requiredParam := &common.KubeParameter{ | 
					
						
							|  |  |  | 		Name:       "reqParam", | 
					
						
							|  |  |  | 		Required:   pointer.BoolPtr(true), | 
					
						
							|  |  |  | 		ValueType:  common.StringType, | 
					
						
							|  |  |  | 		FieldPaths: []string{"spec"}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	tests := map[string]struct { | 
					
						
							|  |  |  | 		reason   string | 
					
						
							|  |  |  | 		params   []common.KubeParameter | 
					
						
							|  |  |  | 		settings map[string]interface{} | 
					
						
							|  |  |  | 		want     paramValueSettings | 
					
						
							|  |  |  | 		wantErr  error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"EmptyParam": { | 
					
						
							|  |  |  | 			reason: "Empty value settings and no error should be returned", | 
					
						
							|  |  |  | 			want:   make(paramValueSettings), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"UnsupportedParam": { | 
					
						
							|  |  |  | 			reason:   "An error shoulde be returned because of unsupported param", | 
					
						
							|  |  |  | 			params:   []common.KubeParameter{*stringParam}, | 
					
						
							|  |  |  | 			settings: map[string]interface{}{"unsupported": "invalid parameter"}, | 
					
						
							|  |  |  | 			want:     nil, | 
					
						
							|  |  |  | 			wantErr:  errors.Errorf("unsupported parameter %q", "unsupported"), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"MissingRequiredParam": { | 
					
						
							|  |  |  | 			reason:   "An error should be returned because of missing required param", | 
					
						
							|  |  |  | 			params:   []common.KubeParameter{*stringParam, *requiredParam}, | 
					
						
							|  |  |  | 			settings: map[string]interface{}{"strParam": "string"}, | 
					
						
							|  |  |  | 			want:     nil, | 
					
						
							|  |  |  | 			wantErr:  errors.Errorf("require parameter %q", "reqParam"), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"Succeed": { | 
					
						
							|  |  |  | 			reason:   "No error should be returned", | 
					
						
							|  |  |  | 			params:   []common.KubeParameter{*stringParam, *requiredParam}, | 
					
						
							|  |  |  | 			settings: map[string]interface{}{"strParam": "test", "reqParam": "test"}, | 
					
						
							|  |  |  | 			want: paramValueSettings{ | 
					
						
							|  |  |  | 				"strParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.StringType, | 
					
						
							|  |  |  | 					FieldPaths: stringParam.FieldPaths, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"reqParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.StringType, | 
					
						
							|  |  |  | 					FieldPaths: requiredParam.FieldPaths, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantErr: nil, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for tcName, tc := range tests { | 
					
						
							|  |  |  | 		t.Run(tcName, func(t *testing.T) { | 
					
						
							|  |  |  | 			result, err := resolveKubeParameters(tc.params, tc.settings) | 
					
						
							|  |  |  | 			if diff := cmp.Diff(tc.want, result); diff != "" { | 
					
						
							|  |  |  | 				t.Fatalf("\nresolveKubeParameters(...)(...) -want +get \nreason:%s\n%s\n", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if diff := cmp.Diff(tc.wantErr, err, test.EquateErrors()); diff != "" { | 
					
						
							|  |  |  | 				t.Fatalf("\nresolveKubeParameters(...)(...) -want +get \nreason:%s\n%s\n", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestSetParameterValuesToKubeObj(t *testing.T) { | 
					
						
							|  |  |  | 	tests := map[string]struct { | 
					
						
							|  |  |  | 		reason  string | 
					
						
							|  |  |  | 		obj     unstructured.Unstructured | 
					
						
							|  |  |  | 		values  paramValueSettings | 
					
						
							|  |  |  | 		wantObj unstructured.Unstructured | 
					
						
							|  |  |  | 		wantErr error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"InvalidStringType": { | 
					
						
							|  |  |  | 			reason: "An error should be returned", | 
					
						
							|  |  |  | 			values: paramValueSettings{ | 
					
						
							|  |  |  | 				"strParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      int32(100), | 
					
						
							|  |  |  | 					ValueType:  common.StringType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.test"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantErr: errors.Errorf(errInvalidValueType, common.StringType), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"InvalidNumberType": { | 
					
						
							|  |  |  | 			reason: "An error should be returned", | 
					
						
							|  |  |  | 			values: paramValueSettings{ | 
					
						
							|  |  |  | 				"intParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.NumberType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.test"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantErr: errors.Errorf(errInvalidValueType, common.NumberType), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"InvalidBoolType": { | 
					
						
							|  |  |  | 			reason: "An error should be returned", | 
					
						
							|  |  |  | 			values: paramValueSettings{ | 
					
						
							|  |  |  | 				"boolParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.BooleanType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.test"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantErr: errors.Errorf(errInvalidValueType, common.BooleanType), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"InvalidFieldPath": { | 
					
						
							|  |  |  | 			reason: "An error should be returned", | 
					
						
							|  |  |  | 			values: paramValueSettings{ | 
					
						
							|  |  |  | 				"strParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.StringType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec[.test"}, // a invalid field path
 | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantErr: errors.Wrap(errors.New(`cannot parse path "spec[.test": unterminated '[' at position 4`), | 
					
						
							|  |  |  | 				`cannot set parameter "strParam" to field "spec[.test"`), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"Succeed": { | 
					
						
							|  |  |  | 			reason: "No error should be returned", | 
					
						
							|  |  |  | 			obj:    unstructured.Unstructured{Object: make(map[string]interface{})}, | 
					
						
							|  |  |  | 			values: paramValueSettings{ | 
					
						
							|  |  |  | 				"strParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      "test", | 
					
						
							|  |  |  | 					ValueType:  common.StringType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.strField"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"intParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      10, | 
					
						
							|  |  |  | 					ValueType:  common.NumberType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.intField"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"floatParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      float64(10.01), | 
					
						
							|  |  |  | 					ValueType:  common.NumberType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.floatField"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"boolParam": paramValueSetting{ | 
					
						
							|  |  |  | 					Value:      true, | 
					
						
							|  |  |  | 					ValueType:  common.BooleanType, | 
					
						
							|  |  |  | 					FieldPaths: []string{"spec.boolField"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			wantObj: unstructured.Unstructured{Object: map[string]interface{}{ | 
					
						
							|  |  |  | 				"spec": map[string]interface{}{ | 
					
						
							|  |  |  | 					"strField":   "test", | 
					
						
							|  |  |  | 					"intField":   int64(10), | 
					
						
							|  |  |  | 					"floatField": float64(10.01), | 
					
						
							|  |  |  | 					"boolField":  true, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for tcName, tc := range tests { | 
					
						
							|  |  |  | 		t.Run(tcName, func(t *testing.T) { | 
					
						
							|  |  |  | 			obj := tc.obj.DeepCopy() | 
					
						
							|  |  |  | 			err := setParameterValuesToKubeObj(obj, tc.values) | 
					
						
							|  |  |  | 			if diff := cmp.Diff(tc.wantObj, *obj); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\nsetParameterValuesToKubeObj(...)error -want +get \nreason:%s\n%s\n", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if diff := cmp.Diff(tc.wantErr, err, test.EquateErrors()); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\nsetParameterValuesToKubeObj(...)error -want +get \nreason:%s\n%s\n", tc.reason, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | var _ = Describe("Test evalWorkloadWithContext", func() { | 
					
						
							|  |  |  | 	It("workload capability is Terraform", func() { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			ns       = "default" | 
					
						
							|  |  |  | 			compName = "sample-db" | 
					
						
							|  |  |  | 			err      error | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		type appArgs struct { | 
					
						
							|  |  |  | 			wl       *Workload | 
					
						
							|  |  |  | 			appName  string | 
					
						
							|  |  |  | 			revision string | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		args := appArgs{ | 
					
						
							|  |  |  | 			wl: &Workload{ | 
					
						
							|  |  |  | 				Name: "sample-db", | 
					
						
							|  |  |  | 				FullTemplate: &Template{ | 
					
						
							|  |  |  | 					Terraform: &common.Terraform{ | 
					
						
							|  |  |  | 						Configuration: ` | 
					
						
							|  |  |  | module "rds" { | 
					
						
							|  |  |  |   source = "terraform-alicloud-modules/rds/alicloud" | 
					
						
							|  |  |  |   engine = "MySQL" | 
					
						
							|  |  |  |   engine_version = "8.0" | 
					
						
							|  |  |  |   instance_type = "rds.mysql.c1.large" | 
					
						
							|  |  |  |   instance_storage = "20" | 
					
						
							|  |  |  |   instance_name = var.instance_name | 
					
						
							|  |  |  |   account_name = var.account_name | 
					
						
							|  |  |  |   password = var.password | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | output "DB_NAME" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_USER" { | 
					
						
							|  |  |  |   value = module.rds.this_db_database_account | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_PORT" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_port | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_HOST" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_connection_string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | output "DB_PASSWORD" { | 
					
						
							|  |  |  |   value = module.rds.this_db_instance_port | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "instance_name" { | 
					
						
							|  |  |  |   description = "RDS instance name" | 
					
						
							|  |  |  |   type = string | 
					
						
							|  |  |  |   default = "poc" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "account_name" { | 
					
						
							|  |  |  |   description = "RDS instance user account name" | 
					
						
							|  |  |  |   type = "string" | 
					
						
							|  |  |  |   default = "oam" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | variable "password" { | 
					
						
							|  |  |  |   description = "RDS instance account password" | 
					
						
							|  |  |  |   type = "string" | 
					
						
							|  |  |  |   default = "Xyfff83jfewGGfaked" | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | `, | 
					
						
							|  |  |  | 						Type: "hcl", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				CapabilityCategory: oamtypes.TerraformCategory, | 
					
						
							|  |  |  | 				engine:             definition.NewWorkloadAbstractEngine(compName, pd), | 
					
						
							|  |  |  | 				Params: map[string]interface{}{ | 
					
						
							|  |  |  | 					"variable": map[string]interface{}{ | 
					
						
							|  |  |  | 						"account_name": "oamtest", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			appName:  "webapp", | 
					
						
							|  |  |  | 			revision: "v1", | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-07 11:50:27 +08:00
										 |  |  | 		pCtx := NewBasicContext(args.appName, args.wl.Name, args.revision, ns, args.wl.Params) | 
					
						
							| 
									
										
										
										
											2021-06-24 15:06:58 +08:00
										 |  |  | 		comp, err := evalWorkloadWithContext(pCtx, args.wl, ns, args.appName, compName) | 
					
						
							|  |  |  | 		Expect(comp.StandardWorkload).ShouldNot(BeNil()) | 
					
						
							|  |  |  | 		Expect(comp.Name).Should(Equal("")) | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		Expect(err).Should(BeNil()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestGenerateTerraformConfigurationWorkload(t *testing.T) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		name     = "oss" | 
					
						
							|  |  |  | 		ns       = "default" | 
					
						
							|  |  |  | 		variable = map[string]interface{}{"acl": "private"} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ch := make(chan string) | 
					
						
							|  |  |  | 	badParam := map[string]interface{}{"abc": ch} | 
					
						
							|  |  |  | 	_, badParamMarshalError := json.Marshal(badParam) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type args struct { | 
					
						
							|  |  |  | 		writeConnectionSecretToRef *terraformtypes.SecretReference | 
					
						
							|  |  |  | 		json                       string | 
					
						
							|  |  |  | 		hcl                        string | 
					
						
							| 
									
										
										
										
											2021-09-29 14:58:27 +08:00
										 |  |  | 		remote                     string | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		params                     map[string]interface{} | 
					
						
							| 
									
										
										
										
											2021-10-08 11:35:52 +08:00
										 |  |  | 		providerRef                *terraformtypes.Reference | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	type want struct { | 
					
						
							|  |  |  | 		err error | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testcases := map[string]struct { | 
					
						
							|  |  |  | 		args args | 
					
						
							|  |  |  | 		want want | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"json workload with invalid secret": { | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				json:   "abc", | 
					
						
							|  |  |  | 				params: map[string]interface{}{"acl": "private", "writeConnectionSecretToRef": map[string]interface{}{"name": "", "namespace": ""}}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: errors.New(errTerraformNameOfWriteConnectionSecretToRefNotSet)}}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		"json workload with secret": { | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				json: "abc", | 
					
						
							|  |  |  | 				params: map[string]interface{}{"acl": "private", | 
					
						
							|  |  |  | 					"writeConnectionSecretToRef": map[string]interface{}{"name": "oss", "namespace": ""}}, | 
					
						
							|  |  |  | 				writeConnectionSecretToRef: &terraformtypes.SecretReference{Name: "oss", Namespace: "default"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: nil}}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		"valid hcl workload": { | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				hcl: "abc", | 
					
						
							|  |  |  | 				params: map[string]interface{}{"acl": "private", | 
					
						
							|  |  |  | 					"writeConnectionSecretToRef": map[string]interface{}{"name": "oss", "namespace": "default"}}, | 
					
						
							|  |  |  | 				writeConnectionSecretToRef: &terraformtypes.SecretReference{Name: "oss", Namespace: "default"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: nil}}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-29 14:58:27 +08:00
										 |  |  | 		"remote hcl workload": { | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				remote: "https://xxx/a.git", | 
					
						
							|  |  |  | 				params: map[string]interface{}{"acl": "private", | 
					
						
							|  |  |  | 					"writeConnectionSecretToRef": map[string]interface{}{"name": "oss", "namespace": "default"}}, | 
					
						
							|  |  |  | 				writeConnectionSecretToRef: &terraformtypes.SecretReference{Name: "oss", Namespace: "default"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: nil}}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 		"workload's TF configuration is empty": { | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				params: variable, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: errors.New(errTerraformConfigurationIsNotSet)}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		"workload's params is bad": { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				params: badParam, | 
					
						
							|  |  |  | 				hcl:    "abc", | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-10-08 11:35:52 +08:00
										 |  |  | 			want: want{err: errors.Wrap(badParamMarshalError, errFailToConvertTerraformComponentProperties)}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		"terraform workload has a provider reference": { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			args: args{ | 
					
						
							|  |  |  | 				params:      badParam, | 
					
						
							|  |  |  | 				hcl:         "abc", | 
					
						
							|  |  |  | 				providerRef: &terraformtypes.Reference{Name: "azure", Namespace: "default"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			want: want{err: errors.Wrap(badParamMarshalError, errFailToConvertTerraformComponentProperties)}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for tcName, tc := range testcases { | 
					
						
							|  |  |  | 		var ( | 
					
						
							|  |  |  | 			template   *Template | 
					
						
							|  |  |  | 			configSpec terraformapi.ConfigurationSpec | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 		data, _ := json.Marshal(variable) | 
					
						
							|  |  |  | 		raw := &runtime.RawExtension{} | 
					
						
							|  |  |  | 		raw.Raw = data | 
					
						
							|  |  |  | 		if tc.args.hcl != "" { | 
					
						
							|  |  |  | 			template = &Template{ | 
					
						
							|  |  |  | 				Terraform: &common.Terraform{ | 
					
						
							|  |  |  | 					Configuration: tc.args.hcl, | 
					
						
							|  |  |  | 					Type:          "hcl", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			configSpec = terraformapi.ConfigurationSpec{ | 
					
						
							|  |  |  | 				HCL:                              tc.args.hcl, | 
					
						
							|  |  |  | 				Variable:                         raw, | 
					
						
							|  |  |  | 				WriteConnectionSecretToReference: tc.args.writeConnectionSecretToRef, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tc.args.json != "" { | 
					
						
							|  |  |  | 			template = &Template{ | 
					
						
							|  |  |  | 				Terraform: &common.Terraform{ | 
					
						
							|  |  |  | 					Configuration: tc.args.json, | 
					
						
							|  |  |  | 					Type:          "json", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			configSpec = terraformapi.ConfigurationSpec{ | 
					
						
							|  |  |  | 				JSON:                             tc.args.json, | 
					
						
							|  |  |  | 				Variable:                         raw, | 
					
						
							|  |  |  | 				WriteConnectionSecretToReference: tc.args.writeConnectionSecretToRef, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-09-29 14:58:27 +08:00
										 |  |  | 		if tc.args.remote != "" { | 
					
						
							|  |  |  | 			template = &Template{ | 
					
						
							|  |  |  | 				Terraform: &common.Terraform{ | 
					
						
							|  |  |  | 					Configuration: tc.args.remote, | 
					
						
							|  |  |  | 					Type:          "remote", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			configSpec = terraformapi.ConfigurationSpec{ | 
					
						
							|  |  |  | 				Remote:                           tc.args.remote, | 
					
						
							|  |  |  | 				Variable:                         raw, | 
					
						
							|  |  |  | 				WriteConnectionSecretToReference: tc.args.writeConnectionSecretToRef, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if tc.args.hcl == "" && tc.args.json == "" && tc.args.remote == "" { | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 			template = &Template{ | 
					
						
							|  |  |  | 				Terraform: &common.Terraform{}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			configSpec = terraformapi.ConfigurationSpec{ | 
					
						
							|  |  |  | 				Variable:                         raw, | 
					
						
							|  |  |  | 				WriteConnectionSecretToReference: tc.args.writeConnectionSecretToRef, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-08 11:35:52 +08:00
										 |  |  | 		if tc.args.providerRef != nil { | 
					
						
							|  |  |  | 			template.Terraform.ProviderReference = tc.args.providerRef | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		wl := &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: template, | 
					
						
							|  |  |  | 			Name:         name, | 
					
						
							|  |  |  | 			Params:       tc.args.params, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		got, err := generateTerraformConfigurationWorkload(wl, ns) | 
					
						
							|  |  |  | 		if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { | 
					
						
							|  |  |  | 			t.Errorf("\n%s\ngenerateTerraformConfigurationWorkload(...): -want error, +got error:\n%s\n", tcName, diff) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			tfConfiguration := terraformapi.Configuration{ | 
					
						
							|  |  |  | 				TypeMeta:   metav1.TypeMeta{APIVersion: "terraform.core.oam.dev/v1beta1", Kind: "Configuration"}, | 
					
						
							|  |  |  | 				ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns}, | 
					
						
							|  |  |  | 				Spec:       configSpec, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			rawConf := util.Object2RawExtension(tfConfiguration) | 
					
						
							| 
									
										
										
										
											2021-10-13 16:16:53 +08:00
										 |  |  | 			wantWL, _ := util.RawExtension2Unstructured(rawConf) | 
					
						
							| 
									
										
										
										
											2021-04-30 16:28:00 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if diff := cmp.Diff(wantWL, got); diff != "" { | 
					
						
							|  |  |  | 				t.Errorf("\n%s\ngenerateTerraformConfigurationWorkload(...): -want, +got:\n%s\n", tcName, diff) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-05-13 21:46:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-08 15:16:55 +08:00
										 |  |  | func TestGenerateCUETemplate(t *testing.T) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var testCorrectTemplate = func() runtime.RawExtension { | 
					
						
							|  |  |  | 		yamlStr := `apiVersion: apps/v1 | 
					
						
							|  |  |  | kind: Deployment | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   selector: | 
					
						
							|  |  |  |     matchLabels: | 
					
						
							|  |  |  |       app: nginx | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  |     metadata: | 
					
						
							|  |  |  |       labels: | 
					
						
							|  |  |  |         app: nginx | 
					
						
							|  |  |  |     spec: | 
					
						
							|  |  |  |       containers: | 
					
						
							|  |  |  |       - name: nginx | 
					
						
							|  |  |  |       ports: | 
					
						
							|  |  |  |       - containerPort: 80 ` | 
					
						
							|  |  |  | 		b, _ := yaml.YAMLToJSON([]byte(yamlStr)) | 
					
						
							|  |  |  | 		return runtime.RawExtension{Raw: b} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var testErrorTemplate = func() runtime.RawExtension { | 
					
						
							|  |  |  | 		yamlStr := `apiVersion: apps/v1 | 
					
						
							|  |  |  | kind: Deployment | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   template: | 
					
						
							|  |  |  | 	selector: | 
					
						
							|  |  |  | 		matchLabels: | 
					
						
							|  |  |  | 		app: nginx | 
					
						
							|  |  |  | ` | 
					
						
							|  |  |  | 		b, _ := yaml.YAMLToJSON([]byte(yamlStr)) | 
					
						
							|  |  |  | 		return runtime.RawExtension{Raw: b} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testcases := map[string]struct { | 
					
						
							|  |  |  | 		workload   *Workload | 
					
						
							|  |  |  | 		expectData string | 
					
						
							|  |  |  | 		hasError   bool | 
					
						
							|  |  |  | 		errInfo    string | 
					
						
							|  |  |  | 	}{"Kube workload with Correct template": { | 
					
						
							|  |  |  | 		workload: &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Kube: &common.Kube{ | 
					
						
							|  |  |  | 					Template: testCorrectTemplate(), | 
					
						
							|  |  |  | 					Parameters: []common.KubeParameter{ | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							Name:       "image", | 
					
						
							|  |  |  | 							ValueType:  common.StringType, | 
					
						
							|  |  |  | 							Required:   pointer.BoolPtr(true), | 
					
						
							|  |  |  | 							FieldPaths: []string{"spec.template.spec.containers[0].image"}, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 					Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 						APIVersion: "apps/v1", | 
					
						
							|  |  |  | 						Kind:       "Deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Params: map[string]interface{}{ | 
					
						
							|  |  |  | 				"image": "nginx:1.14.0", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.KubeCategory, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		expectData: ` | 
					
						
							|  |  |  | output: {  | 
					
						
							|  |  |  | apiVersion: "apps/v1" | 
					
						
							|  |  |  | kind:       "Deployment" | 
					
						
							|  |  |  | spec: { | 
					
						
							|  |  |  | 	selector: { | 
					
						
							|  |  |  | 		matchLabels: { | 
					
						
							|  |  |  | 			app: "nginx" | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	template: { | 
					
						
							|  |  |  | 		spec: { | 
					
						
							|  |  |  | 			containers: [{ | 
					
						
							|  |  |  | 				name:  "nginx" | 
					
						
							|  |  |  | 				image: "nginx:1.14.0" | 
					
						
							|  |  |  | 			}] | 
					
						
							|  |  |  | 			ports: [{ | 
					
						
							|  |  |  | 				containerPort: 80 | 
					
						
							|  |  |  | 			}] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		metadata: { | 
					
						
							|  |  |  | 			labels: { | 
					
						
							|  |  |  | 				app: "nginx" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | }`, | 
					
						
							|  |  |  | 		hasError: false, | 
					
						
							|  |  |  | 	}, "Kube workload with wrong template": { | 
					
						
							|  |  |  | 		workload: &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Kube: &common.Kube{ | 
					
						
							|  |  |  | 					Template: testErrorTemplate(), | 
					
						
							|  |  |  | 					Parameters: []common.KubeParameter{ | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							Name:       "image", | 
					
						
							|  |  |  | 							ValueType:  common.StringType, | 
					
						
							|  |  |  | 							Required:   pointer.BoolPtr(true), | 
					
						
							|  |  |  | 							FieldPaths: []string{"spec.template.spec.containers[0].image"}, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 					Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 						APIVersion: "apps/v1", | 
					
						
							|  |  |  | 						Kind:       "Deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Params: map[string]interface{}{ | 
					
						
							|  |  |  | 				"image": "nginx:1.14.0", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.KubeCategory, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		hasError: true, | 
					
						
							|  |  |  | 		errInfo:  "cannot decode Kube template into K8s object: unexpected end of JSON input", | 
					
						
							|  |  |  | 	}, "Kube workload with wrong parameter": { | 
					
						
							|  |  |  | 		workload: &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Kube: &common.Kube{ | 
					
						
							|  |  |  | 					Template: testCorrectTemplate(), | 
					
						
							|  |  |  | 					Parameters: []common.KubeParameter{ | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							Name:       "image", | 
					
						
							|  |  |  | 							ValueType:  common.StringType, | 
					
						
							|  |  |  | 							Required:   pointer.BoolPtr(true), | 
					
						
							|  |  |  | 							FieldPaths: []string{"spec.template.spec.containers[0].image"}, | 
					
						
							|  |  |  | 						}, | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 					Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 						APIVersion: "apps/v1", | 
					
						
							|  |  |  | 						Kind:       "Deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			Params: map[string]interface{}{ | 
					
						
							|  |  |  | 				"unsupported": "invalid parameter", | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.KubeCategory, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		hasError: true, | 
					
						
							|  |  |  | 		errInfo:  "cannot resolve parameter settings: unsupported parameter \"unsupported\"", | 
					
						
							|  |  |  | 	}, "Helm workload with correct reference": { | 
					
						
							|  |  |  | 		workload: &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 					Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 						APIVersion: "app/v1", | 
					
						
							|  |  |  | 						Kind:       "deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.HelmCategory, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		hasError: false, | 
					
						
							|  |  |  | 		expectData: ` | 
					
						
							|  |  |  | output: { | 
					
						
							|  |  |  | 	apiVersion: "app/v1" | 
					
						
							|  |  |  | 	kind: "deployment" | 
					
						
							|  |  |  | }`, | 
					
						
							|  |  |  | 	}, "Helm workload with wrong reference": { | 
					
						
							|  |  |  | 		workload: &Workload{ | 
					
						
							|  |  |  | 			FullTemplate: &Template{ | 
					
						
							|  |  |  | 				Reference: common.WorkloadTypeDescriptor{ | 
					
						
							|  |  |  | 					Definition: common.WorkloadGVK{ | 
					
						
							|  |  |  | 						APIVersion: "app@//v1", | 
					
						
							|  |  |  | 						Kind:       "deployment", | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			CapabilityCategory: oamtypes.HelmCategory, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		hasError: true, | 
					
						
							|  |  |  | 		errInfo:  "unexpected GroupVersion string: app@//v1", | 
					
						
							|  |  |  | 	}} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, tc := range testcases { | 
					
						
							|  |  |  | 		template, err := GenerateCUETemplate(tc.workload) | 
					
						
							|  |  |  | 		assert.Equal(t, err != nil, tc.hasError) | 
					
						
							|  |  |  | 		if tc.hasError { | 
					
						
							|  |  |  | 			assert.Equal(t, tc.errInfo, err.Error()) | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		assert.Equal(t, tc.expectData, template) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | func TestPrepareArtifactsData(t *testing.T) { | 
					
						
							|  |  |  | 	compManifests := []*oamtypes.ComponentManifest{ | 
					
						
							| 
									
										
										
										
											2021-09-12 10:12:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2021-08-29 09:11:10 +08:00
										 |  |  | 			Name:         "readyComp", | 
					
						
							|  |  |  | 			Namespace:    "ns", | 
					
						
							|  |  |  | 			RevisionName: "readyComp-v1", | 
					
						
							|  |  |  | 			StandardWorkload: &unstructured.Unstructured{Object: map[string]interface{}{ | 
					
						
							|  |  |  | 				"fake": "workload", | 
					
						
							|  |  |  | 			}}, | 
					
						
							|  |  |  | 			Traits: func() []*unstructured.Unstructured { | 
					
						
							|  |  |  | 				ingressYAML := `apiVersion: networking.k8s.io/v1 | 
					
						
							|  |  |  | kind: Ingress | 
					
						
							|  |  |  | metadata: | 
					
						
							|  |  |  |   labels: | 
					
						
							|  |  |  |     trait.oam.dev/resource: ingress | 
					
						
							|  |  |  |     trait.oam.dev/type: ingress | 
					
						
							|  |  |  |   namespace: default | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   rules: | 
					
						
							|  |  |  |   - host: testsvc.example.com` | 
					
						
							|  |  |  | 				ingress := &unstructured.Unstructured{} | 
					
						
							|  |  |  | 				_ = yaml.Unmarshal([]byte(ingressYAML), ingress) | 
					
						
							|  |  |  | 				svcYAML := `apiVersion: v1 | 
					
						
							|  |  |  | kind: Service | 
					
						
							|  |  |  | metadata: | 
					
						
							|  |  |  |   labels: | 
					
						
							|  |  |  |     trait.oam.dev/resource: service | 
					
						
							|  |  |  |     trait.oam.dev/type: ingress | 
					
						
							|  |  |  |   namespace: default | 
					
						
							|  |  |  | spec: | 
					
						
							|  |  |  |   clusterIP: 10.96.185.119 | 
					
						
							|  |  |  |   selector: | 
					
						
							|  |  |  |     app.oam.dev/component: express-server | 
					
						
							|  |  |  |   type: ClusterIP` | 
					
						
							|  |  |  | 				svc := &unstructured.Unstructured{} | 
					
						
							|  |  |  | 				_ = yaml.Unmarshal([]byte(svcYAML), svc) | 
					
						
							|  |  |  | 				return []*unstructured.Unstructured{ingress, svc} | 
					
						
							|  |  |  | 			}(), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	gotArtifacts := prepareArtifactsData(compManifests) | 
					
						
							|  |  |  | 	gotWorkload, _, err := unstructured.NestedMap(gotArtifacts, "readyComp", "workload") | 
					
						
							|  |  |  | 	assert.NilError(t, err) | 
					
						
							|  |  |  | 	diff := cmp.Diff(gotWorkload, map[string]interface{}{"fake": string("workload")}) | 
					
						
							|  |  |  | 	assert.Equal(t, diff, "") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	_, gotIngress, err := unstructured.NestedMap(gotArtifacts, "readyComp", "traits", "ingress", "ingress") | 
					
						
							|  |  |  | 	assert.NilError(t, err) | 
					
						
							|  |  |  | 	if !gotIngress { | 
					
						
							|  |  |  | 		t.Fatalf("cannot get ingress trait") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	_, gotSvc, err := unstructured.NestedMap(gotArtifacts, "readyComp", "traits", "ingress", "service") | 
					
						
							|  |  |  | 	assert.NilError(t, err) | 
					
						
							|  |  |  | 	if !gotSvc { | 
					
						
							|  |  |  | 		t.Fatalf("cannot get service trait") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |