github.com/opentofu/opentofu@v1.7.1/internal/command/jsonchecks/checks_test.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package jsonchecks
     7  
     8  import (
     9  	"encoding/json"
    10  	"testing"
    11  
    12  	"github.com/google/go-cmp/cmp"
    13  	"github.com/opentofu/opentofu/internal/addrs"
    14  	"github.com/opentofu/opentofu/internal/checks"
    15  	"github.com/opentofu/opentofu/internal/states"
    16  )
    17  
    18  func TestMarshalCheckStates(t *testing.T) {
    19  	resourceAAddr := addrs.ConfigCheckable(addrs.Resource{
    20  		Mode: addrs.ManagedResourceMode,
    21  		Type: "test",
    22  		Name: "a",
    23  	}.InModule(addrs.RootModule))
    24  	resourceAInstAddr := addrs.Checkable(addrs.Resource{
    25  		Mode: addrs.ManagedResourceMode,
    26  		Type: "test",
    27  		Name: "a",
    28  	}.Instance(addrs.StringKey("foo")).Absolute(addrs.RootModuleInstance))
    29  	moduleChildAddr := addrs.RootModuleInstance.Child("child", addrs.IntKey(0))
    30  	resourceBAddr := addrs.ConfigCheckable(addrs.Resource{
    31  		Mode: addrs.ManagedResourceMode,
    32  		Type: "test",
    33  		Name: "b",
    34  	}.InModule(moduleChildAddr.Module()))
    35  	resourceBInstAddr := addrs.Checkable(addrs.Resource{
    36  		Mode: addrs.ManagedResourceMode,
    37  		Type: "test",
    38  		Name: "b",
    39  	}.Instance(addrs.NoKey).Absolute(moduleChildAddr))
    40  	outputAAddr := addrs.ConfigCheckable(addrs.OutputValue{Name: "a"}.InModule(addrs.RootModule))
    41  	outputAInstAddr := addrs.Checkable(addrs.OutputValue{Name: "a"}.Absolute(addrs.RootModuleInstance))
    42  	outputBAddr := addrs.ConfigCheckable(addrs.OutputValue{Name: "b"}.InModule(moduleChildAddr.Module()))
    43  	outputBInstAddr := addrs.Checkable(addrs.OutputValue{Name: "b"}.Absolute(moduleChildAddr))
    44  	checkBlockAAddr := addrs.ConfigCheckable(addrs.Check{Name: "a"}.InModule(addrs.RootModule))
    45  	checkBlockAInstAddr := addrs.Checkable(addrs.Check{Name: "a"}.Absolute(addrs.RootModuleInstance))
    46  
    47  	tests := map[string]struct {
    48  		Input *states.CheckResults
    49  		Want  any
    50  	}{
    51  		"empty": {
    52  			&states.CheckResults{},
    53  			[]any{},
    54  		},
    55  		"failures": {
    56  			&states.CheckResults{
    57  				ConfigResults: addrs.MakeMap(
    58  					addrs.MakeMapElem(resourceAAddr, &states.CheckResultAggregate{
    59  						Status: checks.StatusFail,
    60  						ObjectResults: addrs.MakeMap(
    61  							addrs.MakeMapElem(resourceAInstAddr, &states.CheckResultObject{
    62  								Status: checks.StatusFail,
    63  								FailureMessages: []string{
    64  									"Not enough boops.",
    65  									"Too many beeps.",
    66  								},
    67  							}),
    68  						),
    69  					}),
    70  					addrs.MakeMapElem(resourceBAddr, &states.CheckResultAggregate{
    71  						Status: checks.StatusFail,
    72  						ObjectResults: addrs.MakeMap(
    73  							addrs.MakeMapElem(resourceBInstAddr, &states.CheckResultObject{
    74  								Status: checks.StatusFail,
    75  								FailureMessages: []string{
    76  									"Splines are too pointy.",
    77  								},
    78  							}),
    79  						),
    80  					}),
    81  					addrs.MakeMapElem(outputAAddr, &states.CheckResultAggregate{
    82  						Status: checks.StatusFail,
    83  						ObjectResults: addrs.MakeMap(
    84  							addrs.MakeMapElem(outputAInstAddr, &states.CheckResultObject{
    85  								Status: checks.StatusFail,
    86  							}),
    87  						),
    88  					}),
    89  					addrs.MakeMapElem(outputBAddr, &states.CheckResultAggregate{
    90  						Status: checks.StatusFail,
    91  						ObjectResults: addrs.MakeMap(
    92  							addrs.MakeMapElem(outputBInstAddr, &states.CheckResultObject{
    93  								Status: checks.StatusFail,
    94  								FailureMessages: []string{
    95  									"Not object-oriented enough.",
    96  								},
    97  							}),
    98  						),
    99  					}),
   100  					addrs.MakeMapElem(checkBlockAAddr, &states.CheckResultAggregate{
   101  						Status: checks.StatusFail,
   102  						ObjectResults: addrs.MakeMap(
   103  							addrs.MakeMapElem(checkBlockAInstAddr, &states.CheckResultObject{
   104  								Status: checks.StatusFail,
   105  								FailureMessages: []string{
   106  									"Couldn't reverse the polarity.",
   107  								},
   108  							}),
   109  						),
   110  					}),
   111  				),
   112  			},
   113  			[]any{
   114  				map[string]any{
   115  					"address": map[string]any{
   116  						"kind":       "check",
   117  						"to_display": "check.a",
   118  						"name":       "a",
   119  					},
   120  					"instances": []any{
   121  						map[string]any{
   122  							"address": map[string]any{
   123  								"to_display": `check.a`,
   124  							},
   125  							"problems": []any{
   126  								map[string]any{
   127  									"message": "Couldn't reverse the polarity.",
   128  								},
   129  							},
   130  							"status": "fail",
   131  						},
   132  					},
   133  					"status": "fail",
   134  				},
   135  				map[string]any{
   136  					"address": map[string]any{
   137  						"kind":       "output_value",
   138  						"module":     "module.child",
   139  						"name":       "b",
   140  						"to_display": "module.child.output.b",
   141  					},
   142  					"instances": []any{
   143  						map[string]any{
   144  							"address": map[string]any{
   145  								"module":     "module.child[0]",
   146  								"to_display": "module.child[0].output.b",
   147  							},
   148  							"problems": []any{
   149  								map[string]any{
   150  									"message": "Not object-oriented enough.",
   151  								},
   152  							},
   153  							"status": "fail",
   154  						},
   155  					},
   156  					"status": "fail",
   157  				},
   158  				map[string]any{
   159  					"address": map[string]any{
   160  						"kind":       "resource",
   161  						"mode":       "managed",
   162  						"module":     "module.child",
   163  						"name":       "b",
   164  						"to_display": "module.child.test.b",
   165  						"type":       "test",
   166  					},
   167  					"instances": []any{
   168  						map[string]any{
   169  							"address": map[string]any{
   170  								"module":     "module.child[0]",
   171  								"to_display": "module.child[0].test.b",
   172  							},
   173  							"problems": []any{
   174  								map[string]any{
   175  									"message": "Splines are too pointy.",
   176  								},
   177  							},
   178  							"status": "fail",
   179  						},
   180  					},
   181  					"status": "fail",
   182  				},
   183  				map[string]any{
   184  					"address": map[string]any{
   185  						"kind":       "output_value",
   186  						"name":       "a",
   187  						"to_display": "output.a",
   188  					},
   189  					"instances": []any{
   190  						map[string]any{
   191  							"address": map[string]any{
   192  								"to_display": "output.a",
   193  							},
   194  							"status": "fail",
   195  						},
   196  					},
   197  					"status": "fail",
   198  				},
   199  				map[string]any{
   200  					"address": map[string]any{
   201  						"kind":       "resource",
   202  						"mode":       "managed",
   203  						"name":       "a",
   204  						"to_display": "test.a",
   205  						"type":       "test",
   206  					},
   207  					"instances": []any{
   208  						map[string]any{
   209  							"address": map[string]any{
   210  								"to_display":   `test.a["foo"]`,
   211  								"instance_key": "foo",
   212  							},
   213  							"problems": []any{
   214  								map[string]any{
   215  									"message": "Not enough boops.",
   216  								},
   217  								map[string]any{
   218  									"message": "Too many beeps.",
   219  								},
   220  							},
   221  							"status": "fail",
   222  						},
   223  					},
   224  					"status": "fail",
   225  				},
   226  			},
   227  		},
   228  	}
   229  
   230  	for name, test := range tests {
   231  		t.Run(name, func(t *testing.T) {
   232  			gotBytes := MarshalCheckStates(test.Input)
   233  
   234  			var got any
   235  			err := json.Unmarshal(gotBytes, &got)
   236  			if err != nil {
   237  				t.Fatal(err)
   238  			}
   239  
   240  			if diff := cmp.Diff(test.Want, got); diff != "" {
   241  				t.Errorf("wrong result\n%s", diff)
   242  			}
   243  		})
   244  	}
   245  }