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

     1  package convert
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/google/go-cmp/cmp/cmpopts"
     9  	"kubeform.dev/terraform-backend-sdk/tfdiags"
    10  	proto "kubeform.dev/terraform-backend-sdk/tfplugin6"
    11  	"github.com/zclconf/go-cty/cty"
    12  )
    13  
    14  var ignoreUnexported = cmpopts.IgnoreUnexported(
    15  	proto.Diagnostic{},
    16  	proto.Schema_Block{},
    17  	proto.Schema_NestedBlock{},
    18  	proto.Schema_Attribute{},
    19  )
    20  
    21  func TestProtoDiagnostics(t *testing.T) {
    22  	diags := WarnsAndErrsToProto(
    23  		[]string{
    24  			"warning 1",
    25  			"warning 2",
    26  		},
    27  		[]error{
    28  			errors.New("error 1"),
    29  			errors.New("error 2"),
    30  		},
    31  	)
    32  
    33  	expected := []*proto.Diagnostic{
    34  		{
    35  			Severity: proto.Diagnostic_WARNING,
    36  			Summary:  "warning 1",
    37  		},
    38  		{
    39  			Severity: proto.Diagnostic_WARNING,
    40  			Summary:  "warning 2",
    41  		},
    42  		{
    43  			Severity: proto.Diagnostic_ERROR,
    44  			Summary:  "error 1",
    45  		},
    46  		{
    47  			Severity: proto.Diagnostic_ERROR,
    48  			Summary:  "error 2",
    49  		},
    50  	}
    51  
    52  	if !cmp.Equal(expected, diags, ignoreUnexported) {
    53  		t.Fatal(cmp.Diff(expected, diags, ignoreUnexported))
    54  	}
    55  }
    56  
    57  func TestDiagnostics(t *testing.T) {
    58  	type diagFlat struct {
    59  		Severity tfdiags.Severity
    60  		Attr     []interface{}
    61  		Summary  string
    62  		Detail   string
    63  	}
    64  
    65  	tests := map[string]struct {
    66  		Cons func([]*proto.Diagnostic) []*proto.Diagnostic
    67  		Want []diagFlat
    68  	}{
    69  		"nil": {
    70  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
    71  				return diags
    72  			},
    73  			nil,
    74  		},
    75  		"error": {
    76  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
    77  				return append(diags, &proto.Diagnostic{
    78  					Severity: proto.Diagnostic_ERROR,
    79  					Summary:  "simple error",
    80  				})
    81  			},
    82  			[]diagFlat{
    83  				{
    84  					Severity: tfdiags.Error,
    85  					Summary:  "simple error",
    86  				},
    87  			},
    88  		},
    89  		"detailed error": {
    90  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
    91  				return append(diags, &proto.Diagnostic{
    92  					Severity: proto.Diagnostic_ERROR,
    93  					Summary:  "simple error",
    94  					Detail:   "detailed error",
    95  				})
    96  			},
    97  			[]diagFlat{
    98  				{
    99  					Severity: tfdiags.Error,
   100  					Summary:  "simple error",
   101  					Detail:   "detailed error",
   102  				},
   103  			},
   104  		},
   105  		"warning": {
   106  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   107  				return append(diags, &proto.Diagnostic{
   108  					Severity: proto.Diagnostic_WARNING,
   109  					Summary:  "simple warning",
   110  				})
   111  			},
   112  			[]diagFlat{
   113  				{
   114  					Severity: tfdiags.Warning,
   115  					Summary:  "simple warning",
   116  				},
   117  			},
   118  		},
   119  		"detailed warning": {
   120  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   121  				return append(diags, &proto.Diagnostic{
   122  					Severity: proto.Diagnostic_WARNING,
   123  					Summary:  "simple warning",
   124  					Detail:   "detailed warning",
   125  				})
   126  			},
   127  			[]diagFlat{
   128  				{
   129  					Severity: tfdiags.Warning,
   130  					Summary:  "simple warning",
   131  					Detail:   "detailed warning",
   132  				},
   133  			},
   134  		},
   135  		"multi error": {
   136  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   137  				diags = append(diags, &proto.Diagnostic{
   138  					Severity: proto.Diagnostic_ERROR,
   139  					Summary:  "first error",
   140  				}, &proto.Diagnostic{
   141  					Severity: proto.Diagnostic_ERROR,
   142  					Summary:  "second error",
   143  				})
   144  				return diags
   145  			},
   146  			[]diagFlat{
   147  				{
   148  					Severity: tfdiags.Error,
   149  					Summary:  "first error",
   150  				},
   151  				{
   152  					Severity: tfdiags.Error,
   153  					Summary:  "second error",
   154  				},
   155  			},
   156  		},
   157  		"warning and error": {
   158  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   159  				diags = append(diags, &proto.Diagnostic{
   160  					Severity: proto.Diagnostic_WARNING,
   161  					Summary:  "warning",
   162  				}, &proto.Diagnostic{
   163  					Severity: proto.Diagnostic_ERROR,
   164  					Summary:  "error",
   165  				})
   166  				return diags
   167  			},
   168  			[]diagFlat{
   169  				{
   170  					Severity: tfdiags.Warning,
   171  					Summary:  "warning",
   172  				},
   173  				{
   174  					Severity: tfdiags.Error,
   175  					Summary:  "error",
   176  				},
   177  			},
   178  		},
   179  		"attr error": {
   180  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   181  				diags = append(diags, &proto.Diagnostic{
   182  					Severity: proto.Diagnostic_ERROR,
   183  					Summary:  "error",
   184  					Detail:   "error detail",
   185  					Attribute: &proto.AttributePath{
   186  						Steps: []*proto.AttributePath_Step{
   187  							{
   188  								Selector: &proto.AttributePath_Step_AttributeName{
   189  									AttributeName: "attribute_name",
   190  								},
   191  							},
   192  						},
   193  					},
   194  				})
   195  				return diags
   196  			},
   197  			[]diagFlat{
   198  				{
   199  					Severity: tfdiags.Error,
   200  					Summary:  "error",
   201  					Detail:   "error detail",
   202  					Attr:     []interface{}{"attribute_name"},
   203  				},
   204  			},
   205  		},
   206  		"multi attr": {
   207  			func(diags []*proto.Diagnostic) []*proto.Diagnostic {
   208  				diags = append(diags,
   209  					&proto.Diagnostic{
   210  						Severity: proto.Diagnostic_ERROR,
   211  						Summary:  "error 1",
   212  						Detail:   "error 1 detail",
   213  						Attribute: &proto.AttributePath{
   214  							Steps: []*proto.AttributePath_Step{
   215  								{
   216  									Selector: &proto.AttributePath_Step_AttributeName{
   217  										AttributeName: "attr",
   218  									},
   219  								},
   220  							},
   221  						},
   222  					},
   223  					&proto.Diagnostic{
   224  						Severity: proto.Diagnostic_ERROR,
   225  						Summary:  "error 2",
   226  						Detail:   "error 2 detail",
   227  						Attribute: &proto.AttributePath{
   228  							Steps: []*proto.AttributePath_Step{
   229  								{
   230  									Selector: &proto.AttributePath_Step_AttributeName{
   231  										AttributeName: "attr",
   232  									},
   233  								},
   234  								{
   235  									Selector: &proto.AttributePath_Step_AttributeName{
   236  										AttributeName: "sub",
   237  									},
   238  								},
   239  							},
   240  						},
   241  					},
   242  					&proto.Diagnostic{
   243  						Severity: proto.Diagnostic_WARNING,
   244  						Summary:  "warning",
   245  						Detail:   "warning detail",
   246  						Attribute: &proto.AttributePath{
   247  							Steps: []*proto.AttributePath_Step{
   248  								{
   249  									Selector: &proto.AttributePath_Step_AttributeName{
   250  										AttributeName: "attr",
   251  									},
   252  								},
   253  								{
   254  									Selector: &proto.AttributePath_Step_ElementKeyInt{
   255  										ElementKeyInt: 1,
   256  									},
   257  								},
   258  								{
   259  									Selector: &proto.AttributePath_Step_AttributeName{
   260  										AttributeName: "sub",
   261  									},
   262  								},
   263  							},
   264  						},
   265  					},
   266  					&proto.Diagnostic{
   267  						Severity: proto.Diagnostic_ERROR,
   268  						Summary:  "error 3",
   269  						Detail:   "error 3 detail",
   270  						Attribute: &proto.AttributePath{
   271  							Steps: []*proto.AttributePath_Step{
   272  								{
   273  									Selector: &proto.AttributePath_Step_AttributeName{
   274  										AttributeName: "attr",
   275  									},
   276  								},
   277  								{
   278  									Selector: &proto.AttributePath_Step_ElementKeyString{
   279  										ElementKeyString: "idx",
   280  									},
   281  								},
   282  								{
   283  									Selector: &proto.AttributePath_Step_AttributeName{
   284  										AttributeName: "sub",
   285  									},
   286  								},
   287  							},
   288  						},
   289  					},
   290  				)
   291  
   292  				return diags
   293  			},
   294  			[]diagFlat{
   295  				{
   296  					Severity: tfdiags.Error,
   297  					Summary:  "error 1",
   298  					Detail:   "error 1 detail",
   299  					Attr:     []interface{}{"attr"},
   300  				},
   301  				{
   302  					Severity: tfdiags.Error,
   303  					Summary:  "error 2",
   304  					Detail:   "error 2 detail",
   305  					Attr:     []interface{}{"attr", "sub"},
   306  				},
   307  				{
   308  					Severity: tfdiags.Warning,
   309  					Summary:  "warning",
   310  					Detail:   "warning detail",
   311  					Attr:     []interface{}{"attr", 1, "sub"},
   312  				},
   313  				{
   314  					Severity: tfdiags.Error,
   315  					Summary:  "error 3",
   316  					Detail:   "error 3 detail",
   317  					Attr:     []interface{}{"attr", "idx", "sub"},
   318  				},
   319  			},
   320  		},
   321  	}
   322  
   323  	flattenTFDiags := func(ds tfdiags.Diagnostics) []diagFlat {
   324  		var flat []diagFlat
   325  		for _, item := range ds {
   326  			desc := item.Description()
   327  
   328  			var attr []interface{}
   329  
   330  			for _, a := range tfdiags.GetAttribute(item) {
   331  				switch step := a.(type) {
   332  				case cty.GetAttrStep:
   333  					attr = append(attr, step.Name)
   334  				case cty.IndexStep:
   335  					switch step.Key.Type() {
   336  					case cty.Number:
   337  						i, _ := step.Key.AsBigFloat().Int64()
   338  						attr = append(attr, int(i))
   339  					case cty.String:
   340  						attr = append(attr, step.Key.AsString())
   341  					}
   342  				}
   343  			}
   344  
   345  			flat = append(flat, diagFlat{
   346  				Severity: item.Severity(),
   347  				Attr:     attr,
   348  				Summary:  desc.Summary,
   349  				Detail:   desc.Detail,
   350  			})
   351  		}
   352  		return flat
   353  	}
   354  
   355  	for name, tc := range tests {
   356  		t.Run(name, func(t *testing.T) {
   357  			// we take the
   358  			tfDiags := ProtoToDiagnostics(tc.Cons(nil))
   359  
   360  			flat := flattenTFDiags(tfDiags)
   361  
   362  			if !cmp.Equal(flat, tc.Want, typeComparer, valueComparer, equateEmpty) {
   363  				t.Fatal(cmp.Diff(flat, tc.Want, typeComparer, valueComparer, equateEmpty))
   364  			}
   365  		})
   366  	}
   367  }