...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/conversion/converter_test.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/conversion

     1  // Copyright 2022 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package conversion_test
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/constants"
    22  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/conversion"
    23  	dclmetadata "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/dcl/metadata"
    24  	testdclschemaloader "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/dclschemaloader"
    25  	testservicemetadataloader "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/servicemetadataloader"
    26  
    27  	dclunstruct "github.com/GoogleCloudPlatform/declarative-resource-client-library/unstructured"
    28  	"github.com/google/go-cmp/cmp"
    29  	"github.com/nasa9084/go-openapi"
    30  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    31  )
    32  
    33  var (
    34  	stv_foo = dclunstruct.ServiceTypeVersion{
    35  		Service: "test1",
    36  		Type:    "Foo",
    37  		Version: "beta",
    38  	}
    39  	stv_bar = dclunstruct.ServiceTypeVersion{
    40  		Service: "test1",
    41  		Type:    "Bar",
    42  		Version: "beta",
    43  	}
    44  	stv_baz = dclunstruct.ServiceTypeVersion{
    45  		Service: "test2",
    46  		Type:    "Baz",
    47  		Version: "beta",
    48  	}
    49  	stv_noname = dclunstruct.ServiceTypeVersion{
    50  		Service: "test2",
    51  		Type:    "NoName",
    52  		Version: "beta",
    53  	}
    54  	stv_nolabelsextension = dclunstruct.ServiceTypeVersion{
    55  		Service: "test1",
    56  		Type:    "NoLabelsExtension",
    57  		Version: "beta",
    58  	}
    59  )
    60  
    61  func TestConverter_KRMObjectToDCLObject(t *testing.T) {
    62  	schemaLoader := testdclschemaloader.New(dclSchemaMap)
    63  	smLoader := testservicemetadataloader.NewForUnitTest()
    64  	converter := conversion.New(schemaLoader, smLoader)
    65  	kind := "Test1Foo"
    66  	apiVersion := "test1.cnrm.cloud.google.com/v1alpha1"
    67  	projectID := "dcl-test"
    68  	tests := []struct {
    69  		name     string
    70  		krmObj   *unstructured.Unstructured
    71  		dclObj   *dclunstruct.Resource
    72  		hasError bool
    73  	}{
    74  		{
    75  			name: "name and project only",
    76  			krmObj: &unstructured.Unstructured{
    77  				Object: map[string]interface{}{
    78  					"kind":       kind,
    79  					"apiVersion": apiVersion,
    80  					"metadata": map[string]interface{}{
    81  						"name":      "foo-example",
    82  						"namespace": "test-system",
    83  						"annotations": map[string]interface{}{
    84  							"cnrm.cloud.google.com/project-id": projectID,
    85  						},
    86  					},
    87  					"spec": map[string]interface{}{
    88  						"resourceID": "CustomizedName",
    89  					},
    90  				},
    91  			},
    92  			dclObj: &dclunstruct.Resource{
    93  				STV: stv_foo,
    94  				Object: map[string]interface{}{
    95  					"name":    "CustomizedName",
    96  					"project": projectID,
    97  				},
    98  			},
    99  		},
   100  		{
   101  			name: "default to metadata.name if user-specified name is not configured in spec",
   102  			krmObj: &unstructured.Unstructured{
   103  				Object: map[string]interface{}{
   104  					"kind":       kind,
   105  					"apiVersion": apiVersion,
   106  					"metadata": map[string]interface{}{
   107  						"name":      "foo-example",
   108  						"namespace": "test-system",
   109  						"annotations": map[string]interface{}{
   110  							"cnrm.cloud.google.com/project-id": projectID,
   111  						},
   112  					},
   113  					"spec": map[string]interface{}{},
   114  				},
   115  			},
   116  			dclObj: &dclunstruct.Resource{
   117  				STV: stv_foo,
   118  				Object: map[string]interface{}{
   119  					"name":    "foo-example",
   120  					"project": projectID,
   121  				},
   122  			},
   123  		},
   124  		{
   125  			name: "error out if specified resourceID is an empty string",
   126  			krmObj: &unstructured.Unstructured{
   127  				Object: map[string]interface{}{
   128  					"kind":       kind,
   129  					"apiVersion": apiVersion,
   130  					"metadata": map[string]interface{}{
   131  						"name":      "foo-example",
   132  						"namespace": "test-system",
   133  						"annotations": map[string]interface{}{
   134  							"cnrm.cloud.google.com/project-id": projectID,
   135  						},
   136  					},
   137  					"spec": map[string]interface{}{
   138  						"resourceID": "",
   139  					},
   140  				},
   141  			},
   142  			hasError: true,
   143  		},
   144  		{
   145  			name: "server-generated id is configured for acquisition",
   146  			krmObj: &unstructured.Unstructured{
   147  				Object: map[string]interface{}{
   148  					"kind":       "Test2Baz",
   149  					"apiVersion": "test2.cnrm.cloud.google.com/v1alpha1",
   150  					"metadata": map[string]interface{}{
   151  						"name":      "foo-example",
   152  						"namespace": "test-system",
   153  						"annotations": map[string]interface{}{
   154  							"cnrm.cloud.google.com/project-id": projectID,
   155  						},
   156  					},
   157  					"spec": map[string]interface{}{
   158  						"resourceID": "server-generated-value",
   159  					},
   160  				},
   161  			},
   162  			dclObj: &dclunstruct.Resource{
   163  				STV: stv_baz,
   164  				Object: map[string]interface{}{
   165  					"name":    "server-generated-value",
   166  					"project": projectID,
   167  				},
   168  			},
   169  		},
   170  		{
   171  			name: "server-generated id is not configured for creation",
   172  			krmObj: &unstructured.Unstructured{
   173  				Object: map[string]interface{}{
   174  					"kind":       "Test2Baz",
   175  					"apiVersion": "test2.cnrm.cloud.google.com/v1alpha1",
   176  					"metadata": map[string]interface{}{
   177  						"name":      "foo-example",
   178  						"namespace": "test-system",
   179  						"annotations": map[string]interface{}{
   180  							"cnrm.cloud.google.com/project-id": projectID,
   181  						},
   182  					},
   183  					"spec": map[string]interface{}{},
   184  				},
   185  			},
   186  			dclObj: &dclunstruct.Resource{
   187  				STV: stv_baz,
   188  				Object: map[string]interface{}{
   189  					"project": projectID,
   190  				},
   191  			},
   192  		},
   193  		{
   194  			name: "resource with no name field",
   195  			krmObj: &unstructured.Unstructured{
   196  				Object: map[string]interface{}{
   197  					"kind":       "Test2NoName",
   198  					"apiVersion": "test2.cnrm.cloud.google.com/v1alpha1",
   199  					"metadata": map[string]interface{}{
   200  						"name":      "foo-example",
   201  						"namespace": "test-system",
   202  						"annotations": map[string]interface{}{
   203  							"cnrm.cloud.google.com/project-id": projectID,
   204  						},
   205  					},
   206  					"spec": map[string]interface{}{
   207  						"resourceID": "should-be-ignored",
   208  					},
   209  				},
   210  			},
   211  			dclObj: &dclunstruct.Resource{
   212  				STV: stv_noname,
   213  				Object: map[string]interface{}{
   214  					"project": projectID,
   215  				},
   216  			},
   217  		},
   218  		{
   219  			name: "primitive fields",
   220  			krmObj: &unstructured.Unstructured{
   221  				Object: map[string]interface{}{
   222  					"kind":       kind,
   223  					"apiVersion": apiVersion,
   224  					"metadata": map[string]interface{}{
   225  						"name":      "foo-example",
   226  						"namespace": "test-system",
   227  						"annotations": map[string]interface{}{
   228  							"cnrm.cloud.google.com/project-id": projectID,
   229  						},
   230  					},
   231  					"spec": map[string]interface{}{
   232  						"intKey":     1,
   233  						"numberKey":  0.5,
   234  						"booleanKey": true,
   235  						"stringKey":  "StringVal",
   236  						"resourceID": "CustomizedName",
   237  					},
   238  				},
   239  			},
   240  			dclObj: &dclunstruct.Resource{
   241  				STV: stv_foo,
   242  				Object: map[string]interface{}{
   243  					"intKey":     int64(1),
   244  					"numberKey":  float64(0.5),
   245  					"booleanKey": true,
   246  					"stringKey":  "StringVal",
   247  					"name":       "CustomizedName",
   248  					"project":    projectID,
   249  				},
   250  			},
   251  		},
   252  		{
   253  			name: "numeric values canonicalization",
   254  			krmObj: &unstructured.Unstructured{
   255  				Object: map[string]interface{}{
   256  					"kind":       kind,
   257  					"apiVersion": apiVersion,
   258  					"metadata": map[string]interface{}{
   259  						"name":      "foo-example",
   260  						"namespace": "test-system",
   261  						"annotations": map[string]interface{}{
   262  							"cnrm.cloud.google.com/project-id": projectID,
   263  						},
   264  					},
   265  					"spec": map[string]interface{}{
   266  						"intKey":     float64(1),
   267  						"numberKey":  int64(1),
   268  						"resourceID": "CustomizedName",
   269  					},
   270  				},
   271  			},
   272  			dclObj: &dclunstruct.Resource{
   273  				STV: stv_foo,
   274  				Object: map[string]interface{}{
   275  					"intKey":    int64(1),
   276  					"numberKey": float64(1),
   277  					"name":      "CustomizedName",
   278  					"project":   projectID,
   279  				},
   280  			},
   281  		},
   282  		{
   283  			name: "list of primitives",
   284  			krmObj: &unstructured.Unstructured{
   285  				Object: map[string]interface{}{
   286  					"kind":       kind,
   287  					"apiVersion": apiVersion,
   288  					"metadata": map[string]interface{}{
   289  						"name":      "foo-example",
   290  						"namespace": "test-system",
   291  						"annotations": map[string]interface{}{
   292  							"cnrm.cloud.google.com/project-id": projectID,
   293  						},
   294  					},
   295  					"spec": map[string]interface{}{
   296  						"primitiveArrayKey": []interface{}{
   297  							"myString1",
   298  							"myString2",
   299  						},
   300  						"resourceID": "foo-example",
   301  					},
   302  				},
   303  			},
   304  			dclObj: &dclunstruct.Resource{
   305  				STV: stv_foo,
   306  				Object: map[string]interface{}{
   307  					"primitiveArrayKey": []interface{}{
   308  						"myString1",
   309  						"myString2",
   310  					},
   311  					"name":    "foo-example",
   312  					"project": projectID,
   313  				},
   314  			},
   315  		},
   316  		{
   317  			name: "nested object",
   318  			krmObj: &unstructured.Unstructured{
   319  				Object: map[string]interface{}{
   320  					"kind":       kind,
   321  					"apiVersion": apiVersion,
   322  					"metadata": map[string]interface{}{
   323  						"name":      "foo-example",
   324  						"namespace": "test-system",
   325  						"annotations": map[string]interface{}{
   326  							"cnrm.cloud.google.com/project-id": projectID,
   327  						},
   328  					},
   329  					"spec": map[string]interface{}{
   330  						"nestedObjectKey": map[string]interface{}{
   331  							"nestedField1": true,
   332  							"nestedField2": "StringVal",
   333  							"nestedReferenceFieldRef": map[string]interface{}{
   334  								"external": "reference-url",
   335  							},
   336  							"nestedSensitiveField": map[string]interface{}{
   337  								"value": "sensitive-data",
   338  							},
   339  						},
   340  						"resourceID": "foo-example",
   341  					},
   342  				},
   343  			},
   344  			dclObj: &dclunstruct.Resource{
   345  				STV: stv_foo,
   346  				Object: map[string]interface{}{
   347  					"nestedObjectKey": map[string]interface{}{
   348  						"nestedField1":         true,
   349  						"nestedField2":         "StringVal",
   350  						"nestedReferenceField": "reference-url",
   351  						"nestedSensitiveField": "sensitive-data",
   352  					},
   353  					"name":    "foo-example",
   354  					"project": projectID,
   355  				},
   356  			},
   357  		},
   358  		{
   359  			name: "string-object map",
   360  			krmObj: &unstructured.Unstructured{
   361  				Object: map[string]interface{}{
   362  					"kind":       kind,
   363  					"apiVersion": apiVersion,
   364  					"metadata": map[string]interface{}{
   365  						"name":      "foo-example",
   366  						"namespace": "test-system",
   367  						"annotations": map[string]interface{}{
   368  							"cnrm.cloud.google.com/project-id": projectID,
   369  						},
   370  					},
   371  					"spec": map[string]interface{}{
   372  						"stringObjectMapKey": map[string]interface{}{
   373  							"someKey": map[string]interface{}{
   374  								"objectField1": 1.0,
   375  								"objectReferenceArrayKey": []interface{}{
   376  									map[string]interface{}{
   377  										"external": "my-ref-1",
   378  									},
   379  									map[string]interface{}{
   380  										"external": "my-ref-2",
   381  									},
   382  								},
   383  								"readOnlyField":          "val1",
   384  								"readOnlySensitiveField": "sensitiveVal",
   385  								"readOnlyReferenceField": "referenceVal",
   386  							},
   387  							"someOtherKey": map[string]interface{}{
   388  								"objectField1": 2.0,
   389  								"objectReferenceArrayKey": []interface{}{
   390  									map[string]interface{}{
   391  										"external": "my-ref-3",
   392  									},
   393  									map[string]interface{}{
   394  										"external": "my-ref-4",
   395  									},
   396  								},
   397  								"readOnlyField": "val2",
   398  							},
   399  						},
   400  						"resourceID": "foo-example",
   401  					},
   402  				},
   403  			},
   404  			dclObj: &dclunstruct.Resource{
   405  				STV: stv_foo,
   406  				Object: map[string]interface{}{
   407  					"stringObjectMapKey": map[string]interface{}{
   408  						"someKey": map[string]interface{}{
   409  							"objectField1": 1.0,
   410  							"objectReferenceArrayKey": []interface{}{
   411  								"my-ref-1",
   412  								"my-ref-2",
   413  							},
   414  							// Read-only fields are left in for objects within
   415  							// collections (maps, arrays)
   416  							"readOnlyField": "val1",
   417  							// Read-only sensitive and reference fields are
   418  							// left in objects within collections (maps,
   419  							// arrays) and simply treated as strings rather
   420  							// than sensitive or reference structs
   421  							"readOnlySensitiveField": "sensitiveVal",
   422  							"readOnlyReferenceField": "referenceVal",
   423  						},
   424  						"someOtherKey": map[string]interface{}{
   425  							"objectField1": 2.0,
   426  							"objectReferenceArrayKey": []interface{}{
   427  								"my-ref-3",
   428  								"my-ref-4",
   429  							},
   430  							"readOnlyField": "val2",
   431  						},
   432  					},
   433  					"name":    "foo-example",
   434  					"project": projectID,
   435  				},
   436  			},
   437  		},
   438  		{
   439  			name: "list of objects",
   440  			krmObj: &unstructured.Unstructured{
   441  				Object: map[string]interface{}{
   442  					"kind":       kind,
   443  					"apiVersion": apiVersion,
   444  					"metadata": map[string]interface{}{
   445  						"name":      "foo-example",
   446  						"namespace": "test-system",
   447  						"annotations": map[string]interface{}{
   448  							"cnrm.cloud.google.com/project-id": projectID,
   449  						},
   450  					},
   451  					"spec": map[string]interface{}{
   452  						"intKey":     1,
   453  						"numberKey":  0.5,
   454  						"booleanKey": true,
   455  						"stringKey":  "StringVal",
   456  						"objectArrayKey": []interface{}{
   457  							map[string]interface{}{
   458  								"field1":                 1,
   459  								"field2":                 "item1",
   460  								"readOnlyField":          "oldVal1",
   461  								"readOnlySensitiveField": "sensitiveVal",
   462  								"readOnlyReferenceField": "referenceVal",
   463  							},
   464  							map[string]interface{}{
   465  								"field1":        2,
   466  								"field2":        "item2",
   467  								"readOnlyField": "oldVal2",
   468  							},
   469  						},
   470  						"resourceID": "CustomizedName",
   471  					},
   472  				},
   473  			},
   474  			dclObj: &dclunstruct.Resource{
   475  				STV: stv_foo,
   476  				Object: map[string]interface{}{
   477  					"intKey":     int64(1),
   478  					"numberKey":  float64(0.5),
   479  					"booleanKey": true,
   480  					"stringKey":  "StringVal",
   481  					"objectArrayKey": []interface{}{
   482  						map[string]interface{}{
   483  							"field1": float64(1),
   484  							"field2": "item1",
   485  							// Read-only fields are left in for objects within
   486  							// collections (maps, arrays)
   487  							"readOnlyField": "oldVal1",
   488  							// Read-only sensitive and reference fields are
   489  							// left in objects within collections (maps,
   490  							// arrays) and simply treated as strings rather
   491  							// than sensitive or reference structs
   492  							"readOnlySensitiveField": "sensitiveVal",
   493  							"readOnlyReferenceField": "referenceVal",
   494  						},
   495  						map[string]interface{}{
   496  							"field1":        float64(2),
   497  							"field2":        "item2",
   498  							"readOnlyField": "oldVal2",
   499  						},
   500  					},
   501  					"name":    "CustomizedName",
   502  					"project": projectID,
   503  				},
   504  			},
   505  		},
   506  		{
   507  			name: "sensitive field",
   508  			krmObj: &unstructured.Unstructured{
   509  				Object: map[string]interface{}{
   510  					"kind":       kind,
   511  					"apiVersion": apiVersion,
   512  					"metadata": map[string]interface{}{
   513  						"name":      "foo-example",
   514  						"namespace": "test-system",
   515  						"annotations": map[string]interface{}{
   516  							"cnrm.cloud.google.com/project-id": projectID,
   517  						},
   518  					},
   519  					"spec": map[string]interface{}{
   520  						"sensitiveFieldKey": map[string]interface{}{
   521  							"value": "sensitive-data",
   522  						},
   523  						"resourceID": "CustomizedName",
   524  					},
   525  				},
   526  			},
   527  			dclObj: &dclunstruct.Resource{
   528  				STV: stv_foo,
   529  				Object: map[string]interface{}{
   530  					"sensitiveFieldKey": "sensitive-data",
   531  					"name":              "CustomizedName",
   532  					"project":           projectID,
   533  				},
   534  			},
   535  		},
   536  		{
   537  			name: "simple reference field",
   538  			krmObj: &unstructured.Unstructured{
   539  				Object: map[string]interface{}{
   540  					"kind":       kind,
   541  					"apiVersion": apiVersion,
   542  					"metadata": map[string]interface{}{
   543  						"name":      "foo-example",
   544  						"namespace": "test-system",
   545  						"annotations": map[string]interface{}{
   546  							"cnrm.cloud.google.com/project-id": projectID,
   547  						},
   548  					},
   549  					"spec": map[string]interface{}{
   550  						"referenceKeyRef": map[string]interface{}{
   551  							"external": "my-ref",
   552  						},
   553  						"resourceID": "CustomizedName",
   554  					},
   555  				},
   556  			},
   557  			dclObj: &dclunstruct.Resource{
   558  				STV: stv_foo,
   559  				Object: map[string]interface{}{
   560  					"referenceKey": "my-ref",
   561  					"name":         "CustomizedName",
   562  					"project":      projectID,
   563  				},
   564  			},
   565  		},
   566  		{
   567  			name: "complex reference field with bar resource kind",
   568  			krmObj: &unstructured.Unstructured{
   569  				Object: map[string]interface{}{
   570  					"kind":       kind,
   571  					"apiVersion": apiVersion,
   572  					"metadata": map[string]interface{}{
   573  						"name":      "foo-example",
   574  						"namespace": "test-system",
   575  						"annotations": map[string]interface{}{
   576  							"cnrm.cloud.google.com/project-id": projectID,
   577  						},
   578  					},
   579  					"spec": map[string]interface{}{
   580  						"complexReferenceKeyRef": map[string]interface{}{
   581  							"external": "bar-url",
   582  						},
   583  						"resourceID": "CustomizedName",
   584  					},
   585  				},
   586  			},
   587  			dclObj: &dclunstruct.Resource{
   588  				STV: stv_foo,
   589  				Object: map[string]interface{}{
   590  					"complexReferenceKey": "bar-url",
   591  					"name":                "CustomizedName",
   592  					"project":             projectID,
   593  				},
   594  			},
   595  		},
   596  		{
   597  			name: "complex reference field with baz resource kind",
   598  			krmObj: &unstructured.Unstructured{
   599  				Object: map[string]interface{}{
   600  					"kind":       kind,
   601  					"apiVersion": apiVersion,
   602  					"metadata": map[string]interface{}{
   603  						"name":      "foo-example",
   604  						"namespace": "test-system",
   605  						"annotations": map[string]interface{}{
   606  							"cnrm.cloud.google.com/project-id": projectID,
   607  						},
   608  					},
   609  					"spec": map[string]interface{}{
   610  						"complexReferenceKeyRef": map[string]interface{}{
   611  							"external": "baz-url",
   612  						},
   613  						"resourceID": "CustomizedName",
   614  					},
   615  				},
   616  			},
   617  			dclObj: &dclunstruct.Resource{
   618  				STV: stv_foo,
   619  				Object: map[string]interface{}{
   620  					"complexReferenceKey": "baz-url",
   621  					"name":                "CustomizedName",
   622  					"project":             projectID,
   623  				},
   624  			},
   625  		},
   626  		{
   627  			name: "a list of references",
   628  			krmObj: &unstructured.Unstructured{
   629  				Object: map[string]interface{}{
   630  					"kind":       kind,
   631  					"apiVersion": apiVersion,
   632  					"metadata": map[string]interface{}{
   633  						"name":      "foo-example",
   634  						"namespace": "test-system",
   635  						"annotations": map[string]interface{}{
   636  							"cnrm.cloud.google.com/project-id": projectID,
   637  						},
   638  					},
   639  					"spec": map[string]interface{}{
   640  						"referenceArrayKey": []interface{}{
   641  							map[string]interface{}{
   642  								"external": "my-ref-1",
   643  							},
   644  							map[string]interface{}{
   645  								"external": "my-ref-2",
   646  							},
   647  						},
   648  						"resourceID": "CustomizedName",
   649  					},
   650  				},
   651  			},
   652  			dclObj: &dclunstruct.Resource{
   653  				STV: stv_foo,
   654  				Object: map[string]interface{}{
   655  					"referenceArrayKey": []interface{}{
   656  						"my-ref-1",
   657  						"my-ref-2",
   658  					},
   659  					"name":    "CustomizedName",
   660  					"project": projectID,
   661  				},
   662  			},
   663  		},
   664  	}
   665  	for _, tc := range tests {
   666  		tc := tc
   667  		t.Run(tc.name, func(t *testing.T) {
   668  			t.Parallel()
   669  			dclObj, err := converter.KRMObjectToDCLObject(tc.krmObj)
   670  			if tc.hasError {
   671  				if err == nil {
   672  					t.Fatalf("expected to get error when converting KRM to DCL")
   673  				}
   674  				return
   675  			}
   676  			if err != nil {
   677  				t.Fatalf("unexpected error: %v", err)
   678  			}
   679  			if !reflect.DeepEqual(dclObj, tc.dclObj) {
   680  				t.Fatalf("unexpected converted dcl obj diff (-want +got): \n%v", cmp.Diff(tc.dclObj, dclObj))
   681  			}
   682  		})
   683  	}
   684  }
   685  
   686  func TestConverter_KRMObjectToDCLObjectForHierarchicalReferences(t *testing.T) {
   687  	tests := []struct {
   688  		name   string
   689  		schema *openapi.Schema
   690  		krmObj *unstructured.Unstructured
   691  		dclObj *dclunstruct.Resource
   692  	}{
   693  		{
   694  			name: "single-parent resource",
   695  			schema: &openapi.Schema{
   696  				Type: "object",
   697  				Properties: map[string]*openapi.Schema{
   698  					"project": &openapi.Schema{
   699  						Type: "string",
   700  						Extension: map[string]interface{}{
   701  							"x-dcl-references": []interface{}{
   702  								map[interface{}]interface{}{
   703  									"field":    "name",
   704  									"parent":   true,
   705  									"resource": "Cloudresourcemanager/Project",
   706  								},
   707  							},
   708  						},
   709  					},
   710  				},
   711  			},
   712  			krmObj: &unstructured.Unstructured{
   713  				Object: map[string]interface{}{
   714  					"kind":       "Test5ProjectRef",
   715  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
   716  					"metadata": map[string]interface{}{
   717  						"name": "name",
   718  					},
   719  					"spec": map[string]interface{}{
   720  						"projectRef": map[string]interface{}{
   721  							"external": "project_id",
   722  						},
   723  					},
   724  				},
   725  			},
   726  			dclObj: &dclunstruct.Resource{
   727  				STV: dclunstruct.ServiceTypeVersion{
   728  					Service: "test5",
   729  					Type:    "ProjectRef",
   730  					Version: "beta",
   731  				},
   732  				Object: map[string]interface{}{
   733  					"project": "project_id",
   734  				},
   735  			},
   736  		},
   737  		{
   738  			name: "multi-parent resource with project reference",
   739  			schema: &openapi.Schema{
   740  				Type: "object",
   741  				Properties: map[string]*openapi.Schema{
   742  					"parent": &openapi.Schema{
   743  						Type: "string",
   744  						Extension: map[string]interface{}{
   745  							"x-dcl-references": []interface{}{
   746  								map[interface{}]interface{}{
   747  									"field":    "name",
   748  									"parent":   true,
   749  									"resource": "Cloudresourcemanager/Project",
   750  								},
   751  								map[interface{}]interface{}{
   752  									"field":    "name",
   753  									"parent":   true,
   754  									"resource": "Cloudresourcemanager/Folder",
   755  								},
   756  								map[interface{}]interface{}{
   757  									"field":    "name",
   758  									"parent":   true,
   759  									"resource": "Cloudresourcemanager/Organization",
   760  								},
   761  								map[interface{}]interface{}{
   762  									"field":    "name",
   763  									"parent":   true,
   764  									"resource": "Cloudresourcemanager/BillingAccount",
   765  								},
   766  							},
   767  						},
   768  					},
   769  				},
   770  			},
   771  			krmObj: &unstructured.Unstructured{
   772  				Object: map[string]interface{}{
   773  					"kind":       "Test5MultipleRefs",
   774  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
   775  					"metadata": map[string]interface{}{
   776  						"name": "name",
   777  					},
   778  					"spec": map[string]interface{}{
   779  						"projectRef": map[string]interface{}{
   780  							"external": "project_id",
   781  						},
   782  					},
   783  				},
   784  			},
   785  			dclObj: &dclunstruct.Resource{
   786  				STV: dclunstruct.ServiceTypeVersion{
   787  					Service: "test5",
   788  					Type:    "MultipleRefs",
   789  					Version: "beta",
   790  				},
   791  				Object: map[string]interface{}{
   792  					"parent": "projects/project_id",
   793  				},
   794  			},
   795  		},
   796  		{
   797  			name: "multi-parent resource with folder reference",
   798  			schema: &openapi.Schema{
   799  				Type: "object",
   800  				Properties: map[string]*openapi.Schema{
   801  					"parent": &openapi.Schema{
   802  						Type: "string",
   803  						Extension: map[string]interface{}{
   804  							"x-dcl-references": []interface{}{
   805  								map[interface{}]interface{}{
   806  									"field":    "name",
   807  									"parent":   true,
   808  									"resource": "Cloudresourcemanager/Project",
   809  								},
   810  								map[interface{}]interface{}{
   811  									"field":    "name",
   812  									"parent":   true,
   813  									"resource": "Cloudresourcemanager/Folder",
   814  								},
   815  								map[interface{}]interface{}{
   816  									"field":    "name",
   817  									"parent":   true,
   818  									"resource": "Cloudresourcemanager/Organization",
   819  								},
   820  								map[interface{}]interface{}{
   821  									"field":    "name",
   822  									"parent":   true,
   823  									"resource": "Cloudresourcemanager/BillingAccount",
   824  								},
   825  							},
   826  						},
   827  					},
   828  				},
   829  			},
   830  			krmObj: &unstructured.Unstructured{
   831  				Object: map[string]interface{}{
   832  					"kind":       "Test5MultipleRefs",
   833  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
   834  					"metadata": map[string]interface{}{
   835  						"name": "name",
   836  					},
   837  					"spec": map[string]interface{}{
   838  						"folderRef": map[string]interface{}{
   839  							"external": "folder_id",
   840  						},
   841  					},
   842  				},
   843  			},
   844  			dclObj: &dclunstruct.Resource{
   845  				STV: dclunstruct.ServiceTypeVersion{
   846  					Service: "test5",
   847  					Type:    "MultipleRefs",
   848  					Version: "beta",
   849  				},
   850  				Object: map[string]interface{}{
   851  					"parent": "folders/folder_id",
   852  				},
   853  			},
   854  		},
   855  		{
   856  			name: "multi-parent resource with organization reference",
   857  			schema: &openapi.Schema{
   858  				Type: "object",
   859  				Properties: map[string]*openapi.Schema{
   860  					"parent": &openapi.Schema{
   861  						Type: "string",
   862  						Extension: map[string]interface{}{
   863  							"x-dcl-references": []interface{}{
   864  								map[interface{}]interface{}{
   865  									"field":    "name",
   866  									"parent":   true,
   867  									"resource": "Cloudresourcemanager/Project",
   868  								},
   869  								map[interface{}]interface{}{
   870  									"field":    "name",
   871  									"parent":   true,
   872  									"resource": "Cloudresourcemanager/Folder",
   873  								},
   874  								map[interface{}]interface{}{
   875  									"field":    "name",
   876  									"parent":   true,
   877  									"resource": "Cloudresourcemanager/Organization",
   878  								},
   879  								map[interface{}]interface{}{
   880  									"field":    "name",
   881  									"parent":   true,
   882  									"resource": "Cloudresourcemanager/BillingAccount",
   883  								},
   884  							},
   885  						},
   886  					},
   887  				},
   888  			},
   889  			krmObj: &unstructured.Unstructured{
   890  				Object: map[string]interface{}{
   891  					"kind":       "Test5MultipleRefs",
   892  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
   893  					"metadata": map[string]interface{}{
   894  						"name": "name",
   895  					},
   896  					"spec": map[string]interface{}{
   897  						"organizationRef": map[string]interface{}{
   898  							"external": "organization_id",
   899  						},
   900  					},
   901  				},
   902  			},
   903  			dclObj: &dclunstruct.Resource{
   904  				STV: dclunstruct.ServiceTypeVersion{
   905  					Service: "test5",
   906  					Type:    "MultipleRefs",
   907  					Version: "beta",
   908  				},
   909  				Object: map[string]interface{}{
   910  					"parent": "organizations/organization_id",
   911  				},
   912  			},
   913  		},
   914  		{
   915  			name: "multi-parent resource with billing account reference",
   916  			schema: &openapi.Schema{
   917  				Type: "object",
   918  				Properties: map[string]*openapi.Schema{
   919  					"parent": &openapi.Schema{
   920  						Type: "string",
   921  						Extension: map[string]interface{}{
   922  							"x-dcl-references": []interface{}{
   923  								map[interface{}]interface{}{
   924  									"field":    "name",
   925  									"parent":   true,
   926  									"resource": "Cloudresourcemanager/Project",
   927  								},
   928  								map[interface{}]interface{}{
   929  									"field":    "name",
   930  									"parent":   true,
   931  									"resource": "Cloudresourcemanager/Folder",
   932  								},
   933  								map[interface{}]interface{}{
   934  									"field":    "name",
   935  									"parent":   true,
   936  									"resource": "Cloudresourcemanager/Organization",
   937  								},
   938  								map[interface{}]interface{}{
   939  									"field":    "name",
   940  									"parent":   true,
   941  									"resource": "Cloudresourcemanager/BillingAccount",
   942  								},
   943  							},
   944  						},
   945  					},
   946  				},
   947  			},
   948  			krmObj: &unstructured.Unstructured{
   949  				Object: map[string]interface{}{
   950  					"kind":       "Test5MultipleRefs",
   951  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
   952  					"metadata": map[string]interface{}{
   953  						"name": "name",
   954  					},
   955  					"spec": map[string]interface{}{
   956  						"billingAccountRef": map[string]interface{}{
   957  							"external": "billing_account_id",
   958  						},
   959  					},
   960  				},
   961  			},
   962  			dclObj: &dclunstruct.Resource{
   963  				STV: dclunstruct.ServiceTypeVersion{
   964  					Service: "test5",
   965  					Type:    "MultipleRefs",
   966  					Version: "beta",
   967  				},
   968  				Object: map[string]interface{}{
   969  					"parent": "billingAccounts/billing_account_id",
   970  				},
   971  			},
   972  		},
   973  		{
   974  			name: "multi-parent resource with reference value that already has parent prefix",
   975  			schema: &openapi.Schema{
   976  				Type: "object",
   977  				Properties: map[string]*openapi.Schema{
   978  					"parent": &openapi.Schema{
   979  						Type: "string",
   980  						Extension: map[string]interface{}{
   981  							"x-dcl-references": []interface{}{
   982  								map[interface{}]interface{}{
   983  									"field":    "name",
   984  									"parent":   true,
   985  									"resource": "Cloudresourcemanager/Project",
   986  								},
   987  								map[interface{}]interface{}{
   988  									"field":    "name",
   989  									"parent":   true,
   990  									"resource": "Cloudresourcemanager/Folder",
   991  								},
   992  								map[interface{}]interface{}{
   993  									"field":    "name",
   994  									"parent":   true,
   995  									"resource": "Cloudresourcemanager/Organization",
   996  								},
   997  							},
   998  						},
   999  					},
  1000  				},
  1001  			},
  1002  			krmObj: &unstructured.Unstructured{
  1003  				Object: map[string]interface{}{
  1004  					"kind":       "Test5MultipleRefs",
  1005  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1006  					"metadata": map[string]interface{}{
  1007  						"name": "name",
  1008  					},
  1009  					"spec": map[string]interface{}{
  1010  						"projectRef": map[string]interface{}{
  1011  							"external": "projects/project_id",
  1012  						},
  1013  					},
  1014  				},
  1015  			},
  1016  			dclObj: &dclunstruct.Resource{
  1017  				STV: dclunstruct.ServiceTypeVersion{
  1018  					Service: "test5",
  1019  					Type:    "MultipleRefs",
  1020  					Version: "beta",
  1021  				},
  1022  				Object: map[string]interface{}{
  1023  					"parent": "projects/project_id",
  1024  				},
  1025  			},
  1026  		},
  1027  	}
  1028  
  1029  	smLoader := dclmetadata.NewFromServiceList(testservicemetadataloader.FakeServiceMetadataWithHierarchicalResources())
  1030  	for _, tc := range tests {
  1031  		tc := tc
  1032  		t.Run(tc.name, func(t *testing.T) {
  1033  			t.Parallel()
  1034  			schemaKey := testdclschemaloader.DCLSchemaKeyForGVK(t, tc.krmObj.GroupVersionKind(), smLoader)
  1035  			schemaMap := map[string]*openapi.Schema{
  1036  				schemaKey: tc.schema,
  1037  			}
  1038  			schemaLoader := testdclschemaloader.New(schemaMap)
  1039  			converter := conversion.New(schemaLoader, smLoader)
  1040  
  1041  			dclObj, err := converter.KRMObjectToDCLObject(tc.krmObj)
  1042  			if err != nil {
  1043  				t.Fatalf("got error, but wanted none: %v", err)
  1044  			}
  1045  			if !reflect.DeepEqual(dclObj, tc.dclObj) {
  1046  				t.Fatalf("unexpected converted dcl obj diff (-want +got): \n%v", cmp.Diff(tc.dclObj, dclObj))
  1047  			}
  1048  		})
  1049  	}
  1050  }
  1051  
  1052  func TestConverter_DCLObjectToKRMObject(t *testing.T) {
  1053  	schemaLoader := testdclschemaloader.New(dclSchemaMap)
  1054  	smLoader := testservicemetadataloader.NewForUnitTest()
  1055  	converter := conversion.New(schemaLoader, smLoader)
  1056  	kind := "Test1Foo"
  1057  	apiVersion := "test1.cnrm.cloud.google.com/v1alpha1"
  1058  	projectID := "dcl-test"
  1059  	tests := []struct {
  1060  		name     string
  1061  		krmObj   *unstructured.Unstructured
  1062  		dclObj   *dclunstruct.Resource
  1063  		hasError bool
  1064  	}{
  1065  		{
  1066  			name: "name and project only",
  1067  			krmObj: &unstructured.Unstructured{
  1068  				Object: map[string]interface{}{
  1069  					"kind":       kind,
  1070  					"apiVersion": apiVersion,
  1071  					"metadata": map[string]interface{}{
  1072  						"name":      "foo-example",
  1073  						"namespace": "test-system",
  1074  						"annotations": map[string]interface{}{
  1075  							"cnrm.cloud.google.com/project-id": projectID,
  1076  						},
  1077  					},
  1078  					"spec": map[string]interface{}{
  1079  						"resourceID": "CustomizedName",
  1080  					},
  1081  				},
  1082  			},
  1083  			dclObj: &dclunstruct.Resource{
  1084  				STV: stv_foo,
  1085  				Object: map[string]interface{}{
  1086  					"name":    "CustomizedName",
  1087  					"project": projectID,
  1088  				},
  1089  			},
  1090  		},
  1091  		{
  1092  			name: "server-generated id is returned by the service",
  1093  			krmObj: &unstructured.Unstructured{
  1094  				Object: map[string]interface{}{
  1095  					"kind":       "Test2Baz",
  1096  					"apiVersion": "test2.cnrm.cloud.google.com/v1alpha1",
  1097  					"metadata": map[string]interface{}{
  1098  						"name":      "foo-example",
  1099  						"namespace": "test-system",
  1100  						"annotations": map[string]interface{}{
  1101  							"cnrm.cloud.google.com/project-id": projectID,
  1102  						},
  1103  					},
  1104  					"spec": map[string]interface{}{
  1105  						"resourceID": "server-generated-value",
  1106  					},
  1107  				},
  1108  			},
  1109  			dclObj: &dclunstruct.Resource{
  1110  				STV: stv_baz,
  1111  				Object: map[string]interface{}{
  1112  					"name":    "server-generated-value",
  1113  					"project": projectID,
  1114  				},
  1115  			},
  1116  		},
  1117  		{
  1118  			name: "error out if server-generated id is not returned",
  1119  			dclObj: &dclunstruct.Resource{
  1120  				STV: stv_baz,
  1121  				Object: map[string]interface{}{
  1122  					"project": projectID,
  1123  				},
  1124  			},
  1125  			hasError: true,
  1126  		},
  1127  		{
  1128  			name: "resource with no name field",
  1129  			krmObj: &unstructured.Unstructured{
  1130  				Object: map[string]interface{}{
  1131  					"kind":       "Test2NoName",
  1132  					"apiVersion": "test2.cnrm.cloud.google.com/v1alpha1",
  1133  					"metadata": map[string]interface{}{
  1134  						"name":      "foo-example",
  1135  						"namespace": "test-system",
  1136  						"annotations": map[string]interface{}{
  1137  							"cnrm.cloud.google.com/project-id": projectID,
  1138  						},
  1139  					},
  1140  					"spec": map[string]interface{}{},
  1141  				},
  1142  			},
  1143  			dclObj: &dclunstruct.Resource{
  1144  				STV: stv_noname,
  1145  				Object: map[string]interface{}{
  1146  					"project": projectID,
  1147  				},
  1148  			},
  1149  		},
  1150  		{
  1151  			name: "primitive fields",
  1152  			krmObj: &unstructured.Unstructured{
  1153  				Object: map[string]interface{}{
  1154  					"kind":       kind,
  1155  					"apiVersion": apiVersion,
  1156  					"metadata": map[string]interface{}{
  1157  						"name":      "foo-example",
  1158  						"namespace": "test-system",
  1159  						"annotations": map[string]interface{}{
  1160  							"cnrm.cloud.google.com/project-id": projectID,
  1161  						},
  1162  					},
  1163  					"spec": map[string]interface{}{
  1164  						"intKey":     1,
  1165  						"numberKey":  0.5,
  1166  						"booleanKey": true,
  1167  						"stringKey":  "StringVal",
  1168  						"resourceID": "CustomizedName",
  1169  					},
  1170  				},
  1171  			},
  1172  			dclObj: &dclunstruct.Resource{
  1173  				STV: stv_foo,
  1174  				Object: map[string]interface{}{
  1175  					"intKey":     1,
  1176  					"numberKey":  0.5,
  1177  					"booleanKey": true,
  1178  					"stringKey":  "StringVal",
  1179  					"name":       "CustomizedName",
  1180  					"project":    projectID,
  1181  				},
  1182  			},
  1183  		},
  1184  		{
  1185  			name: "list of primitives",
  1186  			krmObj: &unstructured.Unstructured{
  1187  				Object: map[string]interface{}{
  1188  					"kind":       kind,
  1189  					"apiVersion": apiVersion,
  1190  					"metadata": map[string]interface{}{
  1191  						"name":      "foo-example",
  1192  						"namespace": "test-system",
  1193  						"annotations": map[string]interface{}{
  1194  							"cnrm.cloud.google.com/project-id": projectID,
  1195  						},
  1196  					},
  1197  					"spec": map[string]interface{}{
  1198  						"primitiveArrayKey": []interface{}{
  1199  							"myString1",
  1200  							"myString2",
  1201  						},
  1202  						"resourceID": "foo-example",
  1203  					},
  1204  				},
  1205  			},
  1206  			dclObj: &dclunstruct.Resource{
  1207  				STV: stv_foo,
  1208  				Object: map[string]interface{}{
  1209  					"primitiveArrayKey": []interface{}{
  1210  						"myString1",
  1211  						"myString2",
  1212  					},
  1213  					"name":    "foo-example",
  1214  					"project": projectID,
  1215  				},
  1216  			},
  1217  		},
  1218  		{
  1219  			name: "nested object",
  1220  			krmObj: &unstructured.Unstructured{
  1221  				Object: map[string]interface{}{
  1222  					"kind":       kind,
  1223  					"apiVersion": apiVersion,
  1224  					"metadata": map[string]interface{}{
  1225  						"name":      "foo-example",
  1226  						"namespace": "test-system",
  1227  						"annotations": map[string]interface{}{
  1228  							"cnrm.cloud.google.com/project-id": projectID,
  1229  						},
  1230  					},
  1231  					"spec": map[string]interface{}{
  1232  						"nestedObjectKey": map[string]interface{}{
  1233  							"nestedField1": true,
  1234  							"nestedField2": "StringVal",
  1235  							"nestedReferenceFieldRef": map[string]interface{}{
  1236  								"external": "reference-url",
  1237  							},
  1238  							"nestedSensitiveField": map[string]interface{}{
  1239  								"value": "sensitive-data",
  1240  							},
  1241  						},
  1242  						"resourceID": "foo-example",
  1243  					},
  1244  				},
  1245  			},
  1246  			dclObj: &dclunstruct.Resource{
  1247  				STV: stv_foo,
  1248  				Object: map[string]interface{}{
  1249  					"nestedObjectKey": map[string]interface{}{
  1250  						"nestedField1":         true,
  1251  						"nestedField2":         "StringVal",
  1252  						"nestedReferenceField": "reference-url",
  1253  						"nestedSensitiveField": "sensitive-data",
  1254  					},
  1255  					"name":    "foo-example",
  1256  					"project": projectID,
  1257  				},
  1258  			},
  1259  		},
  1260  		{
  1261  			name: "list of objects",
  1262  			krmObj: &unstructured.Unstructured{
  1263  				Object: map[string]interface{}{
  1264  					"kind":       kind,
  1265  					"apiVersion": apiVersion,
  1266  					"metadata": map[string]interface{}{
  1267  						"name":      "foo-example",
  1268  						"namespace": "test-system",
  1269  						"annotations": map[string]interface{}{
  1270  							"cnrm.cloud.google.com/project-id": projectID,
  1271  						},
  1272  					},
  1273  					"spec": map[string]interface{}{
  1274  						"intKey":     1,
  1275  						"numberKey":  0.5,
  1276  						"booleanKey": true,
  1277  						"stringKey":  "StringVal",
  1278  						"objectArrayKey": []interface{}{
  1279  							map[string]interface{}{
  1280  								"field1": 1,
  1281  								"field2": "item1",
  1282  								// Read-only fields are surfaced onto the spec
  1283  								// if they're part of objects within
  1284  								// collections (maps, arrays)
  1285  								"readOnlyField": "running",
  1286  								// Read-only sensitive and reference fields are
  1287  								// surfaced onto the spec if they're part of
  1288  								// objects within collections (maps, arrays)
  1289  								// and simply srufaced as strings rather than
  1290  								// sensitive or reference structs.
  1291  								"readOnlySensitiveField": "sensitiveVal",
  1292  								"readOnlyReferenceField": "referenceVal",
  1293  							},
  1294  							map[string]interface{}{
  1295  								"field1":        2,
  1296  								"field2":        "item2",
  1297  								"readOnlyField": "suspended",
  1298  							},
  1299  						},
  1300  						"resourceID": "CustomizedName",
  1301  					},
  1302  				},
  1303  			},
  1304  			dclObj: &dclunstruct.Resource{
  1305  				STV: stv_foo,
  1306  				Object: map[string]interface{}{
  1307  					"intKey":     1,
  1308  					"numberKey":  0.5,
  1309  					"booleanKey": true,
  1310  					"stringKey":  "StringVal",
  1311  					"objectArrayKey": []interface{}{
  1312  						map[string]interface{}{
  1313  							"field1":                 1,
  1314  							"field2":                 "item1",
  1315  							"readOnlyField":          "running",
  1316  							"readOnlySensitiveField": "sensitiveVal",
  1317  							"readOnlyReferenceField": "referenceVal",
  1318  						},
  1319  						map[string]interface{}{
  1320  							"field1":        2,
  1321  							"field2":        "item2",
  1322  							"readOnlyField": "suspended",
  1323  						},
  1324  					},
  1325  					"name":    "CustomizedName",
  1326  					"project": projectID,
  1327  				},
  1328  			},
  1329  		},
  1330  		{
  1331  			name: "sensitive field",
  1332  			krmObj: &unstructured.Unstructured{
  1333  				Object: map[string]interface{}{
  1334  					"kind":       kind,
  1335  					"apiVersion": apiVersion,
  1336  					"metadata": map[string]interface{}{
  1337  						"name":      "foo-example",
  1338  						"namespace": "test-system",
  1339  						"annotations": map[string]interface{}{
  1340  							"cnrm.cloud.google.com/project-id": projectID,
  1341  						},
  1342  					},
  1343  					"spec": map[string]interface{}{
  1344  						"sensitiveFieldKey": map[string]interface{}{
  1345  							"value": "sensitive-data",
  1346  						},
  1347  						"resourceID": "CustomizedName",
  1348  					},
  1349  				},
  1350  			},
  1351  			dclObj: &dclunstruct.Resource{
  1352  				STV: stv_foo,
  1353  				Object: map[string]interface{}{
  1354  					"sensitiveFieldKey": "sensitive-data",
  1355  					"name":              "CustomizedName",
  1356  					"project":           projectID,
  1357  				},
  1358  			},
  1359  		},
  1360  		{
  1361  			name: "single-kind reference field",
  1362  			krmObj: &unstructured.Unstructured{
  1363  				Object: map[string]interface{}{
  1364  					"kind":       kind,
  1365  					"apiVersion": apiVersion,
  1366  					"metadata": map[string]interface{}{
  1367  						"name":      "foo-example",
  1368  						"namespace": "test-system",
  1369  						"annotations": map[string]interface{}{
  1370  							"cnrm.cloud.google.com/project-id": projectID,
  1371  						},
  1372  					},
  1373  					"spec": map[string]interface{}{
  1374  						"referenceKeyRef": map[string]interface{}{
  1375  							"external": "my-ref",
  1376  						},
  1377  						"resourceID": "CustomizedName",
  1378  					},
  1379  				},
  1380  			},
  1381  			dclObj: &dclunstruct.Resource{
  1382  				STV: stv_foo,
  1383  				Object: map[string]interface{}{
  1384  					"referenceKey": "my-ref",
  1385  					"name":         "CustomizedName",
  1386  					"project":      projectID,
  1387  				},
  1388  			},
  1389  		},
  1390  		{
  1391  			name: "multi-kind reference field",
  1392  			krmObj: &unstructured.Unstructured{
  1393  				Object: map[string]interface{}{
  1394  					"kind":       kind,
  1395  					"apiVersion": apiVersion,
  1396  					"metadata": map[string]interface{}{
  1397  						"name":      "foo-example",
  1398  						"namespace": "test-system",
  1399  						"annotations": map[string]interface{}{
  1400  							"cnrm.cloud.google.com/project-id": projectID,
  1401  						},
  1402  					},
  1403  					"spec": map[string]interface{}{
  1404  						"complexReferenceKeyRef": map[string]interface{}{
  1405  							"external": "my-ref",
  1406  						},
  1407  						"resourceID": "CustomizedName",
  1408  					},
  1409  				},
  1410  			},
  1411  			dclObj: &dclunstruct.Resource{
  1412  				STV: stv_foo,
  1413  				Object: map[string]interface{}{
  1414  					"complexReferenceKey": "my-ref",
  1415  					"name":                "CustomizedName",
  1416  					"project":             projectID,
  1417  				},
  1418  			},
  1419  		},
  1420  		{
  1421  			name: "a list of references",
  1422  			krmObj: &unstructured.Unstructured{
  1423  				Object: map[string]interface{}{
  1424  					"kind":       kind,
  1425  					"apiVersion": apiVersion,
  1426  					"metadata": map[string]interface{}{
  1427  						"name":      "foo-example",
  1428  						"namespace": "test-system",
  1429  						"annotations": map[string]interface{}{
  1430  							"cnrm.cloud.google.com/project-id": projectID,
  1431  						},
  1432  					},
  1433  					"spec": map[string]interface{}{
  1434  						"referenceArrayKey": []interface{}{
  1435  							map[string]interface{}{
  1436  								"external": "my-ref-1",
  1437  							},
  1438  							map[string]interface{}{
  1439  								"external": "my-ref-2",
  1440  							},
  1441  						},
  1442  						"resourceID": "CustomizedName",
  1443  					},
  1444  				},
  1445  			},
  1446  			dclObj: &dclunstruct.Resource{
  1447  				STV: stv_foo,
  1448  				Object: map[string]interface{}{
  1449  					"referenceArrayKey": []interface{}{
  1450  						"my-ref-1",
  1451  						"my-ref-2",
  1452  					},
  1453  					"name":    "CustomizedName",
  1454  					"project": projectID,
  1455  				},
  1456  			},
  1457  		},
  1458  		{
  1459  			name: "string-object map",
  1460  			krmObj: &unstructured.Unstructured{
  1461  				Object: map[string]interface{}{
  1462  					"kind":       kind,
  1463  					"apiVersion": apiVersion,
  1464  					"metadata": map[string]interface{}{
  1465  						"name":      "foo-example",
  1466  						"namespace": "test-system",
  1467  						"annotations": map[string]interface{}{
  1468  							"cnrm.cloud.google.com/project-id": projectID,
  1469  						},
  1470  					},
  1471  					"spec": map[string]interface{}{
  1472  						"stringObjectMapKey": map[string]interface{}{
  1473  							"someKey": map[string]interface{}{
  1474  								"objectField1": 1.0,
  1475  								"objectReferenceArrayKey": []interface{}{
  1476  									map[string]interface{}{
  1477  										"external": "my-ref-1",
  1478  									},
  1479  									map[string]interface{}{
  1480  										"external": "my-ref-2",
  1481  									},
  1482  								},
  1483  								// Read-only fields are surfaced onto the spec
  1484  								// if they're part of objects within
  1485  								// collections (maps, arrays)
  1486  								"readOnlyField": "running",
  1487  								// Read-only sensitive and reference fields are
  1488  								// surfaced onto the spec if they're part of
  1489  								// objects within collections (maps, arrays)
  1490  								// and simply srufaced as strings rather than
  1491  								// sensitive or reference structs.
  1492  								"readOnlySensitiveField": "sensitiveVal",
  1493  								"readOnlyReferenceField": "referenceVal",
  1494  							},
  1495  							"someOtherKey": map[string]interface{}{
  1496  								"objectField1": 2.0,
  1497  								"objectReferenceArrayKey": []interface{}{
  1498  									map[string]interface{}{
  1499  										"external": "my-ref-3",
  1500  									},
  1501  									map[string]interface{}{
  1502  										"external": "my-ref-4",
  1503  									},
  1504  								},
  1505  								"readOnlyField": "val2",
  1506  							},
  1507  						},
  1508  						"resourceID": "foo-example",
  1509  					},
  1510  				},
  1511  			},
  1512  			dclObj: &dclunstruct.Resource{
  1513  				STV: stv_foo,
  1514  				Object: map[string]interface{}{
  1515  					"stringObjectMapKey": map[string]interface{}{
  1516  						"someKey": map[string]interface{}{
  1517  							"objectField1": 1.0,
  1518  							"objectReferenceArrayKey": []interface{}{
  1519  								"my-ref-1",
  1520  								"my-ref-2",
  1521  							},
  1522  							"readOnlyField":          "running",
  1523  							"readOnlySensitiveField": "sensitiveVal",
  1524  							"readOnlyReferenceField": "referenceVal",
  1525  						},
  1526  						"someOtherKey": map[string]interface{}{
  1527  							"objectField1": 2.0,
  1528  							"objectReferenceArrayKey": []interface{}{
  1529  								"my-ref-3",
  1530  								"my-ref-4",
  1531  							},
  1532  							"readOnlyField": "val2",
  1533  						},
  1534  					},
  1535  					"name":    "foo-example",
  1536  					"project": projectID,
  1537  				},
  1538  			},
  1539  		},
  1540  	}
  1541  	for _, tc := range tests {
  1542  		tc := tc
  1543  		t.Run(tc.name, func(t *testing.T) {
  1544  			t.Parallel()
  1545  			krmObj, err := converter.DCLObjectToKRMObject(tc.dclObj)
  1546  			if tc.hasError {
  1547  				if err == nil {
  1548  					t.Fatalf("expected to get error when converting DCL TO KRM")
  1549  				}
  1550  				return
  1551  			}
  1552  			if err != nil {
  1553  				t.Fatalf("unexpected error: %v", err)
  1554  			}
  1555  			compareUnstructuredObjects(t, krmObj, tc.krmObj)
  1556  		})
  1557  	}
  1558  }
  1559  
  1560  func TestConverter_DCLObjectToKRMObjectForHierarchicalReferences(t *testing.T) {
  1561  	tests := []struct {
  1562  		name     string
  1563  		schema   *openapi.Schema
  1564  		dclObj   *dclunstruct.Resource
  1565  		krmObj   *unstructured.Unstructured
  1566  		hasError bool
  1567  	}{
  1568  		{
  1569  			name: "single-parent resource",
  1570  			schema: &openapi.Schema{
  1571  				Type: "object",
  1572  				Properties: map[string]*openapi.Schema{
  1573  					"project": &openapi.Schema{
  1574  						Type: "string",
  1575  						Extension: map[string]interface{}{
  1576  							"x-dcl-references": []interface{}{
  1577  								map[interface{}]interface{}{
  1578  									"field":    "name",
  1579  									"parent":   true,
  1580  									"resource": "Cloudresourcemanager/Project",
  1581  								},
  1582  							},
  1583  						},
  1584  					},
  1585  				},
  1586  			},
  1587  			dclObj: &dclunstruct.Resource{
  1588  				STV: dclunstruct.ServiceTypeVersion{
  1589  					Service: "test5",
  1590  					Type:    "ProjectRef",
  1591  					Version: "beta",
  1592  				},
  1593  				Object: map[string]interface{}{
  1594  					"project": "project_id",
  1595  				},
  1596  			},
  1597  			krmObj: &unstructured.Unstructured{
  1598  				Object: map[string]interface{}{
  1599  					"kind":       "Test5ProjectRef",
  1600  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1601  					"spec": map[string]interface{}{
  1602  						"projectRef": map[string]interface{}{
  1603  							"external": "project_id",
  1604  						},
  1605  					},
  1606  				},
  1607  			},
  1608  		},
  1609  		{
  1610  			name: "multi-parent resource with project parent",
  1611  			schema: &openapi.Schema{
  1612  				Type: "object",
  1613  				Properties: map[string]*openapi.Schema{
  1614  					"parent": &openapi.Schema{
  1615  						Type: "string",
  1616  						Extension: map[string]interface{}{
  1617  							"x-dcl-references": []interface{}{
  1618  								map[interface{}]interface{}{
  1619  									"field":    "name",
  1620  									"parent":   true,
  1621  									"resource": "Cloudresourcemanager/Project",
  1622  								},
  1623  								map[interface{}]interface{}{
  1624  									"field":    "name",
  1625  									"parent":   true,
  1626  									"resource": "Cloudresourcemanager/Folder",
  1627  								},
  1628  								map[interface{}]interface{}{
  1629  									"field":    "name",
  1630  									"parent":   true,
  1631  									"resource": "Cloudresourcemanager/Organization",
  1632  								},
  1633  							},
  1634  						},
  1635  					},
  1636  				},
  1637  			},
  1638  			dclObj: &dclunstruct.Resource{
  1639  				STV: dclunstruct.ServiceTypeVersion{
  1640  					Service: "test5",
  1641  					Type:    "MultipleRefs",
  1642  					Version: "beta",
  1643  				},
  1644  				Object: map[string]interface{}{
  1645  					"parent": "projects/project_id",
  1646  				},
  1647  			},
  1648  			krmObj: &unstructured.Unstructured{
  1649  				Object: map[string]interface{}{
  1650  					"kind":       "Test5MultipleRefs",
  1651  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1652  					"spec": map[string]interface{}{
  1653  						"projectRef": map[string]interface{}{
  1654  							"external": "projects/project_id",
  1655  						},
  1656  					},
  1657  				},
  1658  			},
  1659  		},
  1660  		{
  1661  			name: "multi-parent resource with folder parent",
  1662  			schema: &openapi.Schema{
  1663  				Type: "object",
  1664  				Properties: map[string]*openapi.Schema{
  1665  					"parent": &openapi.Schema{
  1666  						Type: "string",
  1667  						Extension: map[string]interface{}{
  1668  							"x-dcl-references": []interface{}{
  1669  								map[interface{}]interface{}{
  1670  									"field":    "name",
  1671  									"parent":   true,
  1672  									"resource": "Cloudresourcemanager/Project",
  1673  								},
  1674  								map[interface{}]interface{}{
  1675  									"field":    "name",
  1676  									"parent":   true,
  1677  									"resource": "Cloudresourcemanager/Folder",
  1678  								},
  1679  								map[interface{}]interface{}{
  1680  									"field":    "name",
  1681  									"parent":   true,
  1682  									"resource": "Cloudresourcemanager/Organization",
  1683  								},
  1684  							},
  1685  						},
  1686  					},
  1687  				},
  1688  			},
  1689  			dclObj: &dclunstruct.Resource{
  1690  				STV: dclunstruct.ServiceTypeVersion{
  1691  					Service: "test5",
  1692  					Type:    "MultipleRefs",
  1693  					Version: "beta",
  1694  				},
  1695  				Object: map[string]interface{}{
  1696  					"parent": "folders/folder_id",
  1697  				},
  1698  			},
  1699  			krmObj: &unstructured.Unstructured{
  1700  				Object: map[string]interface{}{
  1701  					"kind":       "Test5MultipleRefs",
  1702  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1703  					"spec": map[string]interface{}{
  1704  						"folderRef": map[string]interface{}{
  1705  							"external": "folders/folder_id",
  1706  						},
  1707  					},
  1708  				},
  1709  			},
  1710  		},
  1711  		{
  1712  			name: "multi-parent resource with organization parent",
  1713  			schema: &openapi.Schema{
  1714  				Type: "object",
  1715  				Properties: map[string]*openapi.Schema{
  1716  					"parent": &openapi.Schema{
  1717  						Type: "string",
  1718  						Extension: map[string]interface{}{
  1719  							"x-dcl-references": []interface{}{
  1720  								map[interface{}]interface{}{
  1721  									"field":    "name",
  1722  									"parent":   true,
  1723  									"resource": "Cloudresourcemanager/Project",
  1724  								},
  1725  								map[interface{}]interface{}{
  1726  									"field":    "name",
  1727  									"parent":   true,
  1728  									"resource": "Cloudresourcemanager/Folder",
  1729  								},
  1730  								map[interface{}]interface{}{
  1731  									"field":    "name",
  1732  									"parent":   true,
  1733  									"resource": "Cloudresourcemanager/Organization",
  1734  								},
  1735  							},
  1736  						},
  1737  					},
  1738  				},
  1739  			},
  1740  			dclObj: &dclunstruct.Resource{
  1741  				STV: dclunstruct.ServiceTypeVersion{
  1742  					Service: "test5",
  1743  					Type:    "MultipleRefs",
  1744  					Version: "beta",
  1745  				},
  1746  				Object: map[string]interface{}{
  1747  					"parent": "organizations/organization_id",
  1748  				},
  1749  			},
  1750  			krmObj: &unstructured.Unstructured{
  1751  				Object: map[string]interface{}{
  1752  					"kind":       "Test5MultipleRefs",
  1753  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1754  					"spec": map[string]interface{}{
  1755  						"organizationRef": map[string]interface{}{
  1756  							"external": "organizations/organization_id",
  1757  						},
  1758  					},
  1759  				},
  1760  			},
  1761  		},
  1762  		{
  1763  			name: "multi-parent resource with billing account parent",
  1764  			schema: &openapi.Schema{
  1765  				Type: "object",
  1766  				Properties: map[string]*openapi.Schema{
  1767  					"parent": &openapi.Schema{
  1768  						Type: "string",
  1769  						Extension: map[string]interface{}{
  1770  							"x-dcl-references": []interface{}{
  1771  								map[interface{}]interface{}{
  1772  									"field":    "name",
  1773  									"parent":   true,
  1774  									"resource": "Cloudresourcemanager/Project",
  1775  								},
  1776  								map[interface{}]interface{}{
  1777  									"field":    "name",
  1778  									"parent":   true,
  1779  									"resource": "Cloudresourcemanager/Folder",
  1780  								},
  1781  								map[interface{}]interface{}{
  1782  									"field":    "name",
  1783  									"parent":   true,
  1784  									"resource": "Cloudresourcemanager/Organization",
  1785  								},
  1786  								map[interface{}]interface{}{
  1787  									"field":    "name",
  1788  									"parent":   true,
  1789  									"resource": "Cloudresourcemanager/BillingAccount",
  1790  								},
  1791  							},
  1792  						},
  1793  					},
  1794  				},
  1795  			},
  1796  			dclObj: &dclunstruct.Resource{
  1797  				STV: dclunstruct.ServiceTypeVersion{
  1798  					Service: "test5",
  1799  					Type:    "MultipleRefs",
  1800  					Version: "beta",
  1801  				},
  1802  				Object: map[string]interface{}{
  1803  					"parent": "billingAccounts/billing_account_id",
  1804  				},
  1805  			},
  1806  			krmObj: &unstructured.Unstructured{
  1807  				Object: map[string]interface{}{
  1808  					"kind":       "Test5MultipleRefs",
  1809  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1810  					"spec": map[string]interface{}{
  1811  						"billingAccountRef": map[string]interface{}{
  1812  							"external": "billingAccounts/billing_account_id",
  1813  						},
  1814  					},
  1815  				},
  1816  			},
  1817  		},
  1818  		{
  1819  			name: "multi-parent resource with empty parent",
  1820  			schema: &openapi.Schema{
  1821  				Type: "object",
  1822  				Properties: map[string]*openapi.Schema{
  1823  					"parent": &openapi.Schema{
  1824  						Type: "string",
  1825  						Extension: map[string]interface{}{
  1826  							"x-dcl-references": []interface{}{
  1827  								map[interface{}]interface{}{
  1828  									"field":    "name",
  1829  									"parent":   true,
  1830  									"resource": "Cloudresourcemanager/Project",
  1831  								},
  1832  								map[interface{}]interface{}{
  1833  									"field":    "name",
  1834  									"parent":   true,
  1835  									"resource": "Cloudresourcemanager/Folder",
  1836  								},
  1837  								map[interface{}]interface{}{
  1838  									"field":    "name",
  1839  									"parent":   true,
  1840  									"resource": "Cloudresourcemanager/Organization",
  1841  								},
  1842  							},
  1843  						},
  1844  					},
  1845  				},
  1846  			},
  1847  			dclObj: &dclunstruct.Resource{
  1848  				STV: dclunstruct.ServiceTypeVersion{
  1849  					Service: "test5",
  1850  					Type:    "MultipleRefs",
  1851  					Version: "beta",
  1852  				},
  1853  				Object: map[string]interface{}{
  1854  					"parent": "",
  1855  				},
  1856  			},
  1857  			krmObj: &unstructured.Unstructured{
  1858  				Object: map[string]interface{}{
  1859  					"kind":       "Test5MultipleRefs",
  1860  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1861  				},
  1862  			},
  1863  			hasError: true,
  1864  		},
  1865  		{
  1866  			name: "multi-parent resource with unrecognized parent",
  1867  			schema: &openapi.Schema{
  1868  				Type: "object",
  1869  				Properties: map[string]*openapi.Schema{
  1870  					"parent": &openapi.Schema{
  1871  						Type: "string",
  1872  						Extension: map[string]interface{}{
  1873  							"x-dcl-references": []interface{}{
  1874  								map[interface{}]interface{}{
  1875  									"field":    "name",
  1876  									"parent":   true,
  1877  									"resource": "Cloudresourcemanager/Project",
  1878  								},
  1879  								map[interface{}]interface{}{
  1880  									"field":    "name",
  1881  									"parent":   true,
  1882  									"resource": "Cloudresourcemanager/Folder",
  1883  								},
  1884  								map[interface{}]interface{}{
  1885  									"field":    "name",
  1886  									"parent":   true,
  1887  									"resource": "Cloudresourcemanager/Organization",
  1888  								},
  1889  							},
  1890  						},
  1891  					},
  1892  				},
  1893  			},
  1894  			dclObj: &dclunstruct.Resource{
  1895  				STV: dclunstruct.ServiceTypeVersion{
  1896  					Service: "test5",
  1897  					Type:    "MultipleRefs",
  1898  					Version: "beta",
  1899  				},
  1900  				Object: map[string]interface{}{
  1901  					"parent": "val_with_no_known_parent_prefix",
  1902  				},
  1903  			},
  1904  			krmObj: &unstructured.Unstructured{
  1905  				Object: map[string]interface{}{
  1906  					"kind":       "Test5MultipleRefs",
  1907  					"apiVersion": "test5.cnrm.cloud.google.com/v1alpha1",
  1908  				},
  1909  			},
  1910  			hasError: true,
  1911  		},
  1912  	}
  1913  
  1914  	smLoader := dclmetadata.NewFromServiceList(testservicemetadataloader.FakeServiceMetadataWithHierarchicalResources())
  1915  	for _, tc := range tests {
  1916  		tc := tc
  1917  		t.Run(tc.name, func(t *testing.T) {
  1918  			t.Parallel()
  1919  			schemaKey := testdclschemaloader.DCLSchemaKeyForGVK(t, tc.krmObj.GroupVersionKind(), smLoader)
  1920  			schemaMap := map[string]*openapi.Schema{
  1921  				schemaKey: tc.schema,
  1922  			}
  1923  			schemaLoader := testdclschemaloader.New(schemaMap)
  1924  			converter := conversion.New(schemaLoader, smLoader)
  1925  
  1926  			krmObj, err := converter.DCLObjectToKRMObject(tc.dclObj)
  1927  			if tc.hasError {
  1928  				if err == nil {
  1929  					t.Fatalf("got no error, but wanted one")
  1930  				}
  1931  				return
  1932  			}
  1933  			if err != nil {
  1934  				t.Fatalf("got error, but wanted none: %v", err)
  1935  			}
  1936  			compareUnstructuredObjects(t, krmObj, tc.krmObj)
  1937  		})
  1938  	}
  1939  }
  1940  
  1941  func TestLabelsConversion(t *testing.T) {
  1942  	schemaLoader := testdclschemaloader.New(dclSchemaMap)
  1943  	smLoader := testservicemetadataloader.NewForUnitTest()
  1944  	converter := conversion.New(schemaLoader, smLoader)
  1945  	kind := "Test1Bar"
  1946  	apiVersion := "test1.cnrm.cloud.google.com/v1alpha1"
  1947  	projectID := "dcl-test"
  1948  	tests := []struct {
  1949  		name   string
  1950  		krmObj *unstructured.Unstructured
  1951  		dclObj *dclunstruct.Resource
  1952  	}{
  1953  		{
  1954  			name: "system label 'managed-by-cnrm' is added",
  1955  			krmObj: &unstructured.Unstructured{
  1956  				Object: map[string]interface{}{
  1957  					"kind":       kind,
  1958  					"apiVersion": apiVersion,
  1959  					"metadata": map[string]interface{}{
  1960  						"name": "foo-example",
  1961  						"labels": map[string]interface{}{
  1962  							"key1": "val1",
  1963  							"key2": "val2",
  1964  						},
  1965  						"namespace": "test-system",
  1966  						"annotations": map[string]interface{}{
  1967  							"cnrm.cloud.google.com/project-id": projectID,
  1968  						},
  1969  					},
  1970  					"spec": map[string]interface{}{
  1971  						"resourceID": "CustomizedName",
  1972  					},
  1973  				},
  1974  			},
  1975  			dclObj: &dclunstruct.Resource{
  1976  				STV: stv_bar,
  1977  				Object: map[string]interface{}{
  1978  					"labels": map[string]interface{}{
  1979  						"key1":            "val1",
  1980  						"key2":            "val2",
  1981  						"managed-by-cnrm": "true",
  1982  					},
  1983  					"project": projectID,
  1984  					"name":    "CustomizedName",
  1985  				},
  1986  			},
  1987  		},
  1988  		{
  1989  			name: "k8s style labels are trimmed",
  1990  			krmObj: &unstructured.Unstructured{
  1991  				Object: map[string]interface{}{
  1992  					"kind":       kind,
  1993  					"apiVersion": apiVersion,
  1994  					"metadata": map[string]interface{}{
  1995  						"name": "foo-example",
  1996  						"labels": map[string]interface{}{
  1997  							"key1":                 "val1",
  1998  							"key2":                 "val2",
  1999  							"k8s.test.io/some-key": "some-value",
  2000  						},
  2001  						"namespace": "test-system",
  2002  						"annotations": map[string]interface{}{
  2003  							"cnrm.cloud.google.com/project-id": projectID,
  2004  						},
  2005  					},
  2006  					"spec": map[string]interface{}{
  2007  						"resourceID": "CustomizedName",
  2008  					},
  2009  				},
  2010  			},
  2011  			dclObj: &dclunstruct.Resource{
  2012  				STV: stv_bar,
  2013  				Object: map[string]interface{}{
  2014  					"labels": map[string]interface{}{
  2015  						"key1":            "val1",
  2016  						"key2":            "val2",
  2017  						"managed-by-cnrm": "true",
  2018  					},
  2019  					"project": projectID,
  2020  					"name":    "CustomizedName",
  2021  				},
  2022  			},
  2023  		},
  2024  		{
  2025  			name: "without labels extension metadata labels will not be converted to dcl labels field",
  2026  			krmObj: &unstructured.Unstructured{
  2027  				Object: map[string]interface{}{
  2028  					"kind":       "Test1NoLabelsExtension",
  2029  					"apiVersion": apiVersion,
  2030  					"metadata": map[string]interface{}{
  2031  						"name": "foo-example",
  2032  						"labels": map[string]interface{}{
  2033  							"key1":                 "val1",
  2034  							"key2":                 "val2",
  2035  							"k8s.test.io/some-key": "some-value",
  2036  						},
  2037  						"namespace": "test-system",
  2038  						"annotations": map[string]interface{}{
  2039  							"cnrm.cloud.google.com/project-id": projectID,
  2040  						},
  2041  					},
  2042  					"spec": map[string]interface{}{
  2043  						"resourceID": "CustomizedName",
  2044  					},
  2045  				},
  2046  			},
  2047  			dclObj: &dclunstruct.Resource{
  2048  				STV: stv_nolabelsextension,
  2049  				Object: map[string]interface{}{
  2050  					"project": projectID,
  2051  					"name":    "CustomizedName",
  2052  				},
  2053  			},
  2054  		},
  2055  		{
  2056  			name: "without labels extension dcl labels will not be converted to metadata labels",
  2057  			krmObj: &unstructured.Unstructured{
  2058  				Object: map[string]interface{}{
  2059  					"kind":       "Test1NoLabelsExtension",
  2060  					"apiVersion": apiVersion,
  2061  					"metadata": map[string]interface{}{
  2062  						"name":      "foo-example",
  2063  						"labels":    map[string]interface{}{},
  2064  						"namespace": "test-system",
  2065  						"annotations": map[string]interface{}{
  2066  							"cnrm.cloud.google.com/project-id": projectID,
  2067  						},
  2068  					},
  2069  					"spec": map[string]interface{}{
  2070  						"resourceID": "CustomizedName",
  2071  						"labels": map[string]interface{}{
  2072  							"key1": "val1",
  2073  							"key2": "val2",
  2074  						},
  2075  					},
  2076  				},
  2077  			},
  2078  			dclObj: &dclunstruct.Resource{
  2079  				STV: stv_nolabelsextension,
  2080  				Object: map[string]interface{}{
  2081  					"project": projectID,
  2082  					"name":    "CustomizedName",
  2083  					"labels": map[string]interface{}{
  2084  						"key1": "val1",
  2085  						"key2": "val2",
  2086  					},
  2087  				},
  2088  			},
  2089  		},
  2090  	}
  2091  	for _, tc := range tests {
  2092  		tc := tc
  2093  		t.Run(tc.name, func(t *testing.T) {
  2094  			t.Parallel()
  2095  			dclObj, err := converter.KRMObjectToDCLObject(tc.krmObj)
  2096  			if err != nil {
  2097  				t.Fatalf("unexpected error: %v", err)
  2098  			}
  2099  			if !reflect.DeepEqual(dclObj, tc.dclObj) {
  2100  				t.Fatalf("unexpected diff (-want +got): \n%v", cmp.Diff(tc.dclObj, dclObj))
  2101  			}
  2102  			krmObj, err := converter.DCLObjectToKRMObject(tc.dclObj)
  2103  			if err != nil {
  2104  				t.Fatalf("unexpected error: %v", err)
  2105  			}
  2106  			dclSchema, err := converter.SchemaLoader.GetDCLSchema(dclObj.STV)
  2107  			if err != nil {
  2108  				t.Fatalf("unexpected error: %v", err)
  2109  			}
  2110  			labelsField := dclSchema.Extension[constants.DCL_LABELS_FIELD]
  2111  			want := interface{}(nil)
  2112  			if labelsField != nil {
  2113  				want = tc.dclObj.Object[labelsField.(string)].(map[string]interface{})
  2114  			}
  2115  			got := krmObj.Object["metadata"].(map[string]interface{})["labels"]
  2116  			if !reflect.DeepEqual(got, want) {
  2117  				t.Fatalf("unexpected labels diff (-want +got): \n%v", cmp.Diff(want, got))
  2118  			}
  2119  		})
  2120  	}
  2121  }
  2122  
  2123  func TestConverter_DCLObjectToKRMObject_WithStatus(t *testing.T) {
  2124  	schemaLoader := testdclschemaloader.New(dclSchemaMap)
  2125  	smLoader := testservicemetadataloader.NewForUnitTest()
  2126  	converter := conversion.New(schemaLoader, smLoader)
  2127  	kind := "Test1Foo"
  2128  	apiVersion := "test1.cnrm.cloud.google.com/v1alpha1"
  2129  	projectID := "dcl-test"
  2130  	tests := []struct {
  2131  		name   string
  2132  		krmObj *unstructured.Unstructured
  2133  		dclObj *dclunstruct.Resource
  2134  	}{
  2135  		{
  2136  			name: "primitive fields",
  2137  			krmObj: &unstructured.Unstructured{
  2138  				Object: map[string]interface{}{
  2139  					"kind":       kind,
  2140  					"apiVersion": apiVersion,
  2141  					"metadata": map[string]interface{}{
  2142  						"annotations": map[string]interface{}{
  2143  							"cnrm.cloud.google.com/project-id": projectID,
  2144  						},
  2145  					},
  2146  					"spec": map[string]interface{}{
  2147  						"intKey":     1,
  2148  						"numberKey":  0.5,
  2149  						"booleanKey": true,
  2150  						"stringKey":  "StringVal",
  2151  						"resourceID": "CustomizedName",
  2152  					},
  2153  					"status": map[string]interface{}{
  2154  						"statusField": "message",
  2155  					},
  2156  				},
  2157  			},
  2158  			dclObj: &dclunstruct.Resource{
  2159  				STV: stv_foo,
  2160  				Object: map[string]interface{}{
  2161  					"intKey":      1,
  2162  					"numberKey":   0.5,
  2163  					"booleanKey":  true,
  2164  					"stringKey":   "StringVal",
  2165  					"name":        "CustomizedName",
  2166  					"project":     projectID,
  2167  					"statusField": "message",
  2168  				},
  2169  			},
  2170  		},
  2171  		{
  2172  			name: "nested status fields",
  2173  			krmObj: &unstructured.Unstructured{
  2174  				Object: map[string]interface{}{
  2175  					"kind":       kind,
  2176  					"apiVersion": apiVersion,
  2177  					"metadata": map[string]interface{}{
  2178  						"annotations": map[string]interface{}{
  2179  							"cnrm.cloud.google.com/project-id": projectID,
  2180  						},
  2181  					},
  2182  					"spec": map[string]interface{}{
  2183  						"intKey":     1,
  2184  						"numberKey":  0.5,
  2185  						"booleanKey": true,
  2186  						"stringKey":  "StringVal",
  2187  						"resourceID": "CustomizedName",
  2188  						"nestedObjectKey": map[string]interface{}{
  2189  							"nestedField1": true,
  2190  							"nestedField2": "StringVal",
  2191  						},
  2192  					},
  2193  					"status": map[string]interface{}{
  2194  						"statusField": "message",
  2195  						"nestedObjectKey": map[string]interface{}{
  2196  							"nestedStatusField":       "StringVal2",
  2197  							"nestedStatusArrayString": []interface{}{"status1, status2"},
  2198  						},
  2199  					},
  2200  				},
  2201  			},
  2202  			dclObj: &dclunstruct.Resource{
  2203  				STV: stv_foo,
  2204  				Object: map[string]interface{}{
  2205  					"intKey":      1,
  2206  					"numberKey":   0.5,
  2207  					"booleanKey":  true,
  2208  					"stringKey":   "StringVal",
  2209  					"name":        "CustomizedName",
  2210  					"project":     projectID,
  2211  					"statusField": "message",
  2212  					"nestedObjectKey": map[string]interface{}{
  2213  						"nestedField1":            true,
  2214  						"nestedField2":            "StringVal",
  2215  						"nestedStatusField":       "StringVal2",
  2216  						"nestedStatusArrayString": []interface{}{"status1, status2"},
  2217  					},
  2218  				},
  2219  			},
  2220  		},
  2221  		{
  2222  			name: "status array of primitives",
  2223  			krmObj: &unstructured.Unstructured{
  2224  				Object: map[string]interface{}{
  2225  					"kind":       kind,
  2226  					"apiVersion": apiVersion,
  2227  					"metadata": map[string]interface{}{
  2228  						"annotations": map[string]interface{}{
  2229  							"cnrm.cloud.google.com/project-id": projectID,
  2230  						},
  2231  					},
  2232  					"spec": map[string]interface{}{
  2233  						"intKey":     1,
  2234  						"numberKey":  0.5,
  2235  						"booleanKey": true,
  2236  						"stringKey":  "StringVal",
  2237  						"resourceID": "CustomizedName",
  2238  					},
  2239  					"status": map[string]interface{}{
  2240  						"statusField":          "message",
  2241  						"statusArrayPrimitive": []interface{}{"status1, status2"},
  2242  					},
  2243  				},
  2244  			},
  2245  			dclObj: &dclunstruct.Resource{
  2246  				STV: stv_foo,
  2247  				Object: map[string]interface{}{
  2248  					"intKey":               1,
  2249  					"numberKey":            0.5,
  2250  					"booleanKey":           true,
  2251  					"stringKey":            "StringVal",
  2252  					"name":                 "CustomizedName",
  2253  					"project":              projectID,
  2254  					"statusField":          "message",
  2255  					"statusArrayPrimitive": []interface{}{"status1, status2"},
  2256  				},
  2257  			},
  2258  		},
  2259  		{
  2260  			name: "status array of objects",
  2261  			krmObj: &unstructured.Unstructured{
  2262  				Object: map[string]interface{}{
  2263  					"kind":       kind,
  2264  					"apiVersion": apiVersion,
  2265  					"metadata": map[string]interface{}{
  2266  						"annotations": map[string]interface{}{
  2267  							"cnrm.cloud.google.com/project-id": projectID,
  2268  						},
  2269  					},
  2270  					"spec": map[string]interface{}{
  2271  						"intKey":     1,
  2272  						"numberKey":  0.5,
  2273  						"booleanKey": true,
  2274  						"stringKey":  "StringVal",
  2275  						"resourceID": "CustomizedName",
  2276  					},
  2277  					"status": map[string]interface{}{
  2278  						"statusField": "message",
  2279  						"statusArrayObject": []interface{}{
  2280  							map[string]interface{}{
  2281  								"nestedStatusField1": "status1Field1",
  2282  								"nestedStatusField2": "status1Field2",
  2283  							},
  2284  							map[string]interface{}{
  2285  								"nestedStatusField1": "status2Field1",
  2286  								"nestedStatusField2": "status2Field2",
  2287  							},
  2288  						},
  2289  					},
  2290  				},
  2291  			},
  2292  			dclObj: &dclunstruct.Resource{
  2293  				STV: stv_foo,
  2294  				Object: map[string]interface{}{
  2295  					"intKey":      1,
  2296  					"numberKey":   0.5,
  2297  					"booleanKey":  true,
  2298  					"stringKey":   "StringVal",
  2299  					"name":        "CustomizedName",
  2300  					"project":     projectID,
  2301  					"statusField": "message",
  2302  					"statusArrayObject": []interface{}{
  2303  						map[string]interface{}{
  2304  							"nestedStatusField1": "status1Field1",
  2305  							"nestedStatusField2": "status1Field2",
  2306  						},
  2307  						map[string]interface{}{
  2308  							"nestedStatusField1": "status2Field1",
  2309  							"nestedStatusField2": "status2Field2",
  2310  						},
  2311  					},
  2312  				},
  2313  			},
  2314  		},
  2315  		{
  2316  			name: "status string-object map",
  2317  			krmObj: &unstructured.Unstructured{
  2318  				Object: map[string]interface{}{
  2319  					"kind":       kind,
  2320  					"apiVersion": apiVersion,
  2321  					"metadata": map[string]interface{}{
  2322  						"annotations": map[string]interface{}{
  2323  							"cnrm.cloud.google.com/project-id": projectID,
  2324  						},
  2325  					},
  2326  					"spec": map[string]interface{}{
  2327  						"intKey":     1,
  2328  						"numberKey":  0.5,
  2329  						"booleanKey": true,
  2330  						"stringKey":  "StringVal",
  2331  						"resourceID": "CustomizedName",
  2332  					},
  2333  					"status": map[string]interface{}{
  2334  						"statusField": "message",
  2335  						"statusStringObjectMap": map[string]interface{}{
  2336  							"someKey": map[string]interface{}{
  2337  								"nestedStatusField1": true,
  2338  								"nestedStatusField2": "str1",
  2339  							},
  2340  							"someOtherKey": map[string]interface{}{
  2341  								"nestedStatusField1": false,
  2342  								"nestedStatusField2": "str2",
  2343  							},
  2344  						},
  2345  					},
  2346  				},
  2347  			},
  2348  			dclObj: &dclunstruct.Resource{
  2349  				STV: stv_foo,
  2350  				Object: map[string]interface{}{
  2351  					"intKey":      1,
  2352  					"numberKey":   0.5,
  2353  					"booleanKey":  true,
  2354  					"stringKey":   "StringVal",
  2355  					"name":        "CustomizedName",
  2356  					"project":     projectID,
  2357  					"statusField": "message",
  2358  					"statusStringObjectMap": map[string]interface{}{
  2359  						"someKey": map[string]interface{}{
  2360  							"nestedStatusField1": true,
  2361  							"nestedStatusField2": "str1",
  2362  						},
  2363  						"someOtherKey": map[string]interface{}{
  2364  							"nestedStatusField1": false,
  2365  							"nestedStatusField2": "str2",
  2366  						},
  2367  					},
  2368  				},
  2369  			},
  2370  		},
  2371  		{
  2372  			name: "status with fields that collide with reserved names",
  2373  			krmObj: &unstructured.Unstructured{
  2374  				Object: map[string]interface{}{
  2375  					"kind":       kind,
  2376  					"apiVersion": apiVersion,
  2377  					"metadata": map[string]interface{}{
  2378  						"annotations": map[string]interface{}{
  2379  							"cnrm.cloud.google.com/project-id": projectID,
  2380  						},
  2381  					},
  2382  					"spec": map[string]interface{}{
  2383  						"intKey":     1,
  2384  						"numberKey":  0.5,
  2385  						"booleanKey": true,
  2386  						"stringKey":  "StringVal",
  2387  						"resourceID": "CustomizedName",
  2388  					},
  2389  					"status": map[string]interface{}{
  2390  						"statusField":                "message",
  2391  						"resourceConditions":         "value",
  2392  						"resourceObservedGeneration": "value",
  2393  					},
  2394  				},
  2395  			},
  2396  			dclObj: &dclunstruct.Resource{
  2397  				STV: stv_foo,
  2398  				Object: map[string]interface{}{
  2399  					"intKey":             1,
  2400  					"numberKey":          0.5,
  2401  					"booleanKey":         true,
  2402  					"stringKey":          "StringVal",
  2403  					"name":               "CustomizedName",
  2404  					"project":            projectID,
  2405  					"statusField":        "message",
  2406  					"conditions":         "value",
  2407  					"observedGeneration": "value",
  2408  				},
  2409  			},
  2410  		},
  2411  	}
  2412  	for _, tc := range tests {
  2413  		tc := tc
  2414  		t.Run(tc.name, func(t *testing.T) {
  2415  			t.Parallel()
  2416  			krmObj, err := converter.DCLObjectToKRMObject(tc.dclObj)
  2417  			if err != nil {
  2418  				t.Fatalf("unexpected error: %v", err)
  2419  			}
  2420  			compareUnstructuredObjects(t, krmObj, tc.krmObj)
  2421  		})
  2422  	}
  2423  }
  2424  
  2425  func compareUnstructuredObjects(t *testing.T, actual, expected *unstructured.Unstructured) {
  2426  	//ignore name and namespace
  2427  	unstructured.RemoveNestedField(actual.Object, "metadata", "name")
  2428  	unstructured.RemoveNestedField(expected.Object, "metadata", "name")
  2429  	unstructured.RemoveNestedField(actual.Object, "metadata", "namespace")
  2430  	unstructured.RemoveNestedField(expected.Object, "metadata", "namespace")
  2431  	if !reflect.DeepEqual(actual, expected) {
  2432  		t.Fatalf("unexpected spec diff (-want +got): \n%v", cmp.Diff(expected, actual))
  2433  	}
  2434  }
  2435  
  2436  var dclSchemaMap = map[string]*openapi.Schema{
  2437  	"test1_beta_foo": &openapi.Schema{
  2438  		Type: "object",
  2439  		Properties: map[string]*openapi.Schema{
  2440  			"project": &openapi.Schema{
  2441  				Type: "string",
  2442  			},
  2443  			"name": &openapi.Schema{
  2444  				Type: "string",
  2445  			},
  2446  			"stringKey": {
  2447  				Type: "string",
  2448  			},
  2449  			"intKey": {
  2450  				Type: "integer",
  2451  			},
  2452  			"booleanKey": {
  2453  				Type: "boolean",
  2454  			},
  2455  			"numberKey": {
  2456  				Type: "number",
  2457  			},
  2458  			"statusField": {
  2459  				Type:     "string",
  2460  				ReadOnly: true,
  2461  			},
  2462  			"statusArrayPrimitive": {
  2463  				Type:     "array",
  2464  				ReadOnly: true,
  2465  				Items: &openapi.Schema{
  2466  					Type:     "string",
  2467  					ReadOnly: true,
  2468  				},
  2469  			},
  2470  			"statusArrayObject": {
  2471  				Type:     "array",
  2472  				ReadOnly: true,
  2473  				Items: &openapi.Schema{
  2474  					Type:     "object",
  2475  					ReadOnly: true,
  2476  					Properties: map[string]*openapi.Schema{
  2477  						"nestedStatusField1": &openapi.Schema{
  2478  							Type: "boolean",
  2479  						},
  2480  						"nestedStatusField2": &openapi.Schema{
  2481  							Type: "string",
  2482  						},
  2483  					},
  2484  				},
  2485  			},
  2486  			"statusStringObjectMap": {
  2487  				Type:     "object",
  2488  				ReadOnly: true,
  2489  				AdditionalProperties: &openapi.Schema{
  2490  					Type: "object",
  2491  					Properties: map[string]*openapi.Schema{
  2492  						"nestedStatusField1": &openapi.Schema{
  2493  							Type: "boolean",
  2494  						},
  2495  						"nestedStatusField2": &openapi.Schema{
  2496  							Type: "string",
  2497  						},
  2498  					},
  2499  				},
  2500  			},
  2501  			"nestedObjectKey": {
  2502  				Type: "object",
  2503  				Properties: map[string]*openapi.Schema{
  2504  					"nestedField1": {
  2505  						Type: "boolean",
  2506  					},
  2507  					"nestedField2": {
  2508  						Type: "string",
  2509  					},
  2510  					"nestedReferenceField": {
  2511  						Type: "string",
  2512  						Extension: map[string]interface{}{
  2513  							"x-dcl-references": []interface{}{
  2514  								map[interface{}]interface{}{
  2515  									"resource": "SomeService/SomeKind",
  2516  									"field":    "selfLink",
  2517  								},
  2518  							},
  2519  						},
  2520  					},
  2521  					"nestedSensitiveField": {
  2522  						Type: "string",
  2523  						Extension: map[string]interface{}{
  2524  							"x-dcl-sensitive": true,
  2525  						},
  2526  					},
  2527  					"nestedStatusField": {
  2528  						Type:     "string",
  2529  						ReadOnly: true,
  2530  					},
  2531  					"nestedStatusArrayString": {
  2532  						Type:     "array",
  2533  						ReadOnly: true,
  2534  						Items: &openapi.Schema{
  2535  							Type:     "string",
  2536  							ReadOnly: true,
  2537  						},
  2538  					},
  2539  				},
  2540  				Required: []string{"nestedField1"},
  2541  			},
  2542  			"sensitiveFieldKey": {
  2543  				Type: "string",
  2544  				Extension: map[string]interface{}{
  2545  					"x-dcl-sensitive": true,
  2546  				},
  2547  			},
  2548  			"referenceKey": {
  2549  				Type: "string",
  2550  				Extension: map[string]interface{}{
  2551  					"x-dcl-references": []interface{}{
  2552  						map[interface{}]interface{}{
  2553  							"resource": "FakeService/FakeKind",
  2554  							"field":    "name",
  2555  						},
  2556  					},
  2557  				},
  2558  			},
  2559  			"complexReferenceKey": {
  2560  				Type: "string",
  2561  				Extension: map[string]interface{}{
  2562  					"x-dcl-references": []interface{}{
  2563  						map[interface{}]interface{}{
  2564  							"resource": "FakeService/Bar",
  2565  							"field":    "self_link",
  2566  						},
  2567  						map[interface{}]interface{}{
  2568  							"resource": "FakeService/Baz",
  2569  							"field":    "self_link",
  2570  						},
  2571  					},
  2572  				},
  2573  			},
  2574  			"primitiveArrayKey": {
  2575  				Type: "array",
  2576  				Items: &openapi.Schema{
  2577  					Type: "string",
  2578  				},
  2579  			},
  2580  			"objectArrayKey": {
  2581  				Type: "array",
  2582  				Items: &openapi.Schema{
  2583  					Type: "object",
  2584  					Properties: map[string]*openapi.Schema{
  2585  						"field1": {
  2586  							Type: "number",
  2587  						},
  2588  						"field2": {
  2589  							Type: "string",
  2590  						},
  2591  						"readOnlyField": {
  2592  							Type:     "string",
  2593  							ReadOnly: true,
  2594  						},
  2595  						"readOnlySensitiveField": {
  2596  							Type:     "string",
  2597  							ReadOnly: true,
  2598  							Extension: map[string]interface{}{
  2599  								"x-dcl-sensitive": true,
  2600  							},
  2601  						},
  2602  						"readOnlyReferenceField": {
  2603  							Type:     "string",
  2604  							ReadOnly: true,
  2605  							Extension: map[string]interface{}{
  2606  								"x-dcl-references": []interface{}{
  2607  									map[interface{}]interface{}{
  2608  										"resource": "FakeService/FakeKind",
  2609  										"field":    "name",
  2610  									},
  2611  								},
  2612  							},
  2613  						},
  2614  					},
  2615  				},
  2616  			},
  2617  			"referenceArrayKey": {
  2618  				Type: "array",
  2619  				Items: &openapi.Schema{
  2620  					Type: "string",
  2621  					Extension: map[string]interface{}{
  2622  						"x-dcl-references": []interface{}{
  2623  							map[interface{}]interface{}{
  2624  								"resource": "FakeService/FakeKind",
  2625  								"field":    "name",
  2626  							},
  2627  						},
  2628  					},
  2629  				},
  2630  			},
  2631  			"stringObjectMapKey": {
  2632  				Type: "object",
  2633  				AdditionalProperties: &openapi.Schema{
  2634  					Type: "object",
  2635  					Properties: map[string]*openapi.Schema{
  2636  						"objectField1": {
  2637  							Type: "number",
  2638  						},
  2639  						"objectReferenceArrayKey": {
  2640  							Type: "array",
  2641  							Items: &openapi.Schema{
  2642  								Type: "string",
  2643  								Extension: map[string]interface{}{
  2644  									"x-dcl-references": []interface{}{
  2645  										map[interface{}]interface{}{
  2646  											"resource": "FakeService/FakeKind",
  2647  											"field":    "name",
  2648  										},
  2649  									},
  2650  								},
  2651  							},
  2652  						},
  2653  						"readOnlyField": {
  2654  							ReadOnly: true,
  2655  							Type:     "string",
  2656  						},
  2657  						"readOnlySensitiveField": {
  2658  							Type:     "string",
  2659  							ReadOnly: true,
  2660  							Extension: map[string]interface{}{
  2661  								"x-dcl-sensitive": true,
  2662  							},
  2663  						},
  2664  						"readOnlyReferenceField": {
  2665  							Type:     "string",
  2666  							ReadOnly: true,
  2667  							Extension: map[string]interface{}{
  2668  								"x-dcl-references": []interface{}{
  2669  									map[interface{}]interface{}{
  2670  										"resource": "FakeService/FakeKind",
  2671  										"field":    "name",
  2672  									},
  2673  								},
  2674  							},
  2675  						},
  2676  					},
  2677  				},
  2678  			},
  2679  			"conditions": {
  2680  				Type:     "string",
  2681  				ReadOnly: true,
  2682  			},
  2683  			"observedGeneration": {
  2684  				Type:     "string",
  2685  				ReadOnly: true,
  2686  			},
  2687  		},
  2688  		Extension: map[string]interface{}{
  2689  			"x-dcl-parent-container": "project",
  2690  		},
  2691  	},
  2692  	"test1_beta_bar": &openapi.Schema{
  2693  		Type: "object",
  2694  		Properties: map[string]*openapi.Schema{
  2695  			"project": &openapi.Schema{
  2696  				Type: "string",
  2697  			},
  2698  			"name": &openapi.Schema{
  2699  				Type: "string",
  2700  			},
  2701  			"labels": &openapi.Schema{
  2702  				Type: "object",
  2703  				AdditionalProperties: &openapi.Schema{
  2704  					Type: "string",
  2705  				},
  2706  			},
  2707  		},
  2708  		Extension: map[string]interface{}{
  2709  			"x-dcl-parent-container": "project",
  2710  			"x-dcl-labels":           "labels",
  2711  		},
  2712  	},
  2713  	"test2_beta_baz": &openapi.Schema{
  2714  		Type: "object",
  2715  		Properties: map[string]*openapi.Schema{
  2716  			"project": &openapi.Schema{
  2717  				Type: "string",
  2718  			},
  2719  			"name": &openapi.Schema{
  2720  				Type: "string",
  2721  				Extension: map[string]interface{}{
  2722  					"x-dcl-server-generated-parameter": true,
  2723  				},
  2724  			},
  2725  		},
  2726  		Extension: map[string]interface{}{
  2727  			"x-dcl-parent-container": "project",
  2728  		},
  2729  	},
  2730  	"test2_beta_noname": &openapi.Schema{
  2731  		Type: "object",
  2732  		Properties: map[string]*openapi.Schema{
  2733  			"project": &openapi.Schema{
  2734  				Type: "string",
  2735  			},
  2736  		},
  2737  		Extension: map[string]interface{}{
  2738  			"x-dcl-parent-container": "project",
  2739  		},
  2740  	},
  2741  	"test1_beta_nolabelsextension": &openapi.Schema{
  2742  		Type: "object",
  2743  		Properties: map[string]*openapi.Schema{
  2744  			"project": &openapi.Schema{
  2745  				Type: "string",
  2746  			},
  2747  			"name": &openapi.Schema{
  2748  				Type: "string",
  2749  			},
  2750  			"labels": &openapi.Schema{
  2751  				Type: "object",
  2752  				AdditionalProperties: &openapi.Schema{
  2753  					Type: "string",
  2754  				},
  2755  			},
  2756  		},
  2757  		Extension: map[string]interface{}{
  2758  			"x-dcl-parent-container": "project",
  2759  		},
  2760  	},
  2761  }
  2762  

View as plain text