kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/convert/schema_test.go (about)

     1  package convert
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  	"github.com/google/go-cmp/cmp/cmpopts"
     8  	"kubeform.dev/terraform-backend-sdk/configs/configschema"
     9  	proto "kubeform.dev/terraform-backend-sdk/tfplugin6"
    10  	"github.com/zclconf/go-cty/cty"
    11  )
    12  
    13  var (
    14  	equateEmpty   = cmpopts.EquateEmpty()
    15  	typeComparer  = cmp.Comparer(cty.Type.Equals)
    16  	valueComparer = cmp.Comparer(cty.Value.RawEquals)
    17  )
    18  
    19  // Test that we can convert configschema to protobuf types and back again.
    20  func TestConvertSchemaBlocks(t *testing.T) {
    21  	tests := map[string]struct {
    22  		Block *proto.Schema_Block
    23  		Want  *configschema.Block
    24  	}{
    25  		"attributes": {
    26  			&proto.Schema_Block{
    27  				Attributes: []*proto.Schema_Attribute{
    28  					{
    29  						Name:     "computed",
    30  						Type:     []byte(`["list","bool"]`),
    31  						Computed: true,
    32  					},
    33  					{
    34  						Name:     "optional",
    35  						Type:     []byte(`"string"`),
    36  						Optional: true,
    37  					},
    38  					{
    39  						Name:     "optional_computed",
    40  						Type:     []byte(`["map","bool"]`),
    41  						Optional: true,
    42  						Computed: true,
    43  					},
    44  					{
    45  						Name:     "required",
    46  						Type:     []byte(`"number"`),
    47  						Required: true,
    48  					},
    49  					{
    50  						Name: "nested_type",
    51  						NestedType: &proto.Schema_Object{
    52  							Nesting: proto.Schema_Object_SINGLE,
    53  							Attributes: []*proto.Schema_Attribute{
    54  								{
    55  									Name:     "computed",
    56  									Type:     []byte(`["list","bool"]`),
    57  									Computed: true,
    58  								},
    59  								{
    60  									Name:     "optional",
    61  									Type:     []byte(`"string"`),
    62  									Optional: true,
    63  								},
    64  								{
    65  									Name:     "optional_computed",
    66  									Type:     []byte(`["map","bool"]`),
    67  									Optional: true,
    68  									Computed: true,
    69  								},
    70  								{
    71  									Name:     "required",
    72  									Type:     []byte(`"number"`),
    73  									Required: true,
    74  								},
    75  							},
    76  						},
    77  						Required: true,
    78  					},
    79  					{
    80  						Name: "deeply_nested_type",
    81  						NestedType: &proto.Schema_Object{
    82  							Nesting: proto.Schema_Object_SINGLE,
    83  							Attributes: []*proto.Schema_Attribute{
    84  								{
    85  									Name: "first_level",
    86  									NestedType: &proto.Schema_Object{
    87  										Nesting: proto.Schema_Object_SINGLE,
    88  										Attributes: []*proto.Schema_Attribute{
    89  											{
    90  												Name:     "computed",
    91  												Type:     []byte(`["list","bool"]`),
    92  												Computed: true,
    93  											},
    94  											{
    95  												Name:     "optional",
    96  												Type:     []byte(`"string"`),
    97  												Optional: true,
    98  											},
    99  											{
   100  												Name:     "optional_computed",
   101  												Type:     []byte(`["map","bool"]`),
   102  												Optional: true,
   103  												Computed: true,
   104  											},
   105  											{
   106  												Name:     "required",
   107  												Type:     []byte(`"number"`),
   108  												Required: true,
   109  											},
   110  										},
   111  									},
   112  									Computed: true,
   113  								},
   114  							},
   115  						},
   116  						Required: true,
   117  					},
   118  					{
   119  						Name: "nested_list",
   120  						NestedType: &proto.Schema_Object{
   121  							Nesting: proto.Schema_Object_LIST,
   122  							Attributes: []*proto.Schema_Attribute{
   123  								{
   124  									Name:     "required",
   125  									Type:     []byte(`"string"`),
   126  									Computed: true,
   127  								},
   128  							},
   129  							MinItems: 3,
   130  						},
   131  						Required: true,
   132  					},
   133  					{
   134  						Name: "nested_set",
   135  						NestedType: &proto.Schema_Object{
   136  							Nesting: proto.Schema_Object_SET,
   137  							Attributes: []*proto.Schema_Attribute{
   138  								{
   139  									Name:     "required",
   140  									Type:     []byte(`"string"`),
   141  									Computed: true,
   142  								},
   143  							},
   144  						},
   145  						Required: true,
   146  					},
   147  					{
   148  						Name: "nested_map",
   149  						NestedType: &proto.Schema_Object{
   150  							Nesting: proto.Schema_Object_MAP,
   151  							Attributes: []*proto.Schema_Attribute{
   152  								{
   153  									Name:     "required",
   154  									Type:     []byte(`"string"`),
   155  									Computed: true,
   156  								},
   157  							},
   158  						},
   159  						Required: true,
   160  					},
   161  				},
   162  			},
   163  			&configschema.Block{
   164  				Attributes: map[string]*configschema.Attribute{
   165  					"computed": {
   166  						Type:     cty.List(cty.Bool),
   167  						Computed: true,
   168  					},
   169  					"optional": {
   170  						Type:     cty.String,
   171  						Optional: true,
   172  					},
   173  					"optional_computed": {
   174  						Type:     cty.Map(cty.Bool),
   175  						Optional: true,
   176  						Computed: true,
   177  					},
   178  					"required": {
   179  						Type:     cty.Number,
   180  						Required: true,
   181  					},
   182  					"nested_type": {
   183  						NestedType: &configschema.Object{
   184  							Attributes: map[string]*configschema.Attribute{
   185  								"computed": {
   186  									Type:     cty.List(cty.Bool),
   187  									Computed: true,
   188  								},
   189  								"optional": {
   190  									Type:     cty.String,
   191  									Optional: true,
   192  								},
   193  								"optional_computed": {
   194  									Type:     cty.Map(cty.Bool),
   195  									Optional: true,
   196  									Computed: true,
   197  								},
   198  								"required": {
   199  									Type:     cty.Number,
   200  									Required: true,
   201  								},
   202  							},
   203  							Nesting: configschema.NestingSingle,
   204  						},
   205  						Required: true,
   206  					},
   207  					"deeply_nested_type": {
   208  						NestedType: &configschema.Object{
   209  							Attributes: map[string]*configschema.Attribute{
   210  								"first_level": {
   211  									NestedType: &configschema.Object{
   212  										Nesting: configschema.NestingSingle,
   213  										Attributes: map[string]*configschema.Attribute{
   214  											"computed": {
   215  												Type:     cty.List(cty.Bool),
   216  												Computed: true,
   217  											},
   218  											"optional": {
   219  												Type:     cty.String,
   220  												Optional: true,
   221  											},
   222  											"optional_computed": {
   223  												Type:     cty.Map(cty.Bool),
   224  												Optional: true,
   225  												Computed: true,
   226  											},
   227  											"required": {
   228  												Type:     cty.Number,
   229  												Required: true,
   230  											},
   231  										},
   232  									},
   233  									Computed: true,
   234  								},
   235  							},
   236  							Nesting: configschema.NestingSingle,
   237  						},
   238  						Required: true,
   239  					},
   240  					"nested_list": {
   241  						NestedType: &configschema.Object{
   242  							Nesting: configschema.NestingList,
   243  							Attributes: map[string]*configschema.Attribute{
   244  								"required": {
   245  									Type:     cty.String,
   246  									Computed: true,
   247  								},
   248  							},
   249  							MinItems: 3,
   250  						},
   251  						Required: true,
   252  					},
   253  					"nested_map": {
   254  						NestedType: &configschema.Object{
   255  							Nesting: configschema.NestingMap,
   256  							Attributes: map[string]*configschema.Attribute{
   257  								"required": {
   258  									Type:     cty.String,
   259  									Computed: true,
   260  								},
   261  							},
   262  						},
   263  						Required: true,
   264  					},
   265  					"nested_set": {
   266  						NestedType: &configschema.Object{
   267  							Nesting: configschema.NestingSet,
   268  							Attributes: map[string]*configschema.Attribute{
   269  								"required": {
   270  									Type:     cty.String,
   271  									Computed: true,
   272  								},
   273  							},
   274  						},
   275  						Required: true,
   276  					},
   277  				},
   278  			},
   279  		},
   280  		"blocks": {
   281  			&proto.Schema_Block{
   282  				BlockTypes: []*proto.Schema_NestedBlock{
   283  					{
   284  						TypeName: "list",
   285  						Nesting:  proto.Schema_NestedBlock_LIST,
   286  						Block:    &proto.Schema_Block{},
   287  					},
   288  					{
   289  						TypeName: "map",
   290  						Nesting:  proto.Schema_NestedBlock_MAP,
   291  						Block:    &proto.Schema_Block{},
   292  					},
   293  					{
   294  						TypeName: "set",
   295  						Nesting:  proto.Schema_NestedBlock_SET,
   296  						Block:    &proto.Schema_Block{},
   297  					},
   298  					{
   299  						TypeName: "single",
   300  						Nesting:  proto.Schema_NestedBlock_SINGLE,
   301  						Block: &proto.Schema_Block{
   302  							Attributes: []*proto.Schema_Attribute{
   303  								{
   304  									Name:     "foo",
   305  									Type:     []byte(`"dynamic"`),
   306  									Required: true,
   307  								},
   308  							},
   309  						},
   310  					},
   311  				},
   312  			},
   313  			&configschema.Block{
   314  				BlockTypes: map[string]*configschema.NestedBlock{
   315  					"list": &configschema.NestedBlock{
   316  						Nesting: configschema.NestingList,
   317  					},
   318  					"map": &configschema.NestedBlock{
   319  						Nesting: configschema.NestingMap,
   320  					},
   321  					"set": &configschema.NestedBlock{
   322  						Nesting: configschema.NestingSet,
   323  					},
   324  					"single": &configschema.NestedBlock{
   325  						Nesting: configschema.NestingSingle,
   326  						Block: configschema.Block{
   327  							Attributes: map[string]*configschema.Attribute{
   328  								"foo": {
   329  									Type:     cty.DynamicPseudoType,
   330  									Required: true,
   331  								},
   332  							},
   333  						},
   334  					},
   335  				},
   336  			},
   337  		},
   338  		"deep block nesting": {
   339  			&proto.Schema_Block{
   340  				BlockTypes: []*proto.Schema_NestedBlock{
   341  					{
   342  						TypeName: "single",
   343  						Nesting:  proto.Schema_NestedBlock_SINGLE,
   344  						Block: &proto.Schema_Block{
   345  							BlockTypes: []*proto.Schema_NestedBlock{
   346  								{
   347  									TypeName: "list",
   348  									Nesting:  proto.Schema_NestedBlock_LIST,
   349  									Block: &proto.Schema_Block{
   350  										BlockTypes: []*proto.Schema_NestedBlock{
   351  											{
   352  												TypeName: "set",
   353  												Nesting:  proto.Schema_NestedBlock_SET,
   354  												Block:    &proto.Schema_Block{},
   355  											},
   356  										},
   357  									},
   358  								},
   359  							},
   360  						},
   361  					},
   362  				},
   363  			},
   364  			&configschema.Block{
   365  				BlockTypes: map[string]*configschema.NestedBlock{
   366  					"single": &configschema.NestedBlock{
   367  						Nesting: configschema.NestingSingle,
   368  						Block: configschema.Block{
   369  							BlockTypes: map[string]*configschema.NestedBlock{
   370  								"list": &configschema.NestedBlock{
   371  									Nesting: configschema.NestingList,
   372  									Block: configschema.Block{
   373  										BlockTypes: map[string]*configschema.NestedBlock{
   374  											"set": &configschema.NestedBlock{
   375  												Nesting: configschema.NestingSet,
   376  											},
   377  										},
   378  									},
   379  								},
   380  							},
   381  						},
   382  					},
   383  				},
   384  			},
   385  		},
   386  	}
   387  
   388  	for name, tc := range tests {
   389  		t.Run(name, func(t *testing.T) {
   390  			converted := ProtoToConfigSchema(tc.Block)
   391  			if !cmp.Equal(converted, tc.Want, typeComparer, valueComparer, equateEmpty) {
   392  				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, valueComparer, equateEmpty))
   393  			}
   394  		})
   395  	}
   396  }
   397  
   398  // Test that we can convert configschema to protobuf types and back again.
   399  func TestConvertProtoSchemaBlocks(t *testing.T) {
   400  	tests := map[string]struct {
   401  		Want  *proto.Schema_Block
   402  		Block *configschema.Block
   403  	}{
   404  		"attributes": {
   405  			&proto.Schema_Block{
   406  				Attributes: []*proto.Schema_Attribute{
   407  					{
   408  						Name:     "computed",
   409  						Type:     []byte(`["list","bool"]`),
   410  						Computed: true,
   411  					},
   412  					{
   413  						Name:     "optional",
   414  						Type:     []byte(`"string"`),
   415  						Optional: true,
   416  					},
   417  					{
   418  						Name:     "optional_computed",
   419  						Type:     []byte(`["map","bool"]`),
   420  						Optional: true,
   421  						Computed: true,
   422  					},
   423  					{
   424  						Name:     "required",
   425  						Type:     []byte(`"number"`),
   426  						Required: true,
   427  					},
   428  				},
   429  			},
   430  			&configschema.Block{
   431  				Attributes: map[string]*configschema.Attribute{
   432  					"computed": {
   433  						Type:     cty.List(cty.Bool),
   434  						Computed: true,
   435  					},
   436  					"optional": {
   437  						Type:     cty.String,
   438  						Optional: true,
   439  					},
   440  					"optional_computed": {
   441  						Type:     cty.Map(cty.Bool),
   442  						Optional: true,
   443  						Computed: true,
   444  					},
   445  					"required": {
   446  						Type:     cty.Number,
   447  						Required: true,
   448  					},
   449  				},
   450  			},
   451  		},
   452  		"blocks": {
   453  			&proto.Schema_Block{
   454  				BlockTypes: []*proto.Schema_NestedBlock{
   455  					{
   456  						TypeName: "list",
   457  						Nesting:  proto.Schema_NestedBlock_LIST,
   458  						Block:    &proto.Schema_Block{},
   459  					},
   460  					{
   461  						TypeName: "map",
   462  						Nesting:  proto.Schema_NestedBlock_MAP,
   463  						Block:    &proto.Schema_Block{},
   464  					},
   465  					{
   466  						TypeName: "set",
   467  						Nesting:  proto.Schema_NestedBlock_SET,
   468  						Block:    &proto.Schema_Block{},
   469  					},
   470  					{
   471  						TypeName: "single",
   472  						Nesting:  proto.Schema_NestedBlock_SINGLE,
   473  						Block: &proto.Schema_Block{
   474  							Attributes: []*proto.Schema_Attribute{
   475  								{
   476  									Name:     "foo",
   477  									Type:     []byte(`"dynamic"`),
   478  									Required: true,
   479  								},
   480  							},
   481  						},
   482  					},
   483  				},
   484  			},
   485  			&configschema.Block{
   486  				BlockTypes: map[string]*configschema.NestedBlock{
   487  					"list": &configschema.NestedBlock{
   488  						Nesting: configschema.NestingList,
   489  					},
   490  					"map": &configschema.NestedBlock{
   491  						Nesting: configschema.NestingMap,
   492  					},
   493  					"set": &configschema.NestedBlock{
   494  						Nesting: configschema.NestingSet,
   495  					},
   496  					"single": &configschema.NestedBlock{
   497  						Nesting: configschema.NestingSingle,
   498  						Block: configschema.Block{
   499  							Attributes: map[string]*configschema.Attribute{
   500  								"foo": {
   501  									Type:     cty.DynamicPseudoType,
   502  									Required: true,
   503  								},
   504  							},
   505  						},
   506  					},
   507  				},
   508  			},
   509  		},
   510  		"deep block nesting": {
   511  			&proto.Schema_Block{
   512  				BlockTypes: []*proto.Schema_NestedBlock{
   513  					{
   514  						TypeName: "single",
   515  						Nesting:  proto.Schema_NestedBlock_SINGLE,
   516  						Block: &proto.Schema_Block{
   517  							BlockTypes: []*proto.Schema_NestedBlock{
   518  								{
   519  									TypeName: "list",
   520  									Nesting:  proto.Schema_NestedBlock_LIST,
   521  									Block: &proto.Schema_Block{
   522  										BlockTypes: []*proto.Schema_NestedBlock{
   523  											{
   524  												TypeName: "set",
   525  												Nesting:  proto.Schema_NestedBlock_SET,
   526  												Block:    &proto.Schema_Block{},
   527  											},
   528  										},
   529  									},
   530  								},
   531  							},
   532  						},
   533  					},
   534  				},
   535  			},
   536  			&configschema.Block{
   537  				BlockTypes: map[string]*configschema.NestedBlock{
   538  					"single": &configschema.NestedBlock{
   539  						Nesting: configschema.NestingSingle,
   540  						Block: configschema.Block{
   541  							BlockTypes: map[string]*configschema.NestedBlock{
   542  								"list": &configschema.NestedBlock{
   543  									Nesting: configschema.NestingList,
   544  									Block: configschema.Block{
   545  										BlockTypes: map[string]*configschema.NestedBlock{
   546  											"set": &configschema.NestedBlock{
   547  												Nesting: configschema.NestingSet,
   548  											},
   549  										},
   550  									},
   551  								},
   552  							},
   553  						},
   554  					},
   555  				},
   556  			},
   557  		},
   558  	}
   559  
   560  	for name, tc := range tests {
   561  		t.Run(name, func(t *testing.T) {
   562  			converted := ConfigSchemaToProto(tc.Block)
   563  			if !cmp.Equal(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported) {
   564  				t.Fatal(cmp.Diff(converted, tc.Want, typeComparer, equateEmpty, ignoreUnexported))
   565  			}
   566  		})
   567  	}
   568  }