github.com/oam-dev/kubevela@v1.9.11/references/docgen/parser_test.go (about)

     1  /*
     2  Copyright 2021 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package docgen
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"testing"
    26  
    27  	"github.com/crossplane/crossplane-runtime/pkg/test"
    28  	"github.com/getkin/kin-openapi/openapi3"
    29  	"github.com/google/go-cmp/cmp"
    30  	"github.com/stretchr/testify/assert"
    31  
    32  	"github.com/oam-dev/kubevela/apis/types"
    33  	"github.com/oam-dev/kubevela/pkg/utils/common"
    34  )
    35  
    36  var RefTestDir = filepath.Join(TestDir, "ref")
    37  
    38  func TestCreateRefTestDir(t *testing.T) {
    39  	if _, err := os.Stat(RefTestDir); err != nil && os.IsNotExist(err) {
    40  		err := os.MkdirAll(RefTestDir, 0750)
    41  		assert.NoError(t, err)
    42  	}
    43  }
    44  
    45  func TestPrepareParameterTable(t *testing.T) {
    46  	ref := MarkdownReference{}
    47  	ref.I18N = &En
    48  	tableName := "hello"
    49  	parameterList := []ReferenceParameter{
    50  		{
    51  			PrintableType: "string",
    52  		},
    53  	}
    54  	parameterName := "cpu"
    55  	parameterList[0].Name = parameterName
    56  	parameterList[0].Required = true
    57  	refContent := ref.getParameterString(tableName, parameterList, types.CUECategory)
    58  	assert.Contains(t, refContent, parameterName)
    59  	assert.Contains(t, refContent, "cpu")
    60  }
    61  
    62  func TestDeleteRefTestDir(t *testing.T) {
    63  	if _, err := os.Stat(RefTestDir); err == nil {
    64  		err := os.RemoveAll(RefTestDir)
    65  		assert.NoError(t, err)
    66  	}
    67  }
    68  
    69  func TestWalkParameterSchema(t *testing.T) {
    70  	testcases := []struct {
    71  		data       string
    72  		ExpectRefs map[string]map[string]ReferenceParameter
    73  	}{
    74  		{
    75  			data: `{
    76      "properties": {
    77          "cmd": {
    78              "description": "Commands to run in the container",
    79              "items": {
    80                  "type": "string"
    81              },
    82              "title": "cmd",
    83              "type": "array"
    84          },
    85          "image": {
    86              "description": "Which image would you like to use for your service",
    87              "title": "image",
    88              "type": "string"
    89          }
    90      },
    91      "required": [
    92          "image"
    93      ],
    94      "type": "object"
    95  }`,
    96  			ExpectRefs: map[string]map[string]ReferenceParameter{
    97  				"# Specification": {
    98  					"cmd": ReferenceParameter{
    99  						Parameter: types.Parameter{
   100  							Name:     "cmd",
   101  							Usage:    "Commands to run in the container",
   102  							JSONType: "array",
   103  						},
   104  						PrintableType: "array",
   105  					},
   106  					"image": ReferenceParameter{
   107  						Parameter: types.Parameter{
   108  							Name:     "image",
   109  							Required: true,
   110  							Usage:    "Which image would you like to use for your service",
   111  							JSONType: "string",
   112  						},
   113  						PrintableType: "string",
   114  					},
   115  				},
   116  			},
   117  		},
   118  		{
   119  			data: `{
   120      "properties": {
   121          "obj": {
   122              "properties": {
   123                  "f0": {
   124                      "default": "v0",
   125                      "type": "string"
   126                  },
   127                  "f1": {
   128                      "default": "v1",
   129                      "type": "string"
   130                  },
   131                  "f2": {
   132                      "default": "v2",
   133                      "type": "string"
   134                  }
   135              },
   136              "type": "object"
   137          },
   138      },
   139      "type": "object"
   140  }`,
   141  			ExpectRefs: map[string]map[string]ReferenceParameter{
   142  				"# Specification": {
   143  					"obj": ReferenceParameter{
   144  						Parameter: types.Parameter{
   145  							Name:     "obj",
   146  							JSONType: "object",
   147  						},
   148  						PrintableType: "[obj](#obj)",
   149  					},
   150  				},
   151  				"## obj": {
   152  					"f0": ReferenceParameter{
   153  						Parameter: types.Parameter{
   154  							Name:     "f0",
   155  							Default:  "v0",
   156  							JSONType: "string",
   157  						},
   158  						PrintableType: "string",
   159  					},
   160  					"f1": ReferenceParameter{
   161  						Parameter: types.Parameter{
   162  							Name:     "f1",
   163  							Default:  "v1",
   164  							JSONType: "string",
   165  						},
   166  						PrintableType: "string",
   167  					},
   168  					"f2": ReferenceParameter{
   169  						Parameter: types.Parameter{
   170  							Name:     "f2",
   171  							Default:  "v2",
   172  							JSONType: "string",
   173  						},
   174  						PrintableType: "string",
   175  					},
   176  				},
   177  			},
   178  		},
   179  		{
   180  			data: `{
   181      "properties": {
   182          "obj": {
   183              "properties": {
   184                  "f0": {
   185                      "default": "v0",
   186                      "type": "string"
   187                  },
   188                  "f1": {
   189                      "default": "v1",
   190                      "type": "object",
   191                      "properties": {
   192                          "g0": {
   193                              "default": "v2",
   194                              "type": "string"
   195                          }
   196                      }
   197                  }
   198              },
   199              "type": "object"
   200          }
   201      },
   202      "type": "object"
   203  }`,
   204  			ExpectRefs: map[string]map[string]ReferenceParameter{
   205  				"# Specification": {
   206  					"obj": ReferenceParameter{
   207  						Parameter: types.Parameter{
   208  							Name:     "obj",
   209  							JSONType: "object",
   210  						},
   211  						PrintableType: "[obj](#obj)",
   212  					},
   213  				},
   214  				"## obj": {
   215  					"f0": ReferenceParameter{
   216  						Parameter: types.Parameter{
   217  							Name:     "f0",
   218  							Default:  "v0",
   219  							JSONType: "string",
   220  						},
   221  						PrintableType: "string",
   222  					},
   223  					"f1": ReferenceParameter{
   224  						Parameter: types.Parameter{
   225  							Name:     "f1",
   226  							Default:  "v1",
   227  							JSONType: "object",
   228  						},
   229  						PrintableType: "[f1](#f1)",
   230  					},
   231  				},
   232  				"### f1": {
   233  					"g0": ReferenceParameter{
   234  						Parameter: types.Parameter{
   235  							Name:     "g0",
   236  							Default:  "v2",
   237  							JSONType: "string",
   238  						},
   239  						PrintableType: "string",
   240  					},
   241  				},
   242  			},
   243  		},
   244  	}
   245  	for _, cases := range testcases {
   246  		commonRefs = make([]CommonReference, 0)
   247  		parameterJSON := fmt.Sprintf(BaseOpenAPIV3Template, cases.data)
   248  		swagger, err := openapi3.NewLoader().LoadFromData(json.RawMessage(parameterJSON))
   249  		assert.Equal(t, nil, err)
   250  		parameters := swagger.Components.Schemas["parameter"].Value
   251  		WalkParameterSchema(parameters, Specification, 0)
   252  		refs := make(map[string]map[string]ReferenceParameter)
   253  		for _, items := range commonRefs {
   254  			refs[items.Name] = make(map[string]ReferenceParameter)
   255  			for _, item := range items.Parameters {
   256  				refs[items.Name][item.Name] = item
   257  			}
   258  		}
   259  		assert.Equal(t, true, reflect.DeepEqual(cases.ExpectRefs, refs))
   260  	}
   261  }
   262  
   263  func TestGenerateTerraformCapabilityProperties(t *testing.T) {
   264  	ref := &ConsoleReference{}
   265  	type args struct {
   266  		cap types.Capability
   267  	}
   268  
   269  	type want struct {
   270  		tableName1 string
   271  		tableName2 string
   272  		errMsg     string
   273  	}
   274  	testcases := map[string]struct {
   275  		args args
   276  		want want
   277  	}{
   278  		"normal": {
   279  			args: args{
   280  				cap: types.Capability{
   281  					TerraformConfiguration: `
   282  resource "alicloud_oss_bucket" "bucket-acl" {
   283    bucket = var.bucket
   284    acl = var.acl
   285  }
   286  
   287  output "BUCKET_NAME" {
   288    value = "${alicloud_oss_bucket.bucket-acl.bucket}.${alicloud_oss_bucket.bucket-acl.extranet_endpoint}"
   289  }
   290  
   291  variable "bucket" {
   292    description = "OSS bucket name"
   293    default = "vela-website"
   294    type = string
   295  }
   296  
   297  variable "acl" {
   298    description = "OSS bucket ACL, supported 'private', 'public-read', 'public-read-write'"
   299    default = "private"
   300    type = string
   301  }
   302  `,
   303  				},
   304  			},
   305  			want: want{
   306  				errMsg:     "",
   307  				tableName1: "",
   308  				tableName2: "#### writeConnectionSecretToRef",
   309  			},
   310  		},
   311  		"configuration is in git remote": {
   312  			args: args{
   313  				cap: types.Capability{
   314  					Name:                   "ecs",
   315  					TerraformConfiguration: "https://github.com/wonderflow/terraform-alicloud-ecs-instance.git",
   316  					ConfigurationType:      "remote",
   317  				},
   318  			},
   319  			want: want{
   320  				errMsg:     "",
   321  				tableName1: "",
   322  				tableName2: "#### writeConnectionSecretToRef",
   323  			},
   324  		},
   325  		"configuration is not valid": {
   326  			args: args{
   327  				cap: types.Capability{
   328  					TerraformConfiguration: `abc`,
   329  				},
   330  			},
   331  			want: want{
   332  				errMsg: "failed to generate capability properties: :1,1-4: Argument or block definition required; An " +
   333  					"argument or block definition is required here. To set an argument, use the equals sign \"=\" to " +
   334  					"introduce the argument value.",
   335  			},
   336  		},
   337  	}
   338  	for name, tc := range testcases {
   339  		consoleRef, err := ref.GenerateTerraformCapabilityProperties(tc.args.cap)
   340  		var errMsg string
   341  		if err != nil {
   342  			errMsg = err.Error()
   343  			if diff := cmp.Diff(tc.want.errMsg, errMsg, test.EquateErrors()); diff != "" {
   344  				t.Errorf("\n%s\nGenerateTerraformCapabilityProperties(...): -want error, +got error:\n%s\n", name, diff)
   345  			}
   346  		} else {
   347  			if diff := cmp.Diff(len(consoleRef), 2); diff != "" {
   348  				t.Errorf("\n%s\nGenerateTerraformCapabilityProperties(...): -want, +got:\n%s\n", name, diff)
   349  			}
   350  			if diff := cmp.Diff(tc.want.tableName1, consoleRef[0].TableName); diff != "" {
   351  				t.Errorf("\n%s\nGenerateTerraformCapabilityProperties(...): -want, +got:\n%s\n", name, diff)
   352  			}
   353  			if diff := cmp.Diff(tc.want.tableName2, consoleRef[1].TableName); diff != "" {
   354  				t.Errorf("\n%s\nGexnerateTerraformCapabilityProperties(...): -want, +got:\n%s\n", name, diff)
   355  			}
   356  		}
   357  	}
   358  }
   359  
   360  func TestPrepareTerraformOutputs(t *testing.T) {
   361  	type args struct {
   362  		tableName     string
   363  		parameterList []ReferenceParameter
   364  	}
   365  
   366  	param := ReferenceParameter{}
   367  	param.Name = "ID"
   368  	param.Usage = "Identity of the cloud resource"
   369  
   370  	testcases := []struct {
   371  		args   args
   372  		expect string
   373  	}{
   374  		{
   375  			args: args{
   376  				tableName:     "",
   377  				parameterList: nil,
   378  			},
   379  			expect: "",
   380  		},
   381  		{
   382  			args: args{
   383  				tableName:     "abc",
   384  				parameterList: []ReferenceParameter{param},
   385  			},
   386  			expect: "\n\nabc\n\n Name | Description \n ------------ | ------------- \n ID | Identity of the cloud resource\n",
   387  		},
   388  	}
   389  	ref := &MarkdownReference{}
   390  	for _, tc := range testcases {
   391  		t.Run("", func(t *testing.T) {
   392  			content := ref.prepareTerraformOutputs(tc.args.tableName, tc.args.parameterList)
   393  			if content != tc.expect {
   394  				t.Errorf("prepareTerraformOutputs(...): -want, +got:\n%s\n", cmp.Diff(tc.expect, content))
   395  			}
   396  		})
   397  	}
   398  }
   399  
   400  func TestMakeReadableTitle(t *testing.T) {
   401  	type args struct {
   402  		ref   *MarkdownReference
   403  		title string
   404  	}
   405  
   406  	ref := &MarkdownReference{}
   407  
   408  	refZh := &MarkdownReference{}
   409  	refZh.I18N = &Zh
   410  
   411  	testcases := []struct {
   412  		args args
   413  		want string
   414  	}{
   415  		{
   416  			args: args{
   417  				title: "abc",
   418  				ref:   ref,
   419  			},
   420  			want: "Abc",
   421  		},
   422  		{
   423  			args: args{
   424  				title: "abc-def",
   425  				ref:   ref,
   426  			},
   427  			want: "Abc-Def",
   428  		},
   429  		{
   430  			args: args{
   431  				title: "alibaba-def-ghi",
   432  				ref:   ref,
   433  			},
   434  			want: "Alibaba Cloud DEF-GHI",
   435  		},
   436  		{
   437  			args: args{
   438  				title: "alibaba-def-ghi",
   439  				ref:   refZh,
   440  			},
   441  			want: "阿里云 DEF-GHI",
   442  		},
   443  		{
   444  			args: args{
   445  				title: "aws-jk",
   446  				ref:   refZh,
   447  			},
   448  			want: "AWS JK",
   449  		},
   450  		{
   451  			args: args{
   452  				title: "azure-jk",
   453  				ref:   refZh,
   454  			},
   455  			want: "Azure JK",
   456  		},
   457  	}
   458  	for _, tc := range testcases {
   459  		t.Run("", func(t *testing.T) {
   460  			title := tc.args.ref.makeReadableTitle(tc.args.title)
   461  			if title != tc.want {
   462  				t.Errorf("makeReadableTitle(...): -want, +got:\n%s\n", cmp.Diff(tc.want, title))
   463  			}
   464  		})
   465  	}
   466  }
   467  
   468  func TestParseLocalFile(t *testing.T) {
   469  	testcases := []struct {
   470  		localFilePath string
   471  		want          types.Capability
   472  	}{
   473  		{
   474  			localFilePath: "testdata/terraform-alibaba-ask.yaml",
   475  			want: types.Capability{
   476  				Name:                   "alibaba-ask",
   477  				Description:            "Terraform configuration for Alibaba Cloud Serverless Kubernetes (ASK)",
   478  				TerraformConfiguration: "https://github.com/kubevela-contrib/terraform-modules.git",
   479  				ConfigurationType:      "remote",
   480  				Path:                   "alibaba/cs/serverless-kubernetes",
   481  			},
   482  		},
   483  		{
   484  			localFilePath: "testdata/terraform-aws-elb.yaml",
   485  			want: types.Capability{
   486  				Name:                   "aws-elb",
   487  				Description:            "Terraform module which creates ELB resources on AWS",
   488  				TerraformConfiguration: "https://github.com/terraform-aws-modules/terraform-aws-elb.git",
   489  				ConfigurationType:      "remote",
   490  				Path:                   "",
   491  			},
   492  		},
   493  		{
   494  			localFilePath: "testdata/terraform-azure-database-mariadb.yaml",
   495  			want: types.Capability{
   496  				Name:                   "azure-database-mariadb",
   497  				Description:            "Terraform configuration for Azure Database Mariadb",
   498  				TerraformConfiguration: "",
   499  				ConfigurationType:      "",
   500  				Path:                   "",
   501  			},
   502  		},
   503  		{
   504  			localFilePath: "testdata/terraform-baidu-vpc.yaml",
   505  			want: types.Capability{
   506  				Name:                   "baidu-vpc",
   507  				Description:            "Baidu Cloud VPC",
   508  				TerraformConfiguration: "",
   509  				ConfigurationType:      "",
   510  				Path:                   "",
   511  			},
   512  		},
   513  		{
   514  			localFilePath: "testdata/terraform-gcp-gcs.yaml",
   515  			want: types.Capability{
   516  				Name:                   "gcp-gcs",
   517  				Description:            "GCP Gcs",
   518  				TerraformConfiguration: "https://github.com/woernfl/terraform-gcp-gcs.git",
   519  				ConfigurationType:      "remote",
   520  				Path:                   "",
   521  			},
   522  		},
   523  		{
   524  			localFilePath: "testdata/terraform-tencent-subnet.yaml",
   525  			want: types.Capability{
   526  				Name:                   "tencent-subnet",
   527  				Description:            "Tencent Cloud Subnet",
   528  				TerraformConfiguration: "",
   529  				ConfigurationType:      "",
   530  				Path:                   "",
   531  			},
   532  		},
   533  	}
   534  	for _, tc := range testcases {
   535  		t.Run("", func(t *testing.T) {
   536  			lc, err := ParseLocalFile(tc.localFilePath, common.Args{})
   537  			if err != nil {
   538  				t.Errorf("ParseLocalFile(...): -want: %v, got error: %s\n", tc.want, err)
   539  			}
   540  			if !reflect.DeepEqual(*lc, tc.want) {
   541  				if !reflect.DeepEqual(lc.Name, tc.want.Name) {
   542  					t.Errorf("Name not equal, - got: %v - want: %v", lc.Name, tc.want.Name)
   543  				}
   544  				if !reflect.DeepEqual(lc.Description, tc.want.Description) {
   545  					t.Errorf("Description not equal, - got: %v - want: %v", lc.Description, tc.want.Description)
   546  				}
   547  				if !reflect.DeepEqual(lc.TerraformConfiguration, tc.want.TerraformConfiguration) {
   548  					if len(lc.TerraformConfiguration) == 0 {
   549  						t.Errorf("Parse TerraformConfiguration failed")
   550  					}
   551  				}
   552  				if !reflect.DeepEqual(lc.ConfigurationType, tc.want.ConfigurationType) {
   553  					t.Errorf("ConfigurationType not equal, - got: %v - want: %v", lc.ConfigurationType, tc.want.ConfigurationType)
   554  				}
   555  				if !reflect.DeepEqual(lc.Path, tc.want.Path) {
   556  					t.Errorf("Path not equal, - got: %v - want: %v", lc.Path, tc.want.Path)
   557  				}
   558  			}
   559  		})
   560  	}
   561  }
   562  
   563  func TestExtractParameter(t *testing.T) {
   564  	testcases := map[string]struct {
   565  		cueTemplate string
   566  		contains    string
   567  	}{
   568  		"normal-case": {
   569  			cueTemplate: `parameter: {
   570  	str: string
   571  	itr: int
   572  	btr: bool
   573  	ct: cts: string
   574  }`,
   575  			contains: `### normal-case
   576  
   577   Name | Description | Type | Required | Default 
   578   ---- | ----------- | ---- | -------- | ------- 
   579   str |  | string | true |  
   580   itr |  | int | true |  
   581   btr |  | bool | true |  
   582   ct |  | [ct](#ct) | true |  
   583  
   584  
   585  #### ct
   586  
   587   Name | Description | Type | Required | Default 
   588   ---- | ----------- | ---- | -------- | ------- 
   589   cts |  | string | true |`,
   590  		},
   591  		"normal-map-string-string": {
   592  			cueTemplate: `parameter: {
   593  	envMappings: [string]: string
   594  }`,
   595  			contains: `### normal-map-string-string
   596  
   597   Name | Description | Type | Required | Default 
   598   ---- | ----------- | ---- | -------- | ------- 
   599   envMappings |  | map[string]string | true |`,
   600  		},
   601  		"normal-map-case": {
   602  			cueTemplate: `parameter: {
   603  	// +usage=The mapping of environment variables to secret
   604  	envMappings: [string]: #KeySecret
   605  }
   606  #KeySecret: {
   607  	key?:   string
   608  	secret: string
   609  }`,
   610  			contains: `### normal-map-case
   611  
   612   Name | Description | Type | Required | Default 
   613   ---- | ----------- | ---- | -------- | ------- 
   614   envMappings | The mapping of environment variables to secret. | map[string]KeySecret(#keysecret) | true |  
   615  
   616  
   617  #### KeySecret
   618  
   619   Name | Description | Type | Required | Default 
   620   ---- | ----------- | ---- | -------- | ------- 
   621   key |  | string | false |  
   622   secret |  | string | true |`,
   623  		},
   624  		"or-case-with-type": {
   625  			cueTemplate: `	parameter: {
   626  	   		orValue:  #KeyConfig | #KeySecret
   627  	   	}
   628  
   629  	   	#KeySecret: {
   630  	   		key:   "abc"
   631  	   		secret: string
   632  	   	}
   633  
   634  	   	#KeyConfig: {
   635  	   		key:   "abc"
   636  	   		config: string
   637  	   	}`,
   638  			contains: `### or-case-with-type
   639  
   640   Name | Description | Type | Required | Default 
   641   ---- | ----------- | ---- | -------- | ------- 
   642   orValue |  | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true |  
   643  
   644  
   645  #### KeyConfig
   646  
   647   Name | Description | Type | Required | Default 
   648   ---- | ----------- | ---- | -------- | ------- 
   649   key |  | string | true |  
   650   config |  | string | true |  
   651  
   652  
   653  #### KeySecret
   654  
   655   Name | Description | Type | Required | Default 
   656   ---- | ----------- | ---- | -------- | ------- 
   657   key |  | string | true |  
   658   secret |  | string | true | `,
   659  		},
   660  		"or-type-with-const-str": {
   661  			cueTemplate: `parameter: {
   662  	  type: *"configMap" | "secret" | "emptyDir" | "ephemeral"
   663  }`,
   664  			contains: `### or-type-with-const-str
   665  
   666   Name | Description | Type | Required | Default 
   667   ---- | ----------- | ---- | -------- | ------- 
   668   type |  | "configMap" or "secret" or "emptyDir" or "ephemeral" | false | configMap`,
   669  		},
   670  		"or-type-with-const-and-string": {
   671  			cueTemplate: `parameter: {
   672  	  type: *"configMap" | "secret" | "emptyDir" | string
   673  }`,
   674  			contains: `### or-type-with-const-and-string
   675  
   676   Name | Description | Type | Required | Default 
   677   ---- | ----------- | ---- | -------- | ------- 
   678   type |  | string | false | configMap`,
   679  		},
   680  		"var-or-with-struct-var": {
   681  			cueTemplate: `
   682  	   	parameter: {
   683  	   		orValue:  KeyConfig | KeySecret
   684  	   	}
   685  
   686  	   	KeySecret: {
   687  	   		key:   "abc"
   688  	   		secret: string
   689  	   	}
   690  
   691  	   	KeyConfig: {
   692  	   		key:   "abc"
   693  	   		config: string
   694  	   	}`,
   695  			contains: `### var-or-with-struct-var
   696  
   697   Name | Description | Type | Required | Default 
   698   ---- | ----------- | ---- | -------- | ------- 
   699   orValue |  | [KeyConfig](#keyconfig) or [KeySecret](#keysecret) | true |  
   700  
   701  
   702  #### KeyConfig
   703  
   704   Name | Description | Type | Required | Default 
   705   ---- | ----------- | ---- | -------- | ------- 
   706   key |  | string | true |  
   707   config |  | string | true |  
   708  
   709  
   710  #### KeySecret
   711  
   712   Name | Description | Type | Required | Default 
   713   ---- | ----------- | ---- | -------- | ------- 
   714   key |  | string | true |  
   715   secret |  | string | true | `,
   716  		},
   717  	}
   718  
   719  	ref := &MarkdownReference{}
   720  	for key, ca := range testcases {
   721  		cueValue, _ := common.GetCUEParameterValue(ca.cueTemplate, nil)
   722  		out, _, err := ref.parseParameters("", cueValue, key, 0, false)
   723  		assert.NoError(t, err, key)
   724  		assert.Contains(t, out, ca.contains, key)
   725  	}
   726  }
   727  
   728  func TestExtractParameterFromFiles(t *testing.T) {
   729  	ref := &MarkdownReference{}
   730  	testcases := map[string]struct {
   731  		path     string
   732  		contains string
   733  	}{
   734  		"env": {
   735  			path: "testdata/parameter/env.cue",
   736  			contains: `### env
   737  
   738   Name | Description | Type | Required | Default 
   739   ---- | ----------- | ---- | -------- | ------- 
   740    |  | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false |  
   741  
   742  
   743  #### PatchParams
   744  
   745   Name | Description | Type | Required | Default 
   746   ---- | ----------- | ---- | -------- | ------- 
   747   containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty 
   748   replace | Specify if replacing the whole environment settings for the container. | bool | false | false 
   749   env | Specify the  environment variables to merge, if key already existing, override its value. | map[string]string | true |  
   750   unset | Specify which existing environment variables to unset. | []string | true |  
   751  
   752  
   753  #### type-option-2
   754  
   755   Name | Description | Type | Required | Default 
   756   ---- | ----------- | ---- | -------- | ------- 
   757   containers | Specify the environment variables for multiple containers. | [[]containers](#containers) | true |  
   758  
   759  
   760  ##### containers
   761  
   762   Name | Description | Type | Required | Default 
   763   ---- | ----------- | ---- | -------- | ------- 
   764   containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty 
   765   replace | Specify if replacing the whole environment settings for the container. | bool | false | false 
   766   env | Specify the  environment variables to merge, if key already existing, override its value. | map[string]string | true |  
   767   unset | Specify which existing environment variables to unset. | []string | true |`,
   768  		},
   769  		"command": {
   770  			path: "testdata/parameter/command.cue",
   771  			contains: `### command
   772  
   773   Name | Description | Type | Required | Default 
   774   ---- | ----------- | ---- | -------- | ------- 
   775    |  | [PatchParams](#patchparams) or [type-option-2](#type-option-2) | false |  
   776  
   777  
   778  #### PatchParams
   779  
   780   Name | Description | Type | Required | Default 
   781   ---- | ----------- | ---- | -------- | ------- 
   782   containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty 
   783   command | Specify the command to use in the target container, if not set, it will not be changed. | null | true |  
   784   args | Specify the args to use in the target container, if set, it will override existing args. | null | true |  
   785   addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true |  
   786   delArgs | Specify the existing args to delete in the target container, cannot be used with args. | null | true |  
   787  
   788  
   789  #### type-option-2
   790  
   791   Name | Description | Type | Required | Default 
   792   ---- | ----------- | ---- | -------- | ------- 
   793   containers | Specify the commands for multiple containers. | [[]containers](#containers) | true |  
   794  
   795  
   796  ##### containers
   797  
   798   Name | Description | Type | Required | Default 
   799   ---- | ----------- | ---- | -------- | ------- 
   800   containerName | Specify the name of the target container, if not set, use the component name. | string | false | empty 
   801   command | Specify the command to use in the target container, if not set, it will not be changed. | null | true |  
   802   args | Specify the args to use in the target container, if set, it will override existing args. | null | true |  
   803   addArgs | Specify the args to add in the target container, existing args will be kept, cannot be used with args. | null | true |  
   804   delArgs | Specify the existing args to delete in the target container, cannot be used with args. | null | true |`,
   805  		},
   806  		"condition": {
   807  			path: "testdata/parameter/condition.cue",
   808  			contains: `### condition
   809  
   810   Name | Description | Type | Required | Default 
   811   ---- | ----------- | ---- | -------- | ------- 
   812   volumes |  | [[]volumes](#volumes) | true |  
   813  
   814  
   815  #### volumes
   816  
   817   Name | Description | Type | Required | Default 
   818   ---- | ----------- | ---- | -------- | ------- 
   819   name |  | string | true |  
   820   defaultMode | only works when type equals configmap. | int | false | 420 
   821   type |  | "configMap" or "secret" or "emptyDir" or "ephemeral" | false | configMap`,
   822  		},
   823  	}
   824  	for key, ca := range testcases {
   825  		content, err := os.ReadFile(ca.path)
   826  		assert.NoError(t, err, ca.path)
   827  		cueValue, _ := common.GetCUEParameterValue(string(content), nil)
   828  		out, _, err := ref.parseParameters("", cueValue, key, 0, false)
   829  		assert.NoError(t, err, key)
   830  		assert.Contains(t, out, ca.contains, key)
   831  	}
   832  }