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

     1  package commands
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"os"
    10  	"slices"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/argoproj/gitops-engine/pkg/health"
    16  	"github.com/argoproj/gitops-engine/pkg/utils/kube"
    17  	"github.com/coreos/go-oidc/v3/oidc"
    18  	"github.com/google/go-cmp/cmp"
    19  	"github.com/google/go-cmp/cmp/cmpopts"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  	"golang.org/x/oauth2"
    23  	"google.golang.org/grpc"
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    27  	"k8s.io/apimachinery/pkg/runtime"
    28  	"k8s.io/apimachinery/pkg/util/intstr"
    29  	"k8s.io/apimachinery/pkg/watch"
    30  	"sigs.k8s.io/yaml"
    31  
    32  	argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
    33  	accountpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/account"
    34  	applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application"
    35  	applicationsetpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/applicationset"
    36  	certificatepkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/certificate"
    37  	clusterpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster"
    38  	gpgkeypkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/gpgkey"
    39  	notificationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/notification"
    40  	projectpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/project"
    41  	repocredspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repocreds"
    42  	repositorypkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repository"
    43  	sessionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/session"
    44  	settingspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/settings"
    45  	versionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/version"
    46  	"github.com/argoproj/argo-cd/v3/pkg/apis/application"
    47  	"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    48  	"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
    49  )
    50  
    51  func Test_getInfos(t *testing.T) {
    52  	testCases := []struct {
    53  		name          string
    54  		infos         []string
    55  		expectedInfos []*v1alpha1.Info
    56  	}{
    57  		{
    58  			name:          "empty",
    59  			infos:         []string{},
    60  			expectedInfos: []*v1alpha1.Info{},
    61  		},
    62  		{
    63  			name:  "simple key value",
    64  			infos: []string{"key1=value1", "key2=value2"},
    65  			expectedInfos: []*v1alpha1.Info{
    66  				{Name: "key1", Value: "value1"},
    67  				{Name: "key2", Value: "value2"},
    68  			},
    69  		},
    70  	}
    71  
    72  	for _, testCase := range testCases {
    73  		t.Run(testCase.name, func(t *testing.T) {
    74  			infos := getInfos(testCase.infos)
    75  			assert.Len(t, infos, len(testCase.expectedInfos))
    76  			sort := func(a, b *v1alpha1.Info) bool { return a.Name < b.Name }
    77  			assert.Empty(t, cmp.Diff(testCase.expectedInfos, infos, cmpopts.SortSlices(sort)))
    78  		})
    79  	}
    80  }
    81  
    82  func Test_getRefreshType(t *testing.T) {
    83  	refreshTypeNormal := string(v1alpha1.RefreshTypeNormal)
    84  	refreshTypeHard := string(v1alpha1.RefreshTypeHard)
    85  	testCases := []struct {
    86  		refresh     bool
    87  		hardRefresh bool
    88  		expected    *string
    89  	}{
    90  		{false, false, nil},
    91  		{false, true, &refreshTypeHard},
    92  		{true, false, &refreshTypeNormal},
    93  		{true, true, &refreshTypeHard},
    94  	}
    95  
    96  	for _, testCase := range testCases {
    97  		t.Run(fmt.Sprintf("hardRefresh=%t refresh=%t", testCase.hardRefresh, testCase.refresh), func(t *testing.T) {
    98  			refreshType := getRefreshType(testCase.refresh, testCase.hardRefresh)
    99  			if testCase.expected == nil {
   100  				assert.Nil(t, refreshType)
   101  			} else {
   102  				assert.NotNil(t, refreshType)
   103  				assert.Equal(t, *testCase.expected, *refreshType)
   104  			}
   105  		})
   106  	}
   107  }
   108  
   109  func TestFindRevisionHistoryWithoutPassedId(t *testing.T) {
   110  	histories := v1alpha1.RevisionHistories{}
   111  
   112  	histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
   113  	histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
   114  	histories = append(histories, v1alpha1.RevisionHistory{ID: 3})
   115  
   116  	status := v1alpha1.ApplicationStatus{
   117  		Resources:      nil,
   118  		Sync:           v1alpha1.SyncStatus{},
   119  		Health:         v1alpha1.AppHealthStatus{},
   120  		History:        histories,
   121  		Conditions:     nil,
   122  		ReconciledAt:   nil,
   123  		OperationState: nil,
   124  		ObservedAt:     nil,
   125  		SourceType:     "",
   126  		Summary:        v1alpha1.ApplicationSummary{},
   127  	}
   128  
   129  	application := v1alpha1.Application{
   130  		Status: status,
   131  	}
   132  
   133  	history, err := findRevisionHistory(&application, -1)
   134  	require.NoError(t, err, "Find revision history should fail without errors")
   135  	require.NotNil(t, history, "History should be found")
   136  }
   137  
   138  func TestPrintTreeViewAppGet(t *testing.T) {
   139  	var nodes [3]v1alpha1.ResourceNode
   140  	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"}
   141  	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"}}
   142  	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"}
   143  	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"}}
   144  	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"}
   145  
   146  	nodeMapping := make(map[string]v1alpha1.ResourceNode)
   147  	mapParentToChild := make(map[string][]string)
   148  	parentNode := make(map[string]struct{})
   149  
   150  	for _, node := range nodes {
   151  		nodeMapping[node.UID] = node
   152  
   153  		if len(node.ParentRefs) > 0 {
   154  			_, ok := mapParentToChild[node.ParentRefs[0].UID]
   155  			if !ok {
   156  				var temp []string
   157  				mapParentToChild[node.ParentRefs[0].UID] = temp
   158  			}
   159  			mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
   160  		} else {
   161  			parentNode[node.UID] = struct{}{}
   162  		}
   163  	}
   164  
   165  	output, _ := captureOutput(func() error {
   166  		printTreeView(nodeMapping, mapParentToChild, parentNode, nil)
   167  		return nil
   168  	})
   169  
   170  	assert.Contains(t, output, "Pod")
   171  	assert.Contains(t, output, "ReplicaSet")
   172  	assert.Contains(t, output, "Rollout")
   173  	assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt")
   174  }
   175  
   176  func TestPrintTreeViewDetailedAppGet(t *testing.T) {
   177  	var nodes [3]v1alpha1.ResourceNode
   178  	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"}
   179  	nodes[0].Health = &v1alpha1.HealthStatus{Status: "Degraded", Message: "Readiness Gate failed"}
   180  	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"}}
   181  	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"}
   182  	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"}}
   183  	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"}
   184  
   185  	nodeMapping := make(map[string]v1alpha1.ResourceNode)
   186  	mapParentToChild := make(map[string][]string)
   187  	parentNode := make(map[string]struct{})
   188  
   189  	for _, node := range nodes {
   190  		nodeMapping[node.UID] = node
   191  
   192  		if len(node.ParentRefs) > 0 {
   193  			_, ok := mapParentToChild[node.ParentRefs[0].UID]
   194  			if !ok {
   195  				var temp []string
   196  				mapParentToChild[node.ParentRefs[0].UID] = temp
   197  			}
   198  			mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
   199  		} else {
   200  			parentNode[node.UID] = struct{}{}
   201  		}
   202  	}
   203  
   204  	output, _ := captureOutput(func() error {
   205  		printTreeViewDetailed(nodeMapping, mapParentToChild, parentNode, nil)
   206  		return nil
   207  	})
   208  
   209  	assert.Contains(t, output, "Pod")
   210  	assert.Contains(t, output, "ReplicaSet")
   211  	assert.Contains(t, output, "Rollout")
   212  	assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt")
   213  	assert.Contains(t, output, "Degraded")
   214  	assert.Contains(t, output, "Readiness Gate failed")
   215  }
   216  
   217  func TestFindRevisionHistoryWithoutPassedIdWithMultipleSources(t *testing.T) {
   218  	histories := v1alpha1.RevisionHistories{}
   219  
   220  	histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
   221  	histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
   222  	histories = append(histories, v1alpha1.RevisionHistory{ID: 3})
   223  
   224  	status := v1alpha1.ApplicationStatus{
   225  		Resources:      nil,
   226  		Sync:           v1alpha1.SyncStatus{},
   227  		Health:         v1alpha1.AppHealthStatus{},
   228  		History:        histories,
   229  		Conditions:     nil,
   230  		ReconciledAt:   nil,
   231  		OperationState: nil,
   232  		ObservedAt:     nil,
   233  		SourceType:     "",
   234  		Summary:        v1alpha1.ApplicationSummary{},
   235  	}
   236  
   237  	application := v1alpha1.Application{
   238  		Status: status,
   239  	}
   240  
   241  	history, err := findRevisionHistory(&application, -1)
   242  	require.NoError(t, err, "Find revision history should fail without errors")
   243  	require.NotNil(t, history, "History should be found")
   244  }
   245  
   246  func TestDefaultWaitOptions(t *testing.T) {
   247  	watch := watchOpts{
   248  		sync:      false,
   249  		health:    false,
   250  		operation: false,
   251  		suspended: false,
   252  	}
   253  	opts := getWatchOpts(watch)
   254  	assert.True(t, opts.sync)
   255  	assert.True(t, opts.health)
   256  	assert.True(t, opts.operation)
   257  	assert.False(t, opts.suspended)
   258  }
   259  
   260  func TestOverrideWaitOptions(t *testing.T) {
   261  	watch := watchOpts{
   262  		sync:      true,
   263  		health:    false,
   264  		operation: false,
   265  		suspended: false,
   266  	}
   267  	opts := getWatchOpts(watch)
   268  	assert.True(t, opts.sync)
   269  	assert.False(t, opts.health)
   270  	assert.False(t, opts.operation)
   271  	assert.False(t, opts.suspended)
   272  }
   273  
   274  func TestFindRevisionHistoryWithoutPassedIdAndEmptyHistoryList(t *testing.T) {
   275  	histories := v1alpha1.RevisionHistories{}
   276  
   277  	status := v1alpha1.ApplicationStatus{
   278  		Resources:      nil,
   279  		Sync:           v1alpha1.SyncStatus{},
   280  		Health:         v1alpha1.AppHealthStatus{},
   281  		History:        histories,
   282  		Conditions:     nil,
   283  		ReconciledAt:   nil,
   284  		OperationState: nil,
   285  		ObservedAt:     nil,
   286  		SourceType:     "",
   287  		Summary:        v1alpha1.ApplicationSummary{},
   288  	}
   289  
   290  	application := v1alpha1.Application{
   291  		Status: status,
   292  	}
   293  
   294  	history, err := findRevisionHistory(&application, -1)
   295  
   296  	require.Error(t, err, "Find revision history should fail with errors")
   297  	require.Nil(t, history, "History should be empty")
   298  	require.EqualError(t, err, "application '' should have at least two successful deployments", "Find revision history should fail with correct error message")
   299  }
   300  
   301  func TestFindRevisionHistoryWithPassedId(t *testing.T) {
   302  	histories := v1alpha1.RevisionHistories{}
   303  
   304  	histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
   305  	histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
   306  	histories = append(histories, v1alpha1.RevisionHistory{ID: 3, Revision: "123"})
   307  
   308  	status := v1alpha1.ApplicationStatus{
   309  		Resources:      nil,
   310  		Sync:           v1alpha1.SyncStatus{},
   311  		Health:         v1alpha1.AppHealthStatus{},
   312  		History:        histories,
   313  		Conditions:     nil,
   314  		ReconciledAt:   nil,
   315  		OperationState: nil,
   316  		ObservedAt:     nil,
   317  		SourceType:     "",
   318  		Summary:        v1alpha1.ApplicationSummary{},
   319  	}
   320  
   321  	application := v1alpha1.Application{
   322  		Status: status,
   323  	}
   324  
   325  	history, err := findRevisionHistory(&application, 3)
   326  	require.NoError(t, err, "Find revision history should fail without errors")
   327  	require.NotNil(t, history, "History should be found")
   328  	require.Equal(t, "123", history.Revision, "Failed to find correct history with correct revision")
   329  }
   330  
   331  func TestFindRevisionHistoryWithPassedIdThatNotExist(t *testing.T) {
   332  	histories := v1alpha1.RevisionHistories{}
   333  
   334  	histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
   335  	histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
   336  	histories = append(histories, v1alpha1.RevisionHistory{ID: 3, Revision: "123"})
   337  
   338  	status := v1alpha1.ApplicationStatus{
   339  		Resources:      nil,
   340  		Sync:           v1alpha1.SyncStatus{},
   341  		Health:         v1alpha1.AppHealthStatus{},
   342  		History:        histories,
   343  		Conditions:     nil,
   344  		ReconciledAt:   nil,
   345  		OperationState: nil,
   346  		ObservedAt:     nil,
   347  		SourceType:     "",
   348  		Summary:        v1alpha1.ApplicationSummary{},
   349  	}
   350  
   351  	application := v1alpha1.Application{
   352  		Status: status,
   353  	}
   354  
   355  	history, err := findRevisionHistory(&application, 4)
   356  
   357  	require.Error(t, err, "Find revision history should fail with errors")
   358  	require.Nil(t, history, "History should be not found")
   359  	require.EqualError(t, err, "application '' does not have deployment id '4' in history", "Find revision history should fail with correct error message")
   360  }
   361  
   362  func Test_groupObjsByKey(t *testing.T) {
   363  	localObjs := []*unstructured.Unstructured{
   364  		{
   365  			Object: map[string]any{
   366  				"apiVersion": "v1",
   367  				"kind":       "Pod",
   368  				"metadata": map[string]any{
   369  					"name":      "pod-name",
   370  					"namespace": "default",
   371  				},
   372  			},
   373  		},
   374  		{
   375  			Object: map[string]any{
   376  				"apiVersion": "apiextensions.k8s.io/v1",
   377  				"kind":       "CustomResourceDefinition",
   378  				"metadata": map[string]any{
   379  					"name": "certificates.cert-manager.io",
   380  				},
   381  			},
   382  		},
   383  	}
   384  	liveObjs := []*unstructured.Unstructured{
   385  		{
   386  			Object: map[string]any{
   387  				"apiVersion": "v1",
   388  				"kind":       "Pod",
   389  				"metadata": map[string]any{
   390  					"name":      "pod-name",
   391  					"namespace": "default",
   392  				},
   393  			},
   394  		},
   395  		{
   396  			Object: map[string]any{
   397  				"apiVersion": "apiextensions.k8s.io/v1",
   398  				"kind":       "CustomResourceDefinition",
   399  				"metadata": map[string]any{
   400  					"name": "certificates.cert-manager.io",
   401  				},
   402  			},
   403  		},
   404  	}
   405  
   406  	expected := map[kube.ResourceKey]*unstructured.Unstructured{
   407  		{Group: "", Kind: "Pod", Namespace: "default", Name: "pod-name"}:                                                       localObjs[0],
   408  		{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition", Namespace: "", Name: "certificates.cert-manager.io"}: localObjs[1],
   409  	}
   410  
   411  	objByKey := groupObjsByKey(localObjs, liveObjs, "default")
   412  	assert.Equal(t, expected, objByKey)
   413  }
   414  
   415  func TestFormatSyncPolicy(t *testing.T) {
   416  	t.Run("Policy not defined", func(t *testing.T) {
   417  		app := v1alpha1.Application{}
   418  
   419  		policy := formatSyncPolicy(app)
   420  
   421  		require.Equalf(t, "Manual", policy, "Incorrect policy %q, should be Manual", policy)
   422  	})
   423  
   424  	t.Run("Auto policy", func(t *testing.T) {
   425  		app := v1alpha1.Application{
   426  			Spec: v1alpha1.ApplicationSpec{
   427  				SyncPolicy: &v1alpha1.SyncPolicy{
   428  					Automated: &v1alpha1.SyncPolicyAutomated{},
   429  				},
   430  			},
   431  		}
   432  
   433  		policy := formatSyncPolicy(app)
   434  
   435  		require.Equalf(t, "Auto", policy, "Incorrect policy %q, should be Auto", policy)
   436  	})
   437  
   438  	t.Run("Auto policy with prune", func(t *testing.T) {
   439  		app := v1alpha1.Application{
   440  			Spec: v1alpha1.ApplicationSpec{
   441  				SyncPolicy: &v1alpha1.SyncPolicy{
   442  					Automated: &v1alpha1.SyncPolicyAutomated{
   443  						Prune: true,
   444  					},
   445  				},
   446  			},
   447  		}
   448  
   449  		policy := formatSyncPolicy(app)
   450  
   451  		require.Equalf(t, "Auto-Prune", policy, "Incorrect policy %q, should be Auto-Prune", policy)
   452  	})
   453  }
   454  
   455  func TestFormatConditionSummary(t *testing.T) {
   456  	t.Run("No conditions are defined", func(t *testing.T) {
   457  		app := v1alpha1.Application{
   458  			Spec: v1alpha1.ApplicationSpec{
   459  				SyncPolicy: &v1alpha1.SyncPolicy{
   460  					Automated: &v1alpha1.SyncPolicyAutomated{
   461  						Prune: true,
   462  					},
   463  				},
   464  			},
   465  		}
   466  
   467  		summary := formatConditionsSummary(app)
   468  		require.Equalf(t, "<none>", summary, "Incorrect summary %q, should be <none>", summary)
   469  	})
   470  
   471  	t.Run("Few conditions are defined", func(t *testing.T) {
   472  		app := v1alpha1.Application{
   473  			Status: v1alpha1.ApplicationStatus{
   474  				Conditions: []v1alpha1.ApplicationCondition{
   475  					{
   476  						Type: "type1",
   477  					},
   478  					{
   479  						Type: "type1",
   480  					},
   481  					{
   482  						Type: "type2",
   483  					},
   484  				},
   485  			},
   486  		}
   487  
   488  		summary := formatConditionsSummary(app)
   489  		require.Equalf(t, "type1(2),type2", summary, "Incorrect summary %q, should be type1(2),type2", summary)
   490  	})
   491  
   492  	t.Run("Conditions are sorted for idempotent summary", func(t *testing.T) {
   493  		app := v1alpha1.Application{
   494  			Status: v1alpha1.ApplicationStatus{
   495  				Conditions: []v1alpha1.ApplicationCondition{
   496  					{
   497  						Type: "type2",
   498  					},
   499  					{
   500  						Type: "type1",
   501  					},
   502  					{
   503  						Type: "type1",
   504  					},
   505  				},
   506  			},
   507  		}
   508  
   509  		summary := formatConditionsSummary(app)
   510  		require.Equalf(t, "type1(2),type2", summary, "Incorrect summary %q, should be type1(2),type2", summary)
   511  	})
   512  }
   513  
   514  func TestPrintOperationResult(t *testing.T) {
   515  	t.Run("Operation state is empty", func(t *testing.T) {
   516  		output, _ := captureOutput(func() error {
   517  			printOperationResult(nil)
   518  			return nil
   519  		})
   520  
   521  		require.Emptyf(t, output, "Incorrect print operation output %q, should be ''", output)
   522  	})
   523  
   524  	t.Run("Operation state sync result is not empty", func(t *testing.T) {
   525  		time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
   526  		output, _ := captureOutput(func() error {
   527  			printOperationResult(&v1alpha1.OperationState{
   528  				SyncResult: &v1alpha1.SyncOperationResult{Revision: "revision"},
   529  				FinishedAt: &time,
   530  			})
   531  			return nil
   532  		})
   533  
   534  		expectation := "Operation:          Sync\nSync Revision:      revision\nPhase:              \nStart:              0001-01-01 00:00:00 +0000 UTC\nFinished:           2020-11-10 23:00:00 +0000 UTC\nDuration:           2333448h16m18.871345152s\n"
   535  		require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
   536  	})
   537  
   538  	t.Run("Operation state sync result with message is not empty", func(t *testing.T) {
   539  		time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
   540  		output, _ := captureOutput(func() error {
   541  			printOperationResult(&v1alpha1.OperationState{
   542  				SyncResult: &v1alpha1.SyncOperationResult{Revision: "revision"},
   543  				FinishedAt: &time,
   544  				Message:    "test",
   545  			})
   546  			return nil
   547  		})
   548  
   549  		expectation := "Operation:          Sync\nSync Revision:      revision\nPhase:              \nStart:              0001-01-01 00:00:00 +0000 UTC\nFinished:           2020-11-10 23:00:00 +0000 UTC\nDuration:           2333448h16m18.871345152s\nMessage:            test\n"
   550  		require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
   551  	})
   552  }
   553  
   554  func TestPrintApplicationHistoryTable(t *testing.T) {
   555  	histories := []v1alpha1.RevisionHistory{
   556  		{
   557  			ID: 1,
   558  			Source: v1alpha1.ApplicationSource{
   559  				TargetRevision: "1",
   560  				RepoURL:        "test",
   561  			},
   562  		},
   563  		{
   564  			ID: 2,
   565  			Source: v1alpha1.ApplicationSource{
   566  				TargetRevision: "2",
   567  				RepoURL:        "test",
   568  			},
   569  		},
   570  		{
   571  			ID: 3,
   572  			Source: v1alpha1.ApplicationSource{
   573  				TargetRevision: "3",
   574  				RepoURL:        "test",
   575  			},
   576  		},
   577  	}
   578  
   579  	output, _ := captureOutput(func() error {
   580  		printApplicationHistoryTable(histories)
   581  		return nil
   582  	})
   583  
   584  	expectation := "SOURCE  test\nID      DATE                           REVISION\n1       0001-01-01 00:00:00 +0000 UTC  1\n2       0001-01-01 00:00:00 +0000 UTC  2\n3       0001-01-01 00:00:00 +0000 UTC  3\n"
   585  
   586  	require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
   587  }
   588  
   589  func TestPrintApplicationHistoryTableWithMultipleSources(t *testing.T) {
   590  	histories := []v1alpha1.RevisionHistory{
   591  		{
   592  			ID: 0,
   593  			Source: v1alpha1.ApplicationSource{
   594  				TargetRevision: "0",
   595  				RepoURL:        "test",
   596  			},
   597  		},
   598  		{
   599  			ID: 1,
   600  			Revisions: []string{
   601  				"1a",
   602  				"1b",
   603  			},
   604  			// added Source just for testing the fuction
   605  			Source: v1alpha1.ApplicationSource{
   606  				TargetRevision: "-1",
   607  				RepoURL:        "ignore",
   608  			},
   609  			Sources: v1alpha1.ApplicationSources{
   610  				v1alpha1.ApplicationSource{
   611  					RepoURL:        "test-1",
   612  					TargetRevision: "1a",
   613  				},
   614  				v1alpha1.ApplicationSource{
   615  					RepoURL:        "test-2",
   616  					TargetRevision: "1b",
   617  				},
   618  			},
   619  		},
   620  		{
   621  			ID: 2,
   622  			Revisions: []string{
   623  				"2a",
   624  				"2b",
   625  			},
   626  			Sources: v1alpha1.ApplicationSources{
   627  				v1alpha1.ApplicationSource{
   628  					RepoURL:        "test-1",
   629  					TargetRevision: "2a",
   630  				},
   631  				v1alpha1.ApplicationSource{
   632  					RepoURL:        "test-2",
   633  					TargetRevision: "2b",
   634  				},
   635  			},
   636  		},
   637  		{
   638  			ID: 3,
   639  			Revisions: []string{
   640  				"3a",
   641  				"3b",
   642  			},
   643  			Sources: v1alpha1.ApplicationSources{
   644  				v1alpha1.ApplicationSource{
   645  					RepoURL:        "test-1",
   646  					TargetRevision: "3a",
   647  				},
   648  				v1alpha1.ApplicationSource{
   649  					RepoURL:        "test-2",
   650  					TargetRevision: "3b",
   651  				},
   652  			},
   653  		},
   654  	}
   655  
   656  	output, _ := captureOutput(func() error {
   657  		printApplicationHistoryTable(histories)
   658  		return nil
   659  	})
   660  
   661  	expectation := "SOURCE  test\nID      DATE                           REVISION\n0       0001-01-01 00:00:00 +0000 UTC  0\n\nSOURCE  test-1\nID      DATE                           REVISION\n1       0001-01-01 00:00:00 +0000 UTC  1a\n2       0001-01-01 00:00:00 +0000 UTC  2a\n3       0001-01-01 00:00:00 +0000 UTC  3a\n\nSOURCE  test-2\nID      DATE                           REVISION\n1       0001-01-01 00:00:00 +0000 UTC  1b\n2       0001-01-01 00:00:00 +0000 UTC  2b\n3       0001-01-01 00:00:00 +0000 UTC  3b\n"
   662  
   663  	require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
   664  }
   665  
   666  func TestPrintAppSummaryTable(t *testing.T) {
   667  	output, _ := captureOutput(func() error {
   668  		app := &v1alpha1.Application{
   669  			ObjectMeta: metav1.ObjectMeta{
   670  				Name:      "test",
   671  				Namespace: "argocd",
   672  			},
   673  			Spec: v1alpha1.ApplicationSpec{
   674  				SyncPolicy: &v1alpha1.SyncPolicy{
   675  					Automated: &v1alpha1.SyncPolicyAutomated{
   676  						Prune: true,
   677  					},
   678  				},
   679  				Project:     "default",
   680  				Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
   681  				Source: &v1alpha1.ApplicationSource{
   682  					RepoURL:        "test",
   683  					TargetRevision: "master",
   684  					Path:           "/test",
   685  					Helm: &v1alpha1.ApplicationSourceHelm{
   686  						ValueFiles: []string{"path1", "path2"},
   687  					},
   688  					Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
   689  				},
   690  			},
   691  			Status: v1alpha1.ApplicationStatus{
   692  				Sync: v1alpha1.SyncStatus{
   693  					Status: v1alpha1.SyncStatusCodeOutOfSync,
   694  				},
   695  				Health: v1alpha1.AppHealthStatus{
   696  					Status: health.HealthStatusProgressing,
   697  				},
   698  			},
   699  		}
   700  
   701  		windows := &v1alpha1.SyncWindows{
   702  			{
   703  				Kind:     "allow",
   704  				Schedule: "0 0 * * *",
   705  				Duration: "24h",
   706  				Applications: []string{
   707  					"*-prod",
   708  				},
   709  				ManualSync: true,
   710  			},
   711  			{
   712  				Kind:     "deny",
   713  				Schedule: "0 0 * * *",
   714  				Duration: "24h",
   715  				Namespaces: []string{
   716  					"default",
   717  				},
   718  			},
   719  			{
   720  				Kind:     "allow",
   721  				Schedule: "0 0 * * *",
   722  				Duration: "24h",
   723  				Clusters: []string{
   724  					"in-cluster",
   725  					"cluster1",
   726  				},
   727  			},
   728  		}
   729  
   730  		printAppSummaryTable(app, "url", windows)
   731  		return nil
   732  	})
   733  
   734  	expectation := `Name:               argocd/test
   735  Project:            default
   736  Server:             local
   737  Namespace:          argocd
   738  URL:                url
   739  Source:
   740  - Repo:             test
   741    Target:           master
   742    Path:             /test
   743    Helm Values:      path1,path2
   744    Name Prefix:      prefix
   745  SyncWindow:         Sync Denied
   746  Assigned Windows:   allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
   747  Sync Policy:        Automated (Prune)
   748  Sync Status:        OutOfSync from master
   749  Health Status:      Progressing
   750  `
   751  	assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation)
   752  }
   753  
   754  func TestPrintAppSummaryTable_MultipleSources(t *testing.T) {
   755  	output, _ := captureOutput(func() error {
   756  		app := &v1alpha1.Application{
   757  			ObjectMeta: metav1.ObjectMeta{
   758  				Name:      "test",
   759  				Namespace: "argocd",
   760  			},
   761  			Spec: v1alpha1.ApplicationSpec{
   762  				SyncPolicy: &v1alpha1.SyncPolicy{
   763  					Automated: &v1alpha1.SyncPolicyAutomated{
   764  						Prune: true,
   765  					},
   766  				},
   767  				Project:     "default",
   768  				Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
   769  				Sources: v1alpha1.ApplicationSources{
   770  					{
   771  						RepoURL:        "test",
   772  						TargetRevision: "master",
   773  						Path:           "/test",
   774  						Helm: &v1alpha1.ApplicationSourceHelm{
   775  							ValueFiles: []string{"path1", "path2"},
   776  						},
   777  						Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
   778  					}, {
   779  						RepoURL:        "test2",
   780  						TargetRevision: "master2",
   781  						Path:           "/test2",
   782  					},
   783  				},
   784  			},
   785  			Status: v1alpha1.ApplicationStatus{
   786  				Sync: v1alpha1.SyncStatus{
   787  					Status: v1alpha1.SyncStatusCodeOutOfSync,
   788  				},
   789  				Health: v1alpha1.AppHealthStatus{
   790  					Status: health.HealthStatusProgressing,
   791  				},
   792  			},
   793  		}
   794  
   795  		windows := &v1alpha1.SyncWindows{
   796  			{
   797  				Kind:     "allow",
   798  				Schedule: "0 0 * * *",
   799  				Duration: "24h",
   800  				Applications: []string{
   801  					"*-prod",
   802  				},
   803  				ManualSync: true,
   804  			},
   805  			{
   806  				Kind:     "deny",
   807  				Schedule: "0 0 * * *",
   808  				Duration: "24h",
   809  				Namespaces: []string{
   810  					"default",
   811  				},
   812  			},
   813  			{
   814  				Kind:     "allow",
   815  				Schedule: "0 0 * * *",
   816  				Duration: "24h",
   817  				Clusters: []string{
   818  					"in-cluster",
   819  					"cluster1",
   820  				},
   821  			},
   822  		}
   823  
   824  		printAppSummaryTable(app, "url", windows)
   825  		return nil
   826  	})
   827  
   828  	expectation := `Name:               argocd/test
   829  Project:            default
   830  Server:             local
   831  Namespace:          argocd
   832  URL:                url
   833  Sources:
   834  - Repo:             test
   835    Target:           master
   836    Path:             /test
   837    Helm Values:      path1,path2
   838    Name Prefix:      prefix
   839  - Repo:             test2
   840    Target:           master2
   841    Path:             /test2
   842  SyncWindow:         Sync Denied
   843  Assigned Windows:   allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
   844  Sync Policy:        Automated (Prune)
   845  Sync Status:        OutOfSync from master
   846  Health Status:      Progressing
   847  `
   848  	assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation)
   849  }
   850  
   851  func TestPrintAppConditions(t *testing.T) {
   852  	output, _ := captureOutput(func() error {
   853  		app := &v1alpha1.Application{
   854  			Status: v1alpha1.ApplicationStatus{
   855  				Conditions: []v1alpha1.ApplicationCondition{
   856  					{
   857  						Type:    v1alpha1.ApplicationConditionDeletionError,
   858  						Message: "test",
   859  					},
   860  					{
   861  						Type:    v1alpha1.ApplicationConditionExcludedResourceWarning,
   862  						Message: "test2",
   863  					},
   864  					{
   865  						Type:    v1alpha1.ApplicationConditionRepeatedResourceWarning,
   866  						Message: "test3",
   867  					},
   868  				},
   869  			},
   870  		}
   871  		printAppConditions(os.Stdout, app)
   872  		return nil
   873  	})
   874  	expectation := "CONDITION\tMESSAGE\tLAST TRANSITION\nDeletionError\ttest\t<nil>\nExcludedResourceWarning\ttest2\t<nil>\nRepeatedResourceWarning\ttest3\t<nil>\n"
   875  	require.Equalf(t, output, expectation, "Incorrect print app conditions output %q, should be %q", output, expectation)
   876  }
   877  
   878  func TestPrintParams(t *testing.T) {
   879  	testCases := []struct {
   880  		name           string
   881  		app            *v1alpha1.Application
   882  		sourcePosition int
   883  		expectedOutput string
   884  	}{
   885  		{
   886  			name: "Single Source application with valid helm parameters",
   887  			app: &v1alpha1.Application{
   888  				Spec: v1alpha1.ApplicationSpec{
   889  					Source: &v1alpha1.ApplicationSource{
   890  						Helm: &v1alpha1.ApplicationSourceHelm{
   891  							Parameters: []v1alpha1.HelmParameter{
   892  								{
   893  									Name:  "name1",
   894  									Value: "value1",
   895  								},
   896  								{
   897  									Name:  "name2",
   898  									Value: "value2",
   899  								},
   900  								{
   901  									Name:  "name3",
   902  									Value: "value3",
   903  								},
   904  							},
   905  						},
   906  					},
   907  				},
   908  			},
   909  			sourcePosition: -1,
   910  			expectedOutput: "\n\nNAME   VALUE\nname1  value1\nname2  value2\nname3  value3\n",
   911  		},
   912  		{
   913  			name: "Multi-source application with a valid Source Position",
   914  			app: &v1alpha1.Application{
   915  				Spec: v1alpha1.ApplicationSpec{
   916  					Sources: []v1alpha1.ApplicationSource{
   917  						{
   918  							Helm: &v1alpha1.ApplicationSourceHelm{
   919  								Parameters: []v1alpha1.HelmParameter{
   920  									{
   921  										Name:  "nameA",
   922  										Value: "valueA",
   923  									},
   924  								},
   925  							},
   926  						},
   927  						{
   928  							Helm: &v1alpha1.ApplicationSourceHelm{
   929  								Parameters: []v1alpha1.HelmParameter{
   930  									{
   931  										Name:  "nameB",
   932  										Value: "valueB",
   933  									},
   934  								},
   935  							},
   936  						},
   937  					},
   938  				},
   939  			},
   940  			sourcePosition: 1,
   941  			expectedOutput: "\n\nNAME   VALUE\nnameA  valueA\n",
   942  		},
   943  	}
   944  
   945  	for _, tc := range testCases {
   946  		t.Run(tc.name, func(t *testing.T) {
   947  			output, _ := captureOutput(func() error {
   948  				printParams(tc.app, tc.sourcePosition)
   949  				return nil
   950  			})
   951  
   952  			require.Equalf(t, tc.expectedOutput, output, "Incorrect print params output %q, should be %q\n", output, tc.expectedOutput)
   953  		})
   954  	}
   955  }
   956  
   957  func TestAppUrlDefault(t *testing.T) {
   958  	t.Run("Plain text", func(t *testing.T) {
   959  		result := appURLDefault(argocdclient.NewClientOrDie(&argocdclient.ClientOptions{
   960  			ServerAddr: "localhost:80",
   961  			PlainText:  true,
   962  		}), "test")
   963  		expectation := "http://localhost:80/applications/test"
   964  		require.Equalf(t, result, expectation, "Incorrect url %q, should be %q", result, expectation)
   965  	})
   966  	t.Run("https", func(t *testing.T) {
   967  		result := appURLDefault(argocdclient.NewClientOrDie(&argocdclient.ClientOptions{
   968  			ServerAddr: "localhost:443",
   969  			PlainText:  false,
   970  		}), "test")
   971  		expectation := "https://localhost/applications/test"
   972  		require.Equalf(t, result, expectation, "Incorrect url %q, should be %q", result, expectation)
   973  	})
   974  }
   975  
   976  func TestTruncateString(t *testing.T) {
   977  	result := truncateString("argocdtool", 2)
   978  	expectation := "ar..."
   979  	require.Equalf(t, result, expectation, "Incorrect truncate string %q, should be %q", result, expectation)
   980  }
   981  
   982  func TestGetService(t *testing.T) {
   983  	t.Run("Server", func(t *testing.T) {
   984  		app := &v1alpha1.Application{
   985  			Spec: v1alpha1.ApplicationSpec{
   986  				Destination: v1alpha1.ApplicationDestination{
   987  					Server: "test-server",
   988  				},
   989  			},
   990  		}
   991  		result := getServer(app)
   992  		expectation := "test-server"
   993  		require.Equal(t, result, expectation, "Incorrect server %q, should be %q", result, expectation)
   994  	})
   995  	t.Run("Name", func(t *testing.T) {
   996  		app := &v1alpha1.Application{
   997  			Spec: v1alpha1.ApplicationSpec{
   998  				Destination: v1alpha1.ApplicationDestination{
   999  					Name: "test-name",
  1000  				},
  1001  			},
  1002  		}
  1003  		result := getServer(app)
  1004  		expectation := "test-name"
  1005  		require.Equal(t, result, expectation, "Incorrect server name %q, should be %q", result, expectation)
  1006  	})
  1007  }
  1008  
  1009  func TestTargetObjects(t *testing.T) {
  1010  	resources := []*v1alpha1.ResourceDiff{
  1011  		{
  1012  			TargetState: "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"name\":\"test-helm-guestbook\",\"namespace\":\"argocd\"},\"spec\":{\"selector\":{\"app\":\"helm-guestbook\",\"release\":\"test\"},\"sessionAffinity\":\"None\",\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}",
  1013  		},
  1014  		{
  1015  			TargetState: "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"name\":\"test-helm-guestbook\",\"namespace\":\"ns\"},\"spec\":{\"selector\":{\"app\":\"helm-guestbook\",\"release\":\"test\"},\"sessionAffinity\":\"None\",\"type\":\"ClusterIP\"},\"status\":{\"loadBalancer\":{}}}",
  1016  		},
  1017  	}
  1018  	objects, err := targetObjects(resources)
  1019  	require.NoError(t, err, "operation should finish without error")
  1020  	require.Lenf(t, objects, 2, "incorrect number of objects %v, should be 2", len(objects))
  1021  	require.Equalf(t, "test-helm-guestbook", objects[0].GetName(), "incorrect name %q, should be %q", objects[0].GetName(), "test-helm-guestbook")
  1022  }
  1023  
  1024  func TestTargetObjects_invalid(t *testing.T) {
  1025  	resources := []*v1alpha1.ResourceDiff{{TargetState: "{"}}
  1026  	_, err := targetObjects(resources)
  1027  	assert.Error(t, err)
  1028  }
  1029  
  1030  func TestCheckForDeleteEvent(t *testing.T) {
  1031  	fakeClient := new(fakeAcdClient)
  1032  
  1033  	checkForDeleteEvent(t.Context(), fakeClient, "testApp")
  1034  }
  1035  
  1036  func TestPrintApplicationNames(t *testing.T) {
  1037  	output, _ := captureOutput(func() error {
  1038  		app := &v1alpha1.Application{
  1039  			ObjectMeta: metav1.ObjectMeta{
  1040  				Name: "test",
  1041  			},
  1042  		}
  1043  		printApplicationNames([]v1alpha1.Application{*app, *app})
  1044  		return nil
  1045  	})
  1046  	expectation := "test\ntest\n"
  1047  	require.Equalf(t, output, expectation, "Incorrect print params output %q, should be %q", output, expectation)
  1048  }
  1049  
  1050  func Test_unset(t *testing.T) {
  1051  	kustomizeSource := &v1alpha1.ApplicationSource{
  1052  		Kustomize: &v1alpha1.ApplicationSourceKustomize{
  1053  			IgnoreMissingComponents: true,
  1054  			NamePrefix:              "some-prefix",
  1055  			NameSuffix:              "some-suffix",
  1056  			Version:                 "123",
  1057  			Images: v1alpha1.KustomizeImages{
  1058  				"old1=new:tag",
  1059  				"old2=new:tag",
  1060  			},
  1061  			Replicas: []v1alpha1.KustomizeReplica{
  1062  				{
  1063  					Name:  "my-deployment",
  1064  					Count: intstr.FromInt(2),
  1065  				},
  1066  				{
  1067  					Name:  "my-statefulset",
  1068  					Count: intstr.FromInt(4),
  1069  				},
  1070  			},
  1071  		},
  1072  	}
  1073  
  1074  	helmSource := &v1alpha1.ApplicationSource{
  1075  		Helm: &v1alpha1.ApplicationSourceHelm{
  1076  			IgnoreMissingValueFiles: true,
  1077  			Parameters: []v1alpha1.HelmParameter{
  1078  				{
  1079  					Name:  "name-1",
  1080  					Value: "value-1",
  1081  				},
  1082  				{
  1083  					Name:  "name-2",
  1084  					Value: "value-2",
  1085  				},
  1086  			},
  1087  			PassCredentials: true,
  1088  			ValuesObject:    &runtime.RawExtension{Raw: []byte("some: yaml")},
  1089  			ValueFiles: []string{
  1090  				"values-1.yaml",
  1091  				"values-2.yaml",
  1092  			},
  1093  		},
  1094  	}
  1095  
  1096  	pluginSource := &v1alpha1.ApplicationSource{
  1097  		Plugin: &v1alpha1.ApplicationSourcePlugin{
  1098  			Env: v1alpha1.Env{
  1099  				{
  1100  					Name:  "env-1",
  1101  					Value: "env-value-1",
  1102  				},
  1103  				{
  1104  					Name:  "env-2",
  1105  					Value: "env-value-2",
  1106  				},
  1107  			},
  1108  		},
  1109  	}
  1110  
  1111  	assert.Equal(t, "some-prefix", kustomizeSource.Kustomize.NamePrefix)
  1112  	updated, nothingToUnset := unset(kustomizeSource, unsetOpts{namePrefix: true})
  1113  	assert.Empty(t, kustomizeSource.Kustomize.NamePrefix)
  1114  	assert.True(t, updated)
  1115  	assert.False(t, nothingToUnset)
  1116  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{namePrefix: true})
  1117  	assert.False(t, updated)
  1118  	assert.False(t, nothingToUnset)
  1119  
  1120  	assert.Equal(t, "some-suffix", kustomizeSource.Kustomize.NameSuffix)
  1121  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{nameSuffix: true})
  1122  	assert.Empty(t, kustomizeSource.Kustomize.NameSuffix)
  1123  	assert.True(t, updated)
  1124  	assert.False(t, nothingToUnset)
  1125  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{nameSuffix: true})
  1126  	assert.False(t, updated)
  1127  	assert.False(t, nothingToUnset)
  1128  
  1129  	assert.Equal(t, "123", kustomizeSource.Kustomize.Version)
  1130  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeVersion: true})
  1131  	assert.Empty(t, kustomizeSource.Kustomize.Version)
  1132  	assert.True(t, updated)
  1133  	assert.False(t, nothingToUnset)
  1134  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeVersion: true})
  1135  	assert.False(t, updated)
  1136  	assert.False(t, nothingToUnset)
  1137  
  1138  	assert.Len(t, kustomizeSource.Kustomize.Images, 2)
  1139  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeImages: []string{"old1=new:tag"}})
  1140  	assert.Len(t, kustomizeSource.Kustomize.Images, 1)
  1141  	assert.True(t, updated)
  1142  	assert.False(t, nothingToUnset)
  1143  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeImages: []string{"old1=new:tag"}})
  1144  	assert.False(t, updated)
  1145  	assert.False(t, nothingToUnset)
  1146  
  1147  	assert.Len(t, kustomizeSource.Kustomize.Replicas, 2)
  1148  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}})
  1149  	assert.Len(t, kustomizeSource.Kustomize.Replicas, 1)
  1150  	assert.True(t, updated)
  1151  	assert.False(t, nothingToUnset)
  1152  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}})
  1153  	assert.False(t, updated)
  1154  	assert.False(t, nothingToUnset)
  1155  
  1156  	assert.True(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
  1157  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
  1158  	assert.False(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
  1159  	assert.True(t, updated)
  1160  	assert.False(t, nothingToUnset)
  1161  	updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
  1162  	assert.False(t, updated)
  1163  	assert.False(t, nothingToUnset)
  1164  
  1165  	assert.Len(t, helmSource.Helm.Parameters, 2)
  1166  	updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
  1167  	assert.Len(t, helmSource.Helm.Parameters, 1)
  1168  	assert.True(t, updated)
  1169  	assert.False(t, nothingToUnset)
  1170  	updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
  1171  	assert.False(t, updated)
  1172  	assert.False(t, nothingToUnset)
  1173  
  1174  	assert.Len(t, helmSource.Helm.ValueFiles, 2)
  1175  	updated, nothingToUnset = unset(helmSource, unsetOpts{valuesFiles: []string{"values-1.yaml"}})
  1176  	assert.Len(t, helmSource.Helm.ValueFiles, 1)
  1177  	assert.True(t, updated)
  1178  	assert.False(t, nothingToUnset)
  1179  	updated, nothingToUnset = unset(helmSource, unsetOpts{valuesFiles: []string{"values-1.yaml"}})
  1180  	assert.False(t, updated)
  1181  	assert.False(t, nothingToUnset)
  1182  
  1183  	assert.Equal(t, "some: yaml", helmSource.Helm.ValuesString())
  1184  	updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true})
  1185  	assert.Empty(t, helmSource.Helm.ValuesString())
  1186  	assert.True(t, updated)
  1187  	assert.False(t, nothingToUnset)
  1188  	updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true})
  1189  	assert.False(t, updated)
  1190  	assert.False(t, nothingToUnset)
  1191  
  1192  	assert.True(t, helmSource.Helm.IgnoreMissingValueFiles)
  1193  	updated, nothingToUnset = unset(helmSource, unsetOpts{ignoreMissingValueFiles: true})
  1194  	assert.False(t, helmSource.Helm.IgnoreMissingValueFiles)
  1195  	assert.True(t, updated)
  1196  	assert.False(t, nothingToUnset)
  1197  	updated, nothingToUnset = unset(helmSource, unsetOpts{ignoreMissingValueFiles: true})
  1198  	assert.False(t, updated)
  1199  	assert.False(t, nothingToUnset)
  1200  
  1201  	assert.True(t, helmSource.Helm.PassCredentials)
  1202  	updated, nothingToUnset = unset(helmSource, unsetOpts{passCredentials: true})
  1203  	assert.False(t, helmSource.Helm.PassCredentials)
  1204  	assert.True(t, updated)
  1205  	assert.False(t, nothingToUnset)
  1206  	updated, nothingToUnset = unset(helmSource, unsetOpts{passCredentials: true})
  1207  	assert.False(t, updated)
  1208  	assert.False(t, nothingToUnset)
  1209  
  1210  	assert.Len(t, pluginSource.Plugin.Env, 2)
  1211  	updated, nothingToUnset = unset(pluginSource, unsetOpts{pluginEnvs: []string{"env-1"}})
  1212  	assert.Len(t, pluginSource.Plugin.Env, 1)
  1213  	assert.True(t, updated)
  1214  	assert.False(t, nothingToUnset)
  1215  	updated, nothingToUnset = unset(pluginSource, unsetOpts{pluginEnvs: []string{"env-1"}})
  1216  	assert.False(t, updated)
  1217  	assert.False(t, nothingToUnset)
  1218  }
  1219  
  1220  func Test_unset_nothingToUnset(t *testing.T) {
  1221  	t.Parallel()
  1222  
  1223  	testCases := []struct {
  1224  		name   string
  1225  		source v1alpha1.ApplicationSource
  1226  	}{
  1227  		{"kustomize", v1alpha1.ApplicationSource{Kustomize: &v1alpha1.ApplicationSourceKustomize{}}},
  1228  		{"helm", v1alpha1.ApplicationSource{Helm: &v1alpha1.ApplicationSourceHelm{}}},
  1229  		{"plugin", v1alpha1.ApplicationSource{Plugin: &v1alpha1.ApplicationSourcePlugin{}}},
  1230  	}
  1231  
  1232  	for _, testCase := range testCases {
  1233  		testCaseCopy := testCase
  1234  
  1235  		t.Run(testCaseCopy.name, func(t *testing.T) {
  1236  			t.Parallel()
  1237  
  1238  			updated, nothingToUnset := unset(&testCaseCopy.source, unsetOpts{})
  1239  			assert.False(t, updated)
  1240  			assert.True(t, nothingToUnset)
  1241  		})
  1242  	}
  1243  }
  1244  
  1245  func TestFilterAppResources(t *testing.T) {
  1246  	// App resources
  1247  	var (
  1248  		appReplicaSet1 = v1alpha1.ResourceStatus{
  1249  			Group:     "apps",
  1250  			Kind:      "ReplicaSet",
  1251  			Namespace: "default",
  1252  			Name:      "replicaSet-name1",
  1253  		}
  1254  		appReplicaSet2 = v1alpha1.ResourceStatus{
  1255  			Group:     "apps",
  1256  			Kind:      "ReplicaSet",
  1257  			Namespace: "default",
  1258  			Name:      "replicaSet-name2",
  1259  		}
  1260  		appJob = v1alpha1.ResourceStatus{
  1261  			Group:     "batch",
  1262  			Kind:      "Job",
  1263  			Namespace: "default",
  1264  			Name:      "job-name",
  1265  		}
  1266  		appService1 = v1alpha1.ResourceStatus{
  1267  			Group:     "",
  1268  			Kind:      "Service",
  1269  			Namespace: "default",
  1270  			Name:      "service-name1",
  1271  		}
  1272  		appService2 = v1alpha1.ResourceStatus{
  1273  			Group:     "",
  1274  			Kind:      "Service",
  1275  			Namespace: "default",
  1276  			Name:      "service-name2",
  1277  		}
  1278  		appDeployment = v1alpha1.ResourceStatus{
  1279  			Group:     "apps",
  1280  			Kind:      "Deployment",
  1281  			Namespace: "default",
  1282  			Name:      "deployment-name",
  1283  		}
  1284  	)
  1285  	app := v1alpha1.Application{
  1286  		Status: v1alpha1.ApplicationStatus{
  1287  			Resources: []v1alpha1.ResourceStatus{
  1288  				appReplicaSet1, appReplicaSet2, appJob, appService1, appService2, appDeployment,
  1289  			},
  1290  		},
  1291  	}
  1292  	// Resource filters
  1293  	var (
  1294  		blankValues = v1alpha1.SyncOperationResource{
  1295  			Group:     "",
  1296  			Kind:      "",
  1297  			Name:      "",
  1298  			Namespace: "",
  1299  			Exclude:   false,
  1300  		}
  1301  		// *:*:*
  1302  		includeAllResources = v1alpha1.SyncOperationResource{
  1303  			Group:     "*",
  1304  			Kind:      "*",
  1305  			Name:      "*",
  1306  			Namespace: "",
  1307  			Exclude:   false,
  1308  		}
  1309  		// !*:*:*
  1310  		excludeAllResources = v1alpha1.SyncOperationResource{
  1311  			Group:     "*",
  1312  			Kind:      "*",
  1313  			Name:      "*",
  1314  			Namespace: "",
  1315  			Exclude:   true,
  1316  		}
  1317  		// *:Service:*
  1318  		includeAllServiceResources = v1alpha1.SyncOperationResource{
  1319  			Group:     "*",
  1320  			Kind:      "Service",
  1321  			Name:      "*",
  1322  			Namespace: "",
  1323  			Exclude:   false,
  1324  		}
  1325  		// !*:Service:*
  1326  		excludeAllServiceResources = v1alpha1.SyncOperationResource{
  1327  			Group:     "*",
  1328  			Kind:      "Service",
  1329  			Name:      "*",
  1330  			Namespace: "",
  1331  			Exclude:   true,
  1332  		}
  1333  		// apps:ReplicaSet:*
  1334  		includeAllReplicaSetResource = v1alpha1.SyncOperationResource{
  1335  			Group:     "apps",
  1336  			Kind:      "ReplicaSet",
  1337  			Name:      "*",
  1338  			Namespace: "",
  1339  			Exclude:   false,
  1340  		}
  1341  		// apps:ReplicaSet:replicaSet-name1
  1342  		includeReplicaSet1Resource = v1alpha1.SyncOperationResource{
  1343  			Group:     "apps",
  1344  			Kind:      "ReplicaSet",
  1345  			Name:      "replicaSet-name1",
  1346  			Namespace: "",
  1347  			Exclude:   false,
  1348  		}
  1349  		// !apps:ReplicaSet:replicaSet-name2
  1350  		excludeReplicaSet2Resource = v1alpha1.SyncOperationResource{
  1351  			Group:     "apps",
  1352  			Kind:      "ReplicaSet",
  1353  			Name:      "replicaSet-name2",
  1354  			Namespace: "",
  1355  			Exclude:   true,
  1356  		}
  1357  	)
  1358  
  1359  	// Filtered resources
  1360  	var (
  1361  		replicaSet1 = v1alpha1.SyncOperationResource{
  1362  			Group:     "apps",
  1363  			Kind:      "ReplicaSet",
  1364  			Namespace: "default",
  1365  			Name:      "replicaSet-name1",
  1366  		}
  1367  		replicaSet2 = v1alpha1.SyncOperationResource{
  1368  			Group:     "apps",
  1369  			Kind:      "ReplicaSet",
  1370  			Namespace: "default",
  1371  			Name:      "replicaSet-name2",
  1372  		}
  1373  		job = v1alpha1.SyncOperationResource{
  1374  			Group:     "batch",
  1375  			Kind:      "Job",
  1376  			Namespace: "default",
  1377  			Name:      "job-name",
  1378  		}
  1379  		service1 = v1alpha1.SyncOperationResource{
  1380  			Group:     "",
  1381  			Kind:      "Service",
  1382  			Namespace: "default",
  1383  			Name:      "service-name1",
  1384  		}
  1385  		service2 = v1alpha1.SyncOperationResource{
  1386  			Group:     "",
  1387  			Kind:      "Service",
  1388  			Namespace: "default",
  1389  			Name:      "service-name2",
  1390  		}
  1391  		deployment = v1alpha1.SyncOperationResource{
  1392  			Group:     "apps",
  1393  			Kind:      "Deployment",
  1394  			Namespace: "default",
  1395  			Name:      "deployment-name",
  1396  		}
  1397  	)
  1398  	tests := []struct {
  1399  		testName          string
  1400  		selectedResources []*v1alpha1.SyncOperationResource
  1401  		expectedResult    []*v1alpha1.SyncOperationResource
  1402  	}{
  1403  		// --resource apps:ReplicaSet:replicaSet-name1 --resource *:Service:*
  1404  		{
  1405  			testName:          "Include ReplicaSet replicaSet-name1 resource and all service resources",
  1406  			selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources, &includeReplicaSet1Resource},
  1407  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1, &service1, &service2},
  1408  		},
  1409  		// --resource apps:ReplicaSet:replicaSet-name1 --resource !*:Service:*
  1410  		{
  1411  			testName:          "Include ReplicaSet replicaSet-name1 resource and exclude all service resources",
  1412  			selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources, &includeReplicaSet1Resource},
  1413  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1},
  1414  		},
  1415  		// --resource !apps:ReplicaSet:replicaSet-name2 --resource !*:Service:*
  1416  		{
  1417  			testName:          "Exclude ReplicaSet replicaSet-name2 resource and all service resources",
  1418  			selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource, &excludeAllServiceResources},
  1419  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1, &job, &deployment},
  1420  		},
  1421  		// --resource !apps:ReplicaSet:replicaSet-name2
  1422  		{
  1423  			testName:          "Exclude ReplicaSet replicaSet-name2 resource",
  1424  			selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource},
  1425  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1, &job, &service1, &service2, &deployment},
  1426  		},
  1427  		// --resource apps:ReplicaSet:replicaSet-name1
  1428  		{
  1429  			testName:          "Include ReplicaSet replicaSet-name1 resource",
  1430  			selectedResources: []*v1alpha1.SyncOperationResource{&includeReplicaSet1Resource},
  1431  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1},
  1432  		},
  1433  		// --resource apps:ReplicaSet:* --resource !apps:ReplicaSet:replicaSet-name2
  1434  		{
  1435  			testName:          "Include All ReplicaSet resource and exclude replicaSet-name1 resource",
  1436  			selectedResources: []*v1alpha1.SyncOperationResource{&includeAllReplicaSetResource, &excludeReplicaSet2Resource},
  1437  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1},
  1438  		},
  1439  		// --resource !*:Service:*
  1440  		{
  1441  			testName:          "Exclude Service resources",
  1442  			selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources},
  1443  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment},
  1444  		},
  1445  		// --resource *:Service:*
  1446  		{
  1447  			testName:          "Include Service resources",
  1448  			selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources},
  1449  			expectedResult:    []*v1alpha1.SyncOperationResource{&service1, &service2},
  1450  		},
  1451  		// --resource !*:*:*
  1452  		{
  1453  			testName:          "Exclude all resources",
  1454  			selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllResources},
  1455  			expectedResult:    nil,
  1456  		},
  1457  		// --resource *:*:*
  1458  		{
  1459  			testName:          "Include all resources",
  1460  			selectedResources: []*v1alpha1.SyncOperationResource{&includeAllResources},
  1461  			expectedResult:    []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment},
  1462  		},
  1463  		{
  1464  			testName:          "No Filters",
  1465  			selectedResources: []*v1alpha1.SyncOperationResource{&blankValues},
  1466  			expectedResult:    nil,
  1467  		},
  1468  		{
  1469  			testName:          "Empty Filter",
  1470  			selectedResources: []*v1alpha1.SyncOperationResource{},
  1471  			expectedResult:    nil,
  1472  		},
  1473  	}
  1474  
  1475  	for _, test := range tests {
  1476  		t.Run(test.testName, func(t *testing.T) {
  1477  			filteredResources := filterAppResources(&app, test.selectedResources)
  1478  			assert.Equal(t, test.expectedResult, filteredResources)
  1479  		})
  1480  	}
  1481  }
  1482  
  1483  func TestParseSelectedResources(t *testing.T) {
  1484  	resources := []string{
  1485  		"v1alpha:Application:test",
  1486  		"v1alpha:Application:namespace/test",
  1487  		"!v1alpha:Application:test",
  1488  		"apps:Deployment:default/test",
  1489  		"!*:*:*",
  1490  	}
  1491  	operationResources, err := parseSelectedResources(resources)
  1492  	require.NoError(t, err)
  1493  	assert.Len(t, operationResources, 5)
  1494  	assert.Equal(t, v1alpha1.SyncOperationResource{
  1495  		Namespace: "",
  1496  		Name:      "test",
  1497  		Kind:      application.ApplicationKind,
  1498  		Group:     "v1alpha",
  1499  	}, *operationResources[0])
  1500  	assert.Equal(t, v1alpha1.SyncOperationResource{
  1501  		Namespace: "namespace",
  1502  		Name:      "test",
  1503  		Kind:      application.ApplicationKind,
  1504  		Group:     "v1alpha",
  1505  	}, *operationResources[1])
  1506  	assert.Equal(t, v1alpha1.SyncOperationResource{
  1507  		Namespace: "",
  1508  		Name:      "test",
  1509  		Kind:      "Application",
  1510  		Group:     "v1alpha",
  1511  		Exclude:   true,
  1512  	}, *operationResources[2])
  1513  	assert.Equal(t, v1alpha1.SyncOperationResource{
  1514  		Namespace: "default",
  1515  		Name:      "test",
  1516  		Kind:      "Deployment",
  1517  		Group:     "apps",
  1518  		Exclude:   false,
  1519  	}, *operationResources[3])
  1520  	assert.Equal(t, v1alpha1.SyncOperationResource{
  1521  		Namespace: "",
  1522  		Name:      "*",
  1523  		Kind:      "*",
  1524  		Group:     "*",
  1525  		Exclude:   true,
  1526  	}, *operationResources[4])
  1527  }
  1528  
  1529  func TestParseSelectedResourcesIncorrect(t *testing.T) {
  1530  	resources := []string{"v1alpha:test", "v1alpha:Application:namespace/test"}
  1531  	_, err := parseSelectedResources(resources)
  1532  	assert.ErrorContains(t, err, "v1alpha:test")
  1533  }
  1534  
  1535  func TestParseSelectedResourcesIncorrectNamespace(t *testing.T) {
  1536  	resources := []string{"v1alpha:Application:namespace/test/unknown"}
  1537  	_, err := parseSelectedResources(resources)
  1538  	assert.ErrorContains(t, err, "v1alpha:Application:namespace/test/unknown")
  1539  }
  1540  
  1541  func TestParseSelectedResourcesEmptyList(t *testing.T) {
  1542  	var resources []string
  1543  	operationResources, err := parseSelectedResources(resources)
  1544  	require.NoError(t, err)
  1545  	assert.Empty(t, operationResources)
  1546  }
  1547  
  1548  func TestPrintApplicationTableNotWide(t *testing.T) {
  1549  	output, err := captureOutput(func() error {
  1550  		app := &v1alpha1.Application{
  1551  			ObjectMeta: metav1.ObjectMeta{
  1552  				Name: "app-name",
  1553  			},
  1554  			Spec: v1alpha1.ApplicationSpec{
  1555  				Destination: v1alpha1.ApplicationDestination{
  1556  					Server:    "http://localhost:8080",
  1557  					Namespace: "default",
  1558  				},
  1559  				Project: "prj",
  1560  			},
  1561  			Status: v1alpha1.ApplicationStatus{
  1562  				Sync: v1alpha1.SyncStatus{
  1563  					Status: "OutOfSync",
  1564  				},
  1565  				Health: v1alpha1.AppHealthStatus{
  1566  					Status: "Healthy",
  1567  				},
  1568  			},
  1569  		}
  1570  		output := "table"
  1571  		printApplicationTable([]v1alpha1.Application{*app, *app}, &output)
  1572  		return nil
  1573  	})
  1574  	require.NoError(t, err)
  1575  	expectation := "NAME      CLUSTER                NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS\napp-name  http://localhost:8080  default    prj      OutOfSync  Healthy  Manual      <none>\napp-name  http://localhost:8080  default    prj      OutOfSync  Healthy  Manual      <none>\n"
  1576  	assert.Equal(t, output, expectation)
  1577  }
  1578  
  1579  func TestPrintApplicationTableWide(t *testing.T) {
  1580  	output, err := captureOutput(func() error {
  1581  		app := &v1alpha1.Application{
  1582  			ObjectMeta: metav1.ObjectMeta{
  1583  				Name: "app-name",
  1584  			},
  1585  			Spec: v1alpha1.ApplicationSpec{
  1586  				Destination: v1alpha1.ApplicationDestination{
  1587  					Server:    "http://localhost:8080",
  1588  					Namespace: "default",
  1589  				},
  1590  				Source: &v1alpha1.ApplicationSource{
  1591  					RepoURL:        "https://github.com/argoproj/argocd-example-apps",
  1592  					Path:           "guestbook",
  1593  					TargetRevision: "123",
  1594  				},
  1595  				Project: "prj",
  1596  			},
  1597  			Status: v1alpha1.ApplicationStatus{
  1598  				Sync: v1alpha1.SyncStatus{
  1599  					Status: "OutOfSync",
  1600  				},
  1601  				Health: v1alpha1.AppHealthStatus{
  1602  					Status: "Healthy",
  1603  				},
  1604  			},
  1605  		}
  1606  		output := "wide"
  1607  		printApplicationTable([]v1alpha1.Application{*app, *app}, &output)
  1608  		return nil
  1609  	})
  1610  	require.NoError(t, err)
  1611  	expectation := "NAME      CLUSTER                NAMESPACE  PROJECT  STATUS     HEALTH   SYNCPOLICY  CONDITIONS  REPO                                             PATH       TARGET\napp-name  http://localhost:8080  default    prj      OutOfSync  Healthy  Manual      <none>      https://github.com/argoproj/argocd-example-apps  guestbook  123\napp-name  http://localhost:8080  default    prj      OutOfSync  Healthy  Manual      <none>      https://github.com/argoproj/argocd-example-apps  guestbook  123\n"
  1612  	assert.Equal(t, output, expectation)
  1613  }
  1614  
  1615  func TestResourceStateKey(t *testing.T) {
  1616  	rst := resourceState{
  1617  		Group:     "group",
  1618  		Kind:      "kind",
  1619  		Namespace: "namespace",
  1620  		Name:      "name",
  1621  	}
  1622  
  1623  	key := rst.Key()
  1624  	assert.Equal(t, "group/kind/namespace/name", key)
  1625  }
  1626  
  1627  func TestFormatItems(t *testing.T) {
  1628  	rst := resourceState{
  1629  		Group:     "group",
  1630  		Kind:      "kind",
  1631  		Namespace: "namespace",
  1632  		Name:      "name",
  1633  		Status:    "status",
  1634  		Health:    "health",
  1635  		Hook:      "hook",
  1636  		Message:   "message",
  1637  	}
  1638  	items := rst.FormatItems()
  1639  	assert.Equal(t, "group", items[1])
  1640  	assert.Equal(t, "kind", items[2])
  1641  	assert.Equal(t, "namespace", items[3])
  1642  	assert.Equal(t, "name", items[4])
  1643  	assert.Equal(t, "status", items[5])
  1644  	assert.Equal(t, "health", items[6])
  1645  	assert.Equal(t, "hook", items[7])
  1646  	assert.Equal(t, "message", items[8])
  1647  }
  1648  
  1649  func TestMerge(t *testing.T) {
  1650  	rst := resourceState{
  1651  		Group:     "group",
  1652  		Kind:      "kind",
  1653  		Namespace: "namespace",
  1654  		Name:      "name",
  1655  		Status:    "status",
  1656  		Health:    "health",
  1657  		Hook:      "hook",
  1658  		Message:   "message",
  1659  	}
  1660  
  1661  	rstNew := resourceState{
  1662  		Group:     "group",
  1663  		Kind:      "kind",
  1664  		Namespace: "namespace",
  1665  		Name:      "name",
  1666  		Status:    "status",
  1667  		Health:    "health",
  1668  		Hook:      "hook2",
  1669  		Message:   "message2",
  1670  	}
  1671  
  1672  	updated := rst.Merge(&rstNew)
  1673  	assert.True(t, updated)
  1674  	assert.Equal(t, rstNew.Hook, rst.Hook)
  1675  	assert.Equal(t, rstNew.Message, rst.Message)
  1676  	assert.Equal(t, rstNew.Status, rst.Status)
  1677  }
  1678  
  1679  func TestMergeWitoutUpdate(t *testing.T) {
  1680  	rst := resourceState{
  1681  		Group:     "group",
  1682  		Kind:      "kind",
  1683  		Namespace: "namespace",
  1684  		Name:      "name",
  1685  		Status:    "status",
  1686  		Health:    "health",
  1687  		Hook:      "hook",
  1688  		Message:   "message",
  1689  	}
  1690  
  1691  	rstNew := resourceState{
  1692  		Group:     "group",
  1693  		Kind:      "kind",
  1694  		Namespace: "namespace",
  1695  		Name:      "name",
  1696  		Status:    "status",
  1697  		Health:    "health",
  1698  		Hook:      "hook",
  1699  		Message:   "message",
  1700  	}
  1701  
  1702  	updated := rst.Merge(&rstNew)
  1703  	assert.False(t, updated)
  1704  }
  1705  
  1706  func TestCheckResourceStatus(t *testing.T) {
  1707  	t.Run("Degraded, Suspended and health status passed", func(t *testing.T) {
  1708  		res := checkResourceStatus(watchOpts{
  1709  			suspended: true,
  1710  			health:    true,
  1711  			degraded:  true,
  1712  		}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1713  		assert.True(t, res)
  1714  	})
  1715  	t.Run("Degraded, Suspended and health status failed", func(t *testing.T) {
  1716  		res := checkResourceStatus(watchOpts{
  1717  			suspended: true,
  1718  			health:    true,
  1719  			degraded:  true,
  1720  		}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1721  		assert.False(t, res)
  1722  	})
  1723  	t.Run("Suspended and health status passed", func(t *testing.T) {
  1724  		res := checkResourceStatus(watchOpts{
  1725  			suspended: true,
  1726  			health:    true,
  1727  		}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1728  		assert.True(t, res)
  1729  	})
  1730  	t.Run("Suspended and health status failed", func(t *testing.T) {
  1731  		res := checkResourceStatus(watchOpts{
  1732  			suspended: true,
  1733  			health:    true,
  1734  		}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1735  		assert.False(t, res)
  1736  	})
  1737  	t.Run("Suspended passed", func(t *testing.T) {
  1738  		res := checkResourceStatus(watchOpts{
  1739  			suspended: true,
  1740  			health:    false,
  1741  		}, string(health.HealthStatusSuspended), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1742  		assert.True(t, res)
  1743  	})
  1744  	t.Run("Suspended failed", func(t *testing.T) {
  1745  		res := checkResourceStatus(watchOpts{
  1746  			suspended: true,
  1747  			health:    false,
  1748  		}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1749  		assert.False(t, res)
  1750  	})
  1751  	t.Run("Health passed", func(t *testing.T) {
  1752  		res := checkResourceStatus(watchOpts{
  1753  			suspended: false,
  1754  			health:    true,
  1755  		}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1756  		assert.True(t, res)
  1757  	})
  1758  	t.Run("Health failed", func(t *testing.T) {
  1759  		res := checkResourceStatus(watchOpts{
  1760  			suspended: false,
  1761  			health:    true,
  1762  		}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1763  		assert.False(t, res)
  1764  	})
  1765  	t.Run("Synced passed", func(t *testing.T) {
  1766  		res := checkResourceStatus(watchOpts{}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1767  		assert.True(t, res)
  1768  	})
  1769  	t.Run("Synced failed", func(t *testing.T) {
  1770  		res := checkResourceStatus(watchOpts{}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeOutOfSync), &v1alpha1.Operation{}, true)
  1771  		assert.True(t, res)
  1772  	})
  1773  	t.Run("Degraded passed", func(t *testing.T) {
  1774  		res := checkResourceStatus(watchOpts{
  1775  			suspended: false,
  1776  			health:    false,
  1777  			degraded:  true,
  1778  		}, string(health.HealthStatusDegraded), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1779  		assert.True(t, res)
  1780  	})
  1781  	t.Run("Degraded failed", func(t *testing.T) {
  1782  		res := checkResourceStatus(watchOpts{
  1783  			suspended: false,
  1784  			health:    false,
  1785  			degraded:  true,
  1786  		}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
  1787  		assert.False(t, res)
  1788  	})
  1789  }
  1790  
  1791  func Test_hasAppChanged(t *testing.T) {
  1792  	type args struct {
  1793  		appReq *v1alpha1.Application
  1794  		appRes *v1alpha1.Application
  1795  		upsert bool
  1796  	}
  1797  	tests := []struct {
  1798  		name string
  1799  		args args
  1800  		want bool
  1801  	}{
  1802  		{
  1803  			name: "App has changed - Labels, Annotations, Finalizers empty",
  1804  			args: args{
  1805  				appReq: testApp("foo", "default", map[string]string{}, map[string]string{}, []string{}),
  1806  				appRes: testApp("foo", "foo", nil, nil, nil),
  1807  				upsert: true,
  1808  			},
  1809  			want: true,
  1810  		},
  1811  		{
  1812  			name: "App unchanged - Labels, Annotations, Finalizers populated",
  1813  			args: args{
  1814  				appReq: testApp("foo", "default", map[string]string{"foo": "bar"}, map[string]string{"foo": "bar"}, []string{"foo"}),
  1815  				appRes: testApp("foo", "default", map[string]string{"foo": "bar"}, map[string]string{"foo": "bar"}, []string{"foo"}),
  1816  				upsert: true,
  1817  			},
  1818  			want: false,
  1819  		},
  1820  		{
  1821  			name: "Apps unchanged - Using empty maps/list locally versus server returning nil",
  1822  			args: args{
  1823  				appReq: testApp("foo", "default", map[string]string{}, map[string]string{}, []string{}),
  1824  				appRes: testApp("foo", "default", nil, nil, nil),
  1825  				upsert: true,
  1826  			},
  1827  			want: false,
  1828  		},
  1829  		{
  1830  			name: "App unchanged - Using empty project locally versus server returning default",
  1831  			args: args{
  1832  				appReq: testApp("foo", "", map[string]string{}, map[string]string{}, []string{}),
  1833  				appRes: testApp("foo", "default", nil, nil, nil),
  1834  			},
  1835  			want: false,
  1836  		},
  1837  		{
  1838  			name: "App unchanged - From upsert=false",
  1839  			args: args{
  1840  				appReq: testApp("foo", "foo", map[string]string{}, map[string]string{}, []string{}),
  1841  				appRes: testApp("foo", "default", nil, nil, nil),
  1842  				upsert: false,
  1843  			},
  1844  			want: false,
  1845  		},
  1846  	}
  1847  	for _, tt := range tests {
  1848  		t.Run(tt.name, func(t *testing.T) {
  1849  			got := hasAppChanged(tt.args.appReq, tt.args.appRes, tt.args.upsert)
  1850  			assert.Equalf(t, tt.want, got, "hasAppChanged() = %v, want %v", got, tt.want)
  1851  		})
  1852  	}
  1853  }
  1854  
  1855  func testApp(name, project string, labels map[string]string, annotations map[string]string, finalizers []string) *v1alpha1.Application {
  1856  	return &v1alpha1.Application{
  1857  		ObjectMeta: metav1.ObjectMeta{
  1858  			Name:        name,
  1859  			Labels:      labels,
  1860  			Annotations: annotations,
  1861  			Finalizers:  finalizers,
  1862  		},
  1863  		Spec: v1alpha1.ApplicationSpec{
  1864  			Source: &v1alpha1.ApplicationSource{
  1865  				RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
  1866  			},
  1867  			Project: project,
  1868  		},
  1869  	}
  1870  }
  1871  
  1872  func TestWaitOnApplicationStatus_JSON_YAML_WideOutput(t *testing.T) {
  1873  	acdClient := &customAcdClient{&fakeAcdClient{}}
  1874  	ctx := t.Context()
  1875  	var selectResource []*v1alpha1.SyncOperationResource
  1876  	watch := watchOpts{
  1877  		sync:      false,
  1878  		health:    false,
  1879  		operation: true,
  1880  		suspended: false,
  1881  	}
  1882  	watch = getWatchOpts(watch)
  1883  
  1884  	output, err := captureOutput(func() error {
  1885  		_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "json")
  1886  		return nil
  1887  	},
  1888  	)
  1889  	require.NoError(t, err)
  1890  	assert.True(t, json.Valid([]byte(output)))
  1891  
  1892  	output, err = captureOutput(func() error {
  1893  		_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "yaml")
  1894  		return nil
  1895  	})
  1896  
  1897  	require.NoError(t, err)
  1898  	err = yaml.Unmarshal([]byte(output), &v1alpha1.Application{})
  1899  	require.NoError(t, err)
  1900  
  1901  	output, _ = captureOutput(func() error {
  1902  		_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "")
  1903  		return nil
  1904  	})
  1905  	timeStr := time.Now().Format("2006-01-02T15:04:05-07:00")
  1906  
  1907  	expectation := `TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS   HEALTH        HOOK  MESSAGE
  1908  %s            Service     default         service-name1    Synced  Healthy              
  1909  %s   apps  Deployment     default                  test    Synced  Healthy              
  1910  
  1911  Name:               argocd/test
  1912  Project:            default
  1913  Server:             local
  1914  Namespace:          argocd
  1915  URL:                http://localhost:8080/applications/app-name
  1916  Source:
  1917  - Repo:             test
  1918    Target:           master
  1919    Path:             /test
  1920    Helm Values:      path1,path2
  1921    Name Prefix:      prefix
  1922  SyncWindow:         Sync Allowed
  1923  Sync Policy:        Automated (Prune)
  1924  Sync Status:        OutOfSync from master
  1925  Health Status:      Progressing
  1926  
  1927  Operation:          Sync
  1928  Sync Revision:      revision
  1929  Phase:              
  1930  Start:              0001-01-01 00:00:00 +0000 UTC
  1931  Finished:           2020-11-10 23:00:00 +0000 UTC
  1932  Duration:           2333448h16m18.871345152s
  1933  Message:            test
  1934  
  1935  GROUP  KIND        NAMESPACE  NAME           STATUS  HEALTH   HOOK  MESSAGE
  1936         Service     default    service-name1  Synced  Healthy        
  1937  apps   Deployment  default    test           Synced  Healthy        
  1938  `
  1939  	expectation = fmt.Sprintf(expectation, timeStr, timeStr)
  1940  	expectationParts := strings.Split(expectation, "\n")
  1941  	slices.Sort(expectationParts)
  1942  	expectationSorted := strings.Join(expectationParts, "\n")
  1943  	outputParts := strings.Split(output, "\n")
  1944  	slices.Sort(outputParts)
  1945  	outputSorted := strings.Join(outputParts, "\n")
  1946  	// Need to compare sorted since map entries may not keep a specific order during serialization, leading to flakiness.
  1947  	assert.Equalf(t, expectationSorted, outputSorted, "Incorrect output %q, should be %q (items order doesn't matter)", output, expectation)
  1948  }
  1949  
  1950  func TestWaitOnApplicationStatus_JSON_YAML_WideOutput_With_Timeout(t *testing.T) {
  1951  	acdClient := &customAcdClient{&fakeAcdClient{simulateTimeout: 15}}
  1952  	ctx := t.Context()
  1953  	var selectResource []*v1alpha1.SyncOperationResource
  1954  	watch := watchOpts{
  1955  		sync:      false,
  1956  		health:    false,
  1957  		operation: true,
  1958  		suspended: false,
  1959  	}
  1960  	watch = getWatchOpts(watch)
  1961  
  1962  	output, _ := captureOutput(func() error {
  1963  		_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 5, watch, selectResource, "")
  1964  		return nil
  1965  	})
  1966  	timeStr := time.Now().Format("2006-01-02T15:04:05-07:00")
  1967  
  1968  	expectation := `TIMESTAMP                  GROUP        KIND   NAMESPACE                  NAME    STATUS   HEALTH        HOOK  MESSAGE
  1969  %s            Service     default         service-name1    Synced  Healthy              
  1970  %s   apps  Deployment     default                  test    Synced  Healthy              
  1971  
  1972  The command timed out waiting for the conditions to be met.
  1973  
  1974  This is the state of the app after wait timed out:
  1975  
  1976  Name:               argocd/test
  1977  Project:            default
  1978  Server:             local
  1979  Namespace:          argocd
  1980  URL:                http://localhost:8080/applications/app-name
  1981  Source:
  1982  - Repo:             test
  1983    Target:           master
  1984    Path:             /test
  1985    Helm Values:      path1,path2
  1986    Name Prefix:      prefix
  1987  SyncWindow:         Sync Allowed
  1988  Sync Policy:        Automated (Prune)
  1989  Sync Status:        OutOfSync from master
  1990  Health Status:      Progressing
  1991  
  1992  Operation:          Sync
  1993  Sync Revision:      revision
  1994  Phase:              
  1995  Start:              0001-01-01 00:00:00 +0000 UTC
  1996  Finished:           2020-11-10 23:00:00 +0000 UTC
  1997  Duration:           2333448h16m18.871345152s
  1998  Message:            test
  1999  
  2000  GROUP  KIND        NAMESPACE  NAME           STATUS  HEALTH   HOOK  MESSAGE
  2001         Service     default    service-name1  Synced  Healthy        
  2002  apps   Deployment  default    test           Synced  Healthy        
  2003  `
  2004  	expectation = fmt.Sprintf(expectation, timeStr, timeStr)
  2005  	expectationParts := strings.Split(expectation, "\n")
  2006  	slices.Sort(expectationParts)
  2007  	expectationSorted := strings.Join(expectationParts, "\n")
  2008  	outputParts := strings.Split(output, "\n")
  2009  	slices.Sort(outputParts)
  2010  	outputSorted := strings.Join(outputParts, "\n")
  2011  	// Need to compare sorted since map entries may not keep a specific order during serialization, leading to flakiness.
  2012  	assert.Equalf(t, expectationSorted, outputSorted, "Incorrect output %q, should be %q (items order doesn't matter)", output, expectation)
  2013  }
  2014  
  2015  type customAcdClient struct {
  2016  	*fakeAcdClient
  2017  }
  2018  
  2019  func (c *customAcdClient) WatchApplicationWithRetry(ctx context.Context, _ string, _ string) chan *v1alpha1.ApplicationWatchEvent {
  2020  	appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
  2021  	_, appClient := c.NewApplicationClientOrDie()
  2022  	app, _ := appClient.Get(ctx, &applicationpkg.ApplicationQuery{})
  2023  
  2024  	newApp := v1alpha1.Application{
  2025  		TypeMeta:   app.TypeMeta,
  2026  		ObjectMeta: app.ObjectMeta,
  2027  		Spec:       app.Spec,
  2028  		Status:     app.Status,
  2029  		Operation:  app.Operation,
  2030  	}
  2031  
  2032  	go func() {
  2033  		time.Sleep(time.Duration(c.simulateTimeout) * time.Second)
  2034  		appEventsCh <- &v1alpha1.ApplicationWatchEvent{
  2035  			Type:        watch.Bookmark,
  2036  			Application: newApp,
  2037  		}
  2038  		close(appEventsCh)
  2039  	}()
  2040  
  2041  	return appEventsCh
  2042  }
  2043  
  2044  func (c *customAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
  2045  	return &fakeConnection{}, &fakeAppServiceClient{}
  2046  }
  2047  
  2048  func (c *customAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
  2049  	return &fakeConnection{}, &fakeSettingsServiceClient{}
  2050  }
  2051  
  2052  type fakeConnection struct{}
  2053  
  2054  func (c *fakeConnection) Close() error {
  2055  	return nil
  2056  }
  2057  
  2058  type fakeSettingsServiceClient struct{}
  2059  
  2060  func (f fakeSettingsServiceClient) Get(_ context.Context, _ *settingspkg.SettingsQuery, _ ...grpc.CallOption) (*settingspkg.Settings, error) {
  2061  	return &settingspkg.Settings{
  2062  		URL: "http://localhost:8080",
  2063  	}, nil
  2064  }
  2065  
  2066  func (f fakeSettingsServiceClient) GetPlugins(_ context.Context, _ *settingspkg.SettingsQuery, _ ...grpc.CallOption) (*settingspkg.SettingsPluginsResponse, error) {
  2067  	return nil, nil
  2068  }
  2069  
  2070  type fakeAppServiceClient struct{}
  2071  
  2072  func (c *fakeAppServiceClient) Get(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2073  	time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
  2074  	return &v1alpha1.Application{
  2075  		ObjectMeta: metav1.ObjectMeta{
  2076  			Name:      "test",
  2077  			Namespace: "argocd",
  2078  		},
  2079  		Spec: v1alpha1.ApplicationSpec{
  2080  			SyncPolicy: &v1alpha1.SyncPolicy{
  2081  				Automated: &v1alpha1.SyncPolicyAutomated{
  2082  					Prune: true,
  2083  				},
  2084  			},
  2085  			Project:     "default",
  2086  			Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
  2087  			Source: &v1alpha1.ApplicationSource{
  2088  				RepoURL:        "test",
  2089  				TargetRevision: "master",
  2090  				Path:           "/test",
  2091  				Helm: &v1alpha1.ApplicationSourceHelm{
  2092  					ValueFiles: []string{"path1", "path2"},
  2093  				},
  2094  				Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
  2095  			},
  2096  		},
  2097  		Status: v1alpha1.ApplicationStatus{
  2098  			Resources: []v1alpha1.ResourceStatus{
  2099  				{
  2100  					Group:     "",
  2101  					Kind:      "Service",
  2102  					Namespace: "default",
  2103  					Name:      "service-name1",
  2104  					Status:    "Synced",
  2105  					Health: &v1alpha1.HealthStatus{
  2106  						Status:  health.HealthStatusHealthy,
  2107  						Message: "health-message",
  2108  					},
  2109  				},
  2110  				{
  2111  					Group:     "apps",
  2112  					Kind:      "Deployment",
  2113  					Namespace: "default",
  2114  					Name:      "test",
  2115  					Status:    "Synced",
  2116  					Health: &v1alpha1.HealthStatus{
  2117  						Status:  health.HealthStatusHealthy,
  2118  						Message: "health-message",
  2119  					},
  2120  				},
  2121  			},
  2122  			OperationState: &v1alpha1.OperationState{
  2123  				SyncResult: &v1alpha1.SyncOperationResult{
  2124  					Revision: "revision",
  2125  				},
  2126  				FinishedAt: &time,
  2127  				Message:    "test",
  2128  			},
  2129  			Sync: v1alpha1.SyncStatus{
  2130  				Status: v1alpha1.SyncStatusCodeOutOfSync,
  2131  			},
  2132  			Health: v1alpha1.AppHealthStatus{
  2133  				Status: health.HealthStatusProgressing,
  2134  			},
  2135  		},
  2136  	}, nil
  2137  }
  2138  
  2139  func (c *fakeAppServiceClient) List(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (*v1alpha1.ApplicationList, error) {
  2140  	return nil, nil
  2141  }
  2142  
  2143  func (c *fakeAppServiceClient) ListResourceEvents(_ context.Context, _ *applicationpkg.ApplicationResourceEventsQuery, _ ...grpc.CallOption) (*corev1.EventList, error) {
  2144  	return nil, nil
  2145  }
  2146  
  2147  func (c *fakeAppServiceClient) Watch(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_WatchClient, error) {
  2148  	return nil, nil
  2149  }
  2150  
  2151  func (c *fakeAppServiceClient) Create(_ context.Context, _ *applicationpkg.ApplicationCreateRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2152  	return nil, nil
  2153  }
  2154  
  2155  func (c *fakeAppServiceClient) GetApplicationSyncWindows(_ context.Context, _ *applicationpkg.ApplicationSyncWindowsQuery, _ ...grpc.CallOption) (*applicationpkg.ApplicationSyncWindowsResponse, error) {
  2156  	return nil, nil
  2157  }
  2158  
  2159  func (c *fakeAppServiceClient) GetOCIMetadata(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.OCIMetadata, error) {
  2160  	return nil, nil
  2161  }
  2162  
  2163  func (c *fakeAppServiceClient) RevisionMetadata(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) {
  2164  	return nil, nil
  2165  }
  2166  
  2167  func (c *fakeAppServiceClient) RevisionChartDetails(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.ChartDetails, error) {
  2168  	return nil, nil
  2169  }
  2170  
  2171  func (c *fakeAppServiceClient) GetManifests(_ context.Context, _ *applicationpkg.ApplicationManifestQuery, _ ...grpc.CallOption) (*apiclient.ManifestResponse, error) {
  2172  	return nil, nil
  2173  }
  2174  
  2175  func (c *fakeAppServiceClient) GetManifestsWithFiles(_ context.Context, _ ...grpc.CallOption) (applicationpkg.ApplicationService_GetManifestsWithFilesClient, error) {
  2176  	return nil, nil
  2177  }
  2178  
  2179  func (c *fakeAppServiceClient) Update(_ context.Context, _ *applicationpkg.ApplicationUpdateRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2180  	return nil, nil
  2181  }
  2182  
  2183  func (c *fakeAppServiceClient) UpdateSpec(_ context.Context, _ *applicationpkg.ApplicationUpdateSpecRequest, _ ...grpc.CallOption) (*v1alpha1.ApplicationSpec, error) {
  2184  	return nil, nil
  2185  }
  2186  
  2187  func (c *fakeAppServiceClient) Patch(_ context.Context, _ *applicationpkg.ApplicationPatchRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2188  	return nil, nil
  2189  }
  2190  
  2191  func (c *fakeAppServiceClient) Delete(_ context.Context, _ *applicationpkg.ApplicationDeleteRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
  2192  	return nil, nil
  2193  }
  2194  
  2195  func (c *fakeAppServiceClient) Sync(_ context.Context, _ *applicationpkg.ApplicationSyncRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2196  	return nil, nil
  2197  }
  2198  
  2199  func (c *fakeAppServiceClient) ManagedResources(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (*applicationpkg.ManagedResourcesResponse, error) {
  2200  	return nil, nil
  2201  }
  2202  
  2203  func (c *fakeAppServiceClient) ResourceTree(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (*v1alpha1.ApplicationTree, error) {
  2204  	return nil, nil
  2205  }
  2206  
  2207  func (c *fakeAppServiceClient) WatchResourceTree(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_WatchResourceTreeClient, error) {
  2208  	return nil, nil
  2209  }
  2210  
  2211  func (c *fakeAppServiceClient) Rollback(_ context.Context, _ *applicationpkg.ApplicationRollbackRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
  2212  	return nil, nil
  2213  }
  2214  
  2215  func (c *fakeAppServiceClient) TerminateOperation(_ context.Context, _ *applicationpkg.OperationTerminateRequest, _ ...grpc.CallOption) (*applicationpkg.OperationTerminateResponse, error) {
  2216  	return nil, nil
  2217  }
  2218  
  2219  func (c *fakeAppServiceClient) GetResource(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
  2220  	return nil, nil
  2221  }
  2222  
  2223  func (c *fakeAppServiceClient) PatchResource(_ context.Context, _ *applicationpkg.ApplicationResourcePatchRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
  2224  	return nil, nil
  2225  }
  2226  
  2227  func (c *fakeAppServiceClient) ListResourceActions(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.ResourceActionsListResponse, error) {
  2228  	return nil, nil
  2229  }
  2230  
  2231  // nolint:staticcheck // ResourceActionRunRequest is deprecated, but we still need to implement it to satisfy the server interface.
  2232  func (c *fakeAppServiceClient) RunResourceAction(_ context.Context, _ *applicationpkg.ResourceActionRunRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
  2233  	return nil, nil
  2234  }
  2235  
  2236  func (c *fakeAppServiceClient) RunResourceActionV2(_ context.Context, _ *applicationpkg.ResourceActionRunRequestV2, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
  2237  	return nil, nil
  2238  }
  2239  
  2240  func (c *fakeAppServiceClient) DeleteResource(_ context.Context, _ *applicationpkg.ApplicationResourceDeleteRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
  2241  	return nil, nil
  2242  }
  2243  
  2244  func (c *fakeAppServiceClient) PodLogs(_ context.Context, _ *applicationpkg.ApplicationPodLogsQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_PodLogsClient, error) {
  2245  	return nil, nil
  2246  }
  2247  
  2248  func (c *fakeAppServiceClient) ListLinks(_ context.Context, _ *applicationpkg.ListAppLinksRequest, _ ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
  2249  	return nil, nil
  2250  }
  2251  
  2252  func (c *fakeAppServiceClient) ListResourceLinks(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
  2253  	return nil, nil
  2254  }
  2255  
  2256  func (c *fakeAppServiceClient) ServerSideDiff(_ context.Context, _ *applicationpkg.ApplicationServerSideDiffQuery, _ ...grpc.CallOption) (*applicationpkg.ApplicationServerSideDiffResponse, error) {
  2257  	return nil, nil
  2258  }
  2259  
  2260  type fakeAcdClient struct {
  2261  	simulateTimeout uint
  2262  }
  2263  
  2264  func (c *fakeAcdClient) ClientOptions() argocdclient.ClientOptions {
  2265  	return argocdclient.ClientOptions{}
  2266  }
  2267  func (c *fakeAcdClient) HTTPClient() (*http.Client, error) { return nil, nil }
  2268  func (c *fakeAcdClient) OIDCConfig(context.Context, *settingspkg.Settings) (*oauth2.Config, *oidc.Provider, error) {
  2269  	return nil, nil, nil
  2270  }
  2271  
  2272  func (c *fakeAcdClient) NewRepoClient() (io.Closer, repositorypkg.RepositoryServiceClient, error) {
  2273  	return nil, nil, nil
  2274  }
  2275  
  2276  func (c *fakeAcdClient) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServiceClient) {
  2277  	return nil, nil
  2278  }
  2279  
  2280  func (c *fakeAcdClient) NewRepoCredsClient() (io.Closer, repocredspkg.RepoCredsServiceClient, error) {
  2281  	return nil, nil, nil
  2282  }
  2283  
  2284  func (c *fakeAcdClient) NewRepoCredsClientOrDie() (io.Closer, repocredspkg.RepoCredsServiceClient) {
  2285  	return nil, nil
  2286  }
  2287  
  2288  func (c *fakeAcdClient) NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) {
  2289  	return nil, nil, nil
  2290  }
  2291  
  2292  func (c *fakeAcdClient) NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) {
  2293  	return nil, nil
  2294  }
  2295  
  2296  func (c *fakeAcdClient) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) {
  2297  	return nil, nil, nil
  2298  }
  2299  
  2300  func (c *fakeAcdClient) NewClusterClientOrDie() (io.Closer, clusterpkg.ClusterServiceClient) {
  2301  	return nil, nil
  2302  }
  2303  
  2304  func (c *fakeAcdClient) NewGPGKeyClient() (io.Closer, gpgkeypkg.GPGKeyServiceClient, error) {
  2305  	return nil, nil, nil
  2306  }
  2307  
  2308  func (c *fakeAcdClient) NewGPGKeyClientOrDie() (io.Closer, gpgkeypkg.GPGKeyServiceClient) {
  2309  	return nil, nil
  2310  }
  2311  
  2312  func (c *fakeAcdClient) NewApplicationClient() (io.Closer, applicationpkg.ApplicationServiceClient, error) {
  2313  	return nil, nil, nil
  2314  }
  2315  
  2316  func (c *fakeAcdClient) NewApplicationSetClient() (io.Closer, applicationsetpkg.ApplicationSetServiceClient, error) {
  2317  	return nil, nil, nil
  2318  }
  2319  
  2320  func (c *fakeAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
  2321  	return nil, nil
  2322  }
  2323  
  2324  func (c *fakeAcdClient) NewApplicationSetClientOrDie() (io.Closer, applicationsetpkg.ApplicationSetServiceClient) {
  2325  	return nil, nil
  2326  }
  2327  
  2328  func (c *fakeAcdClient) NewNotificationClient() (io.Closer, notificationpkg.NotificationServiceClient, error) {
  2329  	return nil, nil, nil
  2330  }
  2331  
  2332  func (c *fakeAcdClient) NewNotificationClientOrDie() (io.Closer, notificationpkg.NotificationServiceClient) {
  2333  	return nil, nil
  2334  }
  2335  
  2336  func (c *fakeAcdClient) NewSessionClient() (io.Closer, sessionpkg.SessionServiceClient, error) {
  2337  	return nil, nil, nil
  2338  }
  2339  
  2340  func (c *fakeAcdClient) NewSessionClientOrDie() (io.Closer, sessionpkg.SessionServiceClient) {
  2341  	return nil, nil
  2342  }
  2343  
  2344  func (c *fakeAcdClient) NewSettingsClient() (io.Closer, settingspkg.SettingsServiceClient, error) {
  2345  	return nil, nil, nil
  2346  }
  2347  
  2348  func (c *fakeAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
  2349  	return nil, nil
  2350  }
  2351  
  2352  func (c *fakeAcdClient) NewVersionClient() (io.Closer, versionpkg.VersionServiceClient, error) {
  2353  	return nil, nil, nil
  2354  }
  2355  
  2356  func (c *fakeAcdClient) NewVersionClientOrDie() (io.Closer, versionpkg.VersionServiceClient) {
  2357  	return nil, nil
  2358  }
  2359  
  2360  func (c *fakeAcdClient) NewProjectClient() (io.Closer, projectpkg.ProjectServiceClient, error) {
  2361  	return nil, nil, nil
  2362  }
  2363  
  2364  func (c *fakeAcdClient) NewProjectClientOrDie() (io.Closer, projectpkg.ProjectServiceClient) {
  2365  	return nil, nil
  2366  }
  2367  
  2368  func (c *fakeAcdClient) NewAccountClient() (io.Closer, accountpkg.AccountServiceClient, error) {
  2369  	return nil, nil, nil
  2370  }
  2371  
  2372  func (c *fakeAcdClient) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceClient) {
  2373  	return nil, nil
  2374  }
  2375  
  2376  func (c *fakeAcdClient) WatchApplicationWithRetry(_ context.Context, _ string, _ string) chan *v1alpha1.ApplicationWatchEvent {
  2377  	appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
  2378  
  2379  	go func() {
  2380  		modifiedEvent := new(v1alpha1.ApplicationWatchEvent)
  2381  		modifiedEvent.Type = watch.Modified
  2382  		appEventsCh <- modifiedEvent
  2383  		deletedEvent := new(v1alpha1.ApplicationWatchEvent)
  2384  		deletedEvent.Type = watch.Deleted
  2385  		appEventsCh <- deletedEvent
  2386  	}()
  2387  	return appEventsCh
  2388  }