github.com/argoproj/argo-cd/v3@v3.2.1/cmd/argocd/commands/app_resource_test.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"strings"
     7  	"testing"
     8  	"text/tabwriter"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    13  
    14  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    15  )
    16  
    17  func TestPrintTreeViewAppResources(t *testing.T) {
    18  	var nodes [3]v1alpha1.ResourceNode
    19  	nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"}
    20  	nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}}
    21  	nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}
    22  	nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}}
    23  	nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}
    24  	nodeMapping := make(map[string]v1alpha1.ResourceNode)
    25  	mapParentToChild := make(map[string][]string)
    26  	parentNode := make(map[string]struct{})
    27  	for _, node := range nodes {
    28  		nodeMapping[node.UID] = node
    29  		if len(node.ParentRefs) > 0 {
    30  			_, ok := mapParentToChild[node.ParentRefs[0].UID]
    31  			if !ok {
    32  				var temp []string
    33  				mapParentToChild[node.ParentRefs[0].UID] = temp
    34  			}
    35  			mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
    36  		} else {
    37  			parentNode[node.UID] = struct{}{}
    38  		}
    39  	}
    40  	buf := &bytes.Buffer{}
    41  	w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0)
    42  
    43  	printTreeViewAppResourcesNotOrphaned(nodeMapping, mapParentToChild, parentNode, w)
    44  	require.NoError(t, w.Flush())
    45  	output := buf.String()
    46  
    47  	assert.Contains(t, output, "Rollout")
    48  	assert.Contains(t, output, "argoproj.io")
    49  }
    50  
    51  func TestPrintTreeViewDetailedAppResources(t *testing.T) {
    52  	var nodes [3]v1alpha1.ResourceNode
    53  	nodes[0].ResourceRef = v1alpha1.ResourceRef{Group: "", Version: "v1", Kind: "Pod", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5-6trpt", UID: "92c3a5fe-d13e-4ae2-b8ec-c10dd3543b28"}
    54  	nodes[0].ParentRefs = []v1alpha1.ResourceRef{{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}}
    55  	nodes[1].ResourceRef = v1alpha1.ResourceRef{Group: "apps", Version: "v1", Kind: "ReplicaSet", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo-5dcd5457d5", UID: "75c30dce-1b66-414f-a86c-573a74be0f40"}
    56  	nodes[1].ParentRefs = []v1alpha1.ResourceRef{{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}}
    57  	nodes[2].ResourceRef = v1alpha1.ResourceRef{Group: "argoproj.io", Version: "", Kind: "Rollout", Namespace: "sandbox-rollout-numalogic-demo", Name: "numalogic-rollout-demo", UID: "87f3aab0-f634-4b2c-959a-7ddd30675ed0"}
    58  	nodes[2].Health = &v1alpha1.HealthStatus{
    59  		Status:  "Degraded",
    60  		Message: "Readiness Gate failed",
    61  	}
    62  
    63  	nodeMapping := make(map[string]v1alpha1.ResourceNode)
    64  	mapParentToChild := make(map[string][]string)
    65  	parentNode := make(map[string]struct{})
    66  	for _, node := range nodes {
    67  		nodeMapping[node.UID] = node
    68  		if len(node.ParentRefs) > 0 {
    69  			_, ok := mapParentToChild[node.ParentRefs[0].UID]
    70  			if !ok {
    71  				var temp []string
    72  				mapParentToChild[node.ParentRefs[0].UID] = temp
    73  			}
    74  			mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
    75  		} else {
    76  			parentNode[node.UID] = struct{}{}
    77  		}
    78  	}
    79  	buf := &bytes.Buffer{}
    80  	w := tabwriter.NewWriter(buf, 0, 0, 2, ' ', 0)
    81  
    82  	printDetailedTreeViewAppResourcesNotOrphaned(nodeMapping, mapParentToChild, parentNode, w)
    83  	require.NoError(t, w.Flush())
    84  	output := buf.String()
    85  
    86  	assert.Contains(t, output, "Rollout")
    87  	assert.Contains(t, output, "Degraded")
    88  	assert.Contains(t, output, "Readiness Gate failed")
    89  }
    90  
    91  func TestPrintResourcesTree(t *testing.T) {
    92  	tree := v1alpha1.ApplicationTree{
    93  		Nodes: []v1alpha1.ResourceNode{
    94  			{
    95  				ResourceRef: v1alpha1.ResourceRef{
    96  					Group:     "group",
    97  					Kind:      "kind",
    98  					Namespace: "ns",
    99  					Name:      "rs1",
   100  				},
   101  			},
   102  		},
   103  		OrphanedNodes: []v1alpha1.ResourceNode{
   104  			{
   105  				ResourceRef: v1alpha1.ResourceRef{
   106  					Group:     "group2",
   107  					Kind:      "kind2",
   108  					Namespace: "ns2",
   109  					Name:      "rs2",
   110  				},
   111  			},
   112  		},
   113  	}
   114  	output, _ := captureOutput(func() error {
   115  		printResources(true, false, &tree, "")
   116  		return nil
   117  	})
   118  
   119  	expectation := "GROUP   KIND   NAMESPACE  NAME  ORPHANED\ngroup   kind   ns         rs1   No\ngroup2  kind2  ns2        rs2   Yes\n"
   120  
   121  	assert.Equal(t, expectation, output)
   122  }
   123  
   124  func TestFilterFieldsFromObject(t *testing.T) {
   125  	tests := []struct {
   126  		name             string
   127  		obj              unstructured.Unstructured
   128  		filteredFields   []string
   129  		expectedFields   []string
   130  		unexpectedFields []string
   131  	}{
   132  		{
   133  			name: "filter nested field",
   134  			obj: unstructured.Unstructured{
   135  				Object: map[string]any{
   136  					"apiVersion": "vX",
   137  					"kind":       "kind",
   138  					"metadata": map[string]any{
   139  						"name": "test",
   140  					},
   141  					"spec": map[string]any{
   142  						"testfield": map[string]any{
   143  							"nestedtest": "test",
   144  						},
   145  						"testfield2": "test",
   146  					},
   147  				},
   148  			},
   149  			filteredFields:   []string{"spec.testfield.nestedtest"},
   150  			expectedFields:   []string{"spec.testfield.nestedtest"},
   151  			unexpectedFields: []string{"spec.testfield2"},
   152  		},
   153  		{
   154  			name: "filter multiple fields",
   155  			obj: unstructured.Unstructured{
   156  				Object: map[string]any{
   157  					"apiVersion": "vX",
   158  					"kind":       "kind",
   159  					"metadata": map[string]any{
   160  						"name": "test",
   161  					},
   162  					"spec": map[string]any{
   163  						"testfield": map[string]any{
   164  							"nestedtest": "test",
   165  						},
   166  						"testfield2": "test",
   167  						"testfield3": "deleteme",
   168  					},
   169  				},
   170  			},
   171  			filteredFields:   []string{"spec.testfield.nestedtest", "spec.testfield3"},
   172  			expectedFields:   []string{"spec.testfield.nestedtest"},
   173  			unexpectedFields: []string{"spec.testfield2"},
   174  		},
   175  		{
   176  			name: "filter nested list object",
   177  			obj: unstructured.Unstructured{
   178  				Object: map[string]any{
   179  					"apiVersion": "vX",
   180  					"kind":       "kind",
   181  					"metadata": map[string]any{
   182  						"name": "test",
   183  					},
   184  					"spec": map[string]any{
   185  						"testfield": map[string]any{
   186  							"nestedtest": "test",
   187  						},
   188  						"testfield2": "test",
   189  					},
   190  				},
   191  			},
   192  			filteredFields:   []string{"spec.testfield.nestedtest"},
   193  			expectedFields:   []string{"spec.testfield.nestedtest"},
   194  			unexpectedFields: []string{"spec.testfield2"},
   195  		},
   196  	}
   197  
   198  	for _, tt := range tests {
   199  		t.Run(tt.name, func(t *testing.T) {
   200  			tt.obj.SetName("test-object")
   201  
   202  			filtered := filterFieldsFromObject(&tt.obj, tt.filteredFields)
   203  
   204  			for _, field := range tt.expectedFields {
   205  				fieldPath := strings.Split(field, ".")
   206  				_, exists, err := unstructured.NestedFieldCopy(filtered.Object, fieldPath...)
   207  				require.NoError(t, err)
   208  				assert.True(t, exists, "Expected field %s to exist", field)
   209  			}
   210  
   211  			for _, field := range tt.unexpectedFields {
   212  				fieldPath := strings.Split(field, ".")
   213  				_, exists, err := unstructured.NestedFieldCopy(filtered.Object, fieldPath...)
   214  				require.NoError(t, err)
   215  				assert.False(t, exists, "Expected field %s to not exist", field)
   216  			}
   217  
   218  			assert.Equal(t, tt.obj.GetName(), filtered.GetName())
   219  		})
   220  	}
   221  }
   222  
   223  func TestExtractNestedItem(t *testing.T) {
   224  	tests := []struct {
   225  		name     string
   226  		obj      map[string]any
   227  		fields   []string
   228  		depth    int
   229  		expected map[string]any
   230  	}{
   231  		{
   232  			name: "extract simple nested item",
   233  			obj: map[string]any{
   234  				"listofitems": []any{
   235  					map[string]any{
   236  						"extract":     "123",
   237  						"dontextract": "abc",
   238  					},
   239  					map[string]any{
   240  						"extract":     "456",
   241  						"dontextract": "def",
   242  					},
   243  					map[string]any{
   244  						"extract":     "789",
   245  						"dontextract": "ghi",
   246  					},
   247  				},
   248  			},
   249  			fields: []string{"listofitems", "extract"},
   250  			depth:  0,
   251  			expected: map[string]any{
   252  				"listofitems": []any{
   253  					map[string]any{
   254  						"extract": "123",
   255  					},
   256  					map[string]any{
   257  						"extract": "456",
   258  					},
   259  					map[string]any{
   260  						"extract": "789",
   261  					},
   262  				},
   263  			},
   264  		},
   265  		{
   266  			name: "double nested list of objects",
   267  			obj: map[string]any{
   268  				"listofitems": []any{
   269  					map[string]any{
   270  						"doublenested": []any{
   271  							map[string]any{
   272  								"extract": "123",
   273  							},
   274  						},
   275  						"dontextract": "abc",
   276  					},
   277  					map[string]any{
   278  						"doublenested": []any{
   279  							map[string]any{
   280  								"extract": "456",
   281  							},
   282  						},
   283  						"dontextract": "def",
   284  					},
   285  					map[string]any{
   286  						"doublenested": []any{
   287  							map[string]any{
   288  								"extract": "789",
   289  							},
   290  						},
   291  						"dontextract": "ghi",
   292  					},
   293  				},
   294  			},
   295  			fields: []string{"listofitems", "doublenested", "extract"},
   296  			depth:  0,
   297  			expected: map[string]any{
   298  				"listofitems": []any{
   299  					map[string]any{
   300  						"doublenested": []any{
   301  							map[string]any{
   302  								"extract": "123",
   303  							},
   304  						},
   305  					},
   306  					map[string]any{
   307  						"doublenested": []any{
   308  							map[string]any{
   309  								"extract": "456",
   310  							},
   311  						},
   312  					},
   313  					map[string]any{
   314  						"doublenested": []any{
   315  							map[string]any{
   316  								"extract": "789",
   317  							},
   318  						},
   319  					},
   320  				},
   321  			},
   322  		},
   323  		{
   324  			name:     "depth is greater then list of field size",
   325  			obj:      map[string]any{"test1": "1234567890"},
   326  			fields:   []string{"test1"},
   327  			depth:    4,
   328  			expected: nil,
   329  		},
   330  	}
   331  
   332  	for _, tt := range tests {
   333  		t.Run(tt.name, func(t *testing.T) {
   334  			filteredObj := extractNestedItem(tt.obj, tt.fields, tt.depth)
   335  			assert.Equal(t, tt.expected, filteredObj, "Did not get the correct filtered obj")
   336  		})
   337  	}
   338  }
   339  
   340  func TestExtractItemsFromList(t *testing.T) {
   341  	tests := []struct {
   342  		name     string
   343  		list     []any
   344  		fields   []string
   345  		expected []any
   346  	}{
   347  		{
   348  			name: "test simple field",
   349  			list: []any{
   350  				map[string]any{"extract": "value1", "dontextract": "valueA"},
   351  				map[string]any{"extract": "value2", "dontextract": "valueB"},
   352  				map[string]any{"extract": "value3", "dontextract": "valueC"},
   353  			},
   354  			fields: []string{"extract"},
   355  			expected: []any{
   356  				map[string]any{"extract": "value1"},
   357  				map[string]any{"extract": "value2"},
   358  				map[string]any{"extract": "value3"},
   359  			},
   360  		},
   361  		{
   362  			name: "test simple field with some depth",
   363  			list: []any{
   364  				map[string]any{
   365  					"test1": map[string]any{
   366  						"test2": map[string]any{
   367  							"extract":     "123",
   368  							"dontextract": "abc",
   369  						},
   370  					},
   371  				},
   372  				map[string]any{
   373  					"test1": map[string]any{
   374  						"test2": map[string]any{
   375  							"extract":     "456",
   376  							"dontextract": "def",
   377  						},
   378  					},
   379  				},
   380  				map[string]any{
   381  					"test1": map[string]any{
   382  						"test2": map[string]any{
   383  							"extract":     "789",
   384  							"dontextract": "ghi",
   385  						},
   386  					},
   387  				},
   388  			},
   389  			fields: []string{"test1", "test2", "extract"},
   390  			expected: []any{
   391  				map[string]any{
   392  					"test1": map[string]any{
   393  						"test2": map[string]any{
   394  							"extract": "123",
   395  						},
   396  					},
   397  				},
   398  				map[string]any{
   399  					"test1": map[string]any{
   400  						"test2": map[string]any{
   401  							"extract": "456",
   402  						},
   403  					},
   404  				},
   405  				map[string]any{
   406  					"test1": map[string]any{
   407  						"test2": map[string]any{
   408  							"extract": "789",
   409  						},
   410  					},
   411  				},
   412  			},
   413  		},
   414  		{
   415  			name: "test a missing field",
   416  			list: []any{
   417  				map[string]any{"test1": "123"},
   418  				map[string]any{"test1": "456"},
   419  				map[string]any{"test1": "789"},
   420  			},
   421  			fields:   []string{"test2"},
   422  			expected: nil,
   423  		},
   424  		{
   425  			name: "test getting an object",
   426  			list: []any{
   427  				map[string]any{
   428  					"extract": map[string]any{
   429  						"keyA": "valueA",
   430  						"keyB": "valueB",
   431  						"keyC": "valueC",
   432  					},
   433  					"dontextract": map[string]any{
   434  						"key1": "value1",
   435  						"key2": "value2",
   436  						"key3": "value3",
   437  					},
   438  				},
   439  				map[string]any{
   440  					"extract": map[string]any{
   441  						"keyD": "valueD",
   442  						"keyE": "valueE",
   443  						"keyF": "valueF",
   444  					},
   445  					"dontextract": map[string]any{
   446  						"key4": "value4",
   447  						"key5": "value5",
   448  						"key6": "value6",
   449  					},
   450  				},
   451  			},
   452  			fields: []string{"extract"},
   453  			expected: []any{
   454  				map[string]any{
   455  					"extract": map[string]any{
   456  						"keyA": "valueA",
   457  						"keyB": "valueB",
   458  						"keyC": "valueC",
   459  					},
   460  				},
   461  				map[string]any{
   462  					"extract": map[string]any{
   463  						"keyD": "valueD",
   464  						"keyE": "valueE",
   465  						"keyF": "valueF",
   466  					},
   467  				},
   468  			},
   469  		},
   470  	}
   471  
   472  	for _, tt := range tests {
   473  		t.Run(tt.name, func(t *testing.T) {
   474  			extractedList := extractItemsFromList(tt.list, tt.fields)
   475  			assert.Equal(t, tt.expected, extractedList, "Lists were not equal")
   476  		})
   477  	}
   478  }
   479  
   480  func TestReconstructObject(t *testing.T) {
   481  	tests := []struct {
   482  		name      string
   483  		extracted []any
   484  		fields    []string
   485  		depth     int
   486  		expected  map[string]any
   487  	}{
   488  		{
   489  			name:      "simple single field at depth 0",
   490  			extracted: []any{"value1", "value2"},
   491  			fields:    []string{"items"},
   492  			depth:     0,
   493  			expected: map[string]any{
   494  				"items": []any{"value1", "value2"},
   495  			},
   496  		},
   497  		{
   498  			name:      "object nested at depth 1",
   499  			extracted: []any{map[string]any{"key": "value"}},
   500  			fields:    []string{"test1", "test2"},
   501  			depth:     1,
   502  			expected: map[string]any{
   503  				"test1": map[string]any{
   504  					"test2": []any{map[string]any{"key": "value"}},
   505  				},
   506  			},
   507  		},
   508  		{
   509  			name:      "empty list of extracted items",
   510  			extracted: []any{},
   511  			fields:    []string{"test1"},
   512  			depth:     0,
   513  			expected: map[string]any{
   514  				"test1": []any{},
   515  			},
   516  		},
   517  		{
   518  			name: "complex object nesteed at depth 2",
   519  			extracted: []any{map[string]any{
   520  				"obj1": map[string]any{
   521  					"key1": "value1",
   522  					"key2": "value2",
   523  				},
   524  				"obj2": map[string]any{
   525  					"keyA": "valueA",
   526  					"keyB": "valueB",
   527  				},
   528  			}},
   529  			fields: []string{"test1", "test2", "test3"},
   530  			depth:  2,
   531  			expected: map[string]any{
   532  				"test1": map[string]any{
   533  					"test2": map[string]any{
   534  						"test3": []any{
   535  							map[string]any{
   536  								"obj1": map[string]any{
   537  									"key1": "value1",
   538  									"key2": "value2",
   539  								},
   540  								"obj2": map[string]any{
   541  									"keyA": "valueA",
   542  									"keyB": "valueB",
   543  								},
   544  							},
   545  						},
   546  					},
   547  				},
   548  			},
   549  		},
   550  	}
   551  
   552  	for _, tt := range tests {
   553  		t.Run(tt.name, func(t *testing.T) {
   554  			filteredObj := reconstructObject(tt.extracted, tt.fields, tt.depth)
   555  			assert.Equal(t, tt.expected, filteredObj, "objects were not equal")
   556  		})
   557  	}
   558  }
   559  
   560  func TestPrintManifests(t *testing.T) {
   561  	obj := unstructured.Unstructured{
   562  		Object: map[string]any{
   563  			"apiVersion": "vX",
   564  			"kind":       "test",
   565  			"metadata": map[string]any{
   566  				"name": "unit-test",
   567  			},
   568  			"spec": map[string]any{
   569  				"testfield": "testvalue",
   570  			},
   571  		},
   572  	}
   573  
   574  	expectedYAML := `apiVersion: vX
   575  kind: test
   576  metadata:
   577      name: unit-test
   578  spec:
   579      testfield: testvalue
   580  `
   581  
   582  	output, _ := captureOutput(func() error {
   583  		printManifests(&[]unstructured.Unstructured{obj}, false, true, "yaml")
   584  		return nil
   585  	})
   586  	assert.Equal(t, expectedYAML+"\n", output, "Incorrect yaml output for printManifests")
   587  
   588  	output, _ = captureOutput(func() error {
   589  		printManifests(&[]unstructured.Unstructured{obj, obj}, false, true, "yaml")
   590  		return nil
   591  	})
   592  	assert.Equal(t, expectedYAML+"\n---\n"+expectedYAML+"\n", output, "Incorrect yaml output with multiple objs.")
   593  
   594  	expectedJSON := `{
   595   "apiVersion": "vX",
   596   "kind": "test",
   597   "metadata": {
   598    "name": "unit-test"
   599   },
   600   "spec": {
   601    "testfield": "testvalue"
   602   }
   603  }`
   604  
   605  	output, _ = captureOutput(func() error {
   606  		printManifests(&[]unstructured.Unstructured{obj}, false, true, "json")
   607  		return nil
   608  	})
   609  	assert.Equal(t, expectedJSON+"\n", output, "Incorrect json output.")
   610  
   611  	output, _ = captureOutput(func() error {
   612  		printManifests(&[]unstructured.Unstructured{obj, obj}, false, true, "json")
   613  		return nil
   614  	})
   615  	assert.Equal(t, expectedJSON+"\n---\n"+expectedJSON+"\n", output, "Incorrect json output with multiple objs.")
   616  
   617  	output, _ = captureOutput(func() error {
   618  		printManifests(&[]unstructured.Unstructured{obj}, true, true, "wide")
   619  		return nil
   620  	})
   621  	assert.Contains(t, output, "FIELD           RESOURCE NAME  VALUE", "Missing or incorrect header line for table print with showing names.")
   622  	assert.Contains(t, output, "apiVersion      unit-test      vX", "Missing or incorrect row in table related to apiVersion with showing names.")
   623  	assert.Contains(t, output, "kind            unit-test      test", "Missing or incorrect line in the table related to kind with showing names.")
   624  	assert.Contains(t, output, "spec.testfield  unit-test      testvalue", "Missing or incorrect line in the table related to spec.testfield with showing names.")
   625  	assert.NotContains(t, output, "metadata.name   unit-test      testvalue", "Missing or incorrect line in the table related to metadata.name with showing names.")
   626  
   627  	output, _ = captureOutput(func() error {
   628  		printManifests(&[]unstructured.Unstructured{obj}, true, false, "wide")
   629  		return nil
   630  	})
   631  	assert.Contains(t, output, "FIELD           VALUE", "Missing or incorrect header line for table print with not showing names.")
   632  	assert.Contains(t, output, "apiVersion      vX", "Missing or incorrect row in table related to apiVersion with not showing names.")
   633  	assert.Contains(t, output, "kind            test", "Missing or incorrect row in the table related to kind with not showing names.")
   634  	assert.Contains(t, output, "spec.testfield  testvalue", "Missing or incorrect row in the table related to spec.testefield with not showing names.")
   635  	assert.NotContains(t, output, "metadata.name   testvalue", "Missing or incorrect row in the tbale related to metadata.name with not showing names.")
   636  }
   637  
   638  func TestPrintManifests_FilterNestedListObject_Wide(t *testing.T) {
   639  	obj := unstructured.Unstructured{
   640  		Object: map[string]any{
   641  			"apiVersion": "vX",
   642  			"kind":       "kind",
   643  			"metadata": map[string]any{
   644  				"name": "unit-test",
   645  			},
   646  			"status": map[string]any{
   647  				"podIPs": []map[string]any{
   648  					{
   649  						"IP": "127.0.0.1",
   650  					},
   651  					{
   652  						"IP": "127.0.0.2",
   653  					},
   654  				},
   655  			},
   656  		},
   657  	}
   658  
   659  	output, _ := captureOutput(func() error {
   660  		v, err := json.Marshal(&obj)
   661  		if err != nil {
   662  			return nil
   663  		}
   664  
   665  		var obj2 *unstructured.Unstructured
   666  		err = json.Unmarshal([]byte(v), &obj2)
   667  		if err != nil {
   668  			return nil
   669  		}
   670  		printManifests(&[]unstructured.Unstructured{*obj2}, false, true, "wide")
   671  		return nil
   672  	})
   673  
   674  	// Verify table header
   675  	assert.Contains(t, output, "FIELD                RESOURCE NAME  VALUE", "Missing a line in the table")
   676  	assert.Contains(t, output, "apiVersion           unit-test      vX", "Test for apiVersion field failed for wide output")
   677  	assert.Contains(t, output, "kind                 unit-test      kind", "Test for kind field failed for wide output")
   678  	assert.Contains(t, output, "status.podIPs[0].IP  unit-test      127.0.0.1", "Test for podIP array index 0 field failed for wide output")
   679  	assert.Contains(t, output, "status.podIPs[1].IP  unit-test      127.0.0.2", "Test for podIP array index 1 field failed for wide output")
   680  }