Files
argo-cd/cmd/argocd/commands/app_test.go
2026-02-12 09:29:40 -05:00

2389 lines
76 KiB
Go

package commands
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"slices"
"strings"
"testing"
"time"
"github.com/argoproj/argo-cd/gitops-engine/pkg/health"
"github.com/argoproj/argo-cd/gitops-engine/pkg/utils/kube"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/oauth2"
"google.golang.org/grpc"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/watch"
"sigs.k8s.io/yaml"
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
accountpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/account"
applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application"
applicationsetpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/applicationset"
certificatepkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/certificate"
clusterpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/cluster"
gpgkeypkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/gpgkey"
notificationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/notification"
projectpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/project"
repocredspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repocreds"
repositorypkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/repository"
sessionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/session"
settingspkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/settings"
versionpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/version"
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
)
func Test_getInfos(t *testing.T) {
testCases := []struct {
name string
infos []string
expectedInfos []*v1alpha1.Info
}{
{
name: "empty",
infos: []string{},
expectedInfos: []*v1alpha1.Info{},
},
{
name: "simple key value",
infos: []string{"key1=value1", "key2=value2"},
expectedInfos: []*v1alpha1.Info{
{Name: "key1", Value: "value1"},
{Name: "key2", Value: "value2"},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
infos := getInfos(testCase.infos)
assert.Len(t, infos, len(testCase.expectedInfos))
sort := func(a, b *v1alpha1.Info) bool { return a.Name < b.Name }
assert.Empty(t, cmp.Diff(testCase.expectedInfos, infos, cmpopts.SortSlices(sort)))
})
}
}
func Test_getRefreshType(t *testing.T) {
refreshTypeNormal := string(v1alpha1.RefreshTypeNormal)
refreshTypeHard := string(v1alpha1.RefreshTypeHard)
testCases := []struct {
refresh bool
hardRefresh bool
expected *string
}{
{false, false, nil},
{false, true, &refreshTypeHard},
{true, false, &refreshTypeNormal},
{true, true, &refreshTypeHard},
}
for _, testCase := range testCases {
t.Run(fmt.Sprintf("hardRefresh=%t refresh=%t", testCase.hardRefresh, testCase.refresh), func(t *testing.T) {
refreshType := getRefreshType(testCase.refresh, testCase.hardRefresh)
if testCase.expected == nil {
assert.Nil(t, refreshType)
} else {
assert.NotNil(t, refreshType)
assert.Equal(t, *testCase.expected, *refreshType)
}
})
}
}
func TestFindRevisionHistoryWithoutPassedId(t *testing.T) {
histories := v1alpha1.RevisionHistories{}
histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
histories = append(histories, v1alpha1.RevisionHistory{ID: 3})
status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.AppHealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}
application := v1alpha1.Application{
Status: status,
}
history, err := findRevisionHistory(&application, -1)
require.NoError(t, err, "Find revision history should fail without errors")
require.NotNil(t, history, "History should be found")
}
func TestPrintTreeViewAppGet(t *testing.T) {
var nodes [3]v1alpha1.ResourceNode
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"}
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"}}
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"}
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"}}
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"}
nodeMapping := make(map[string]v1alpha1.ResourceNode)
mapParentToChild := make(map[string][]string)
parentNode := make(map[string]struct{})
for _, node := range nodes {
nodeMapping[node.UID] = node
if len(node.ParentRefs) > 0 {
_, ok := mapParentToChild[node.ParentRefs[0].UID]
if !ok {
var temp []string
mapParentToChild[node.ParentRefs[0].UID] = temp
}
mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
} else {
parentNode[node.UID] = struct{}{}
}
}
output, _ := captureOutput(func() error {
printTreeView(nodeMapping, mapParentToChild, parentNode, nil)
return nil
})
assert.Contains(t, output, "Pod")
assert.Contains(t, output, "ReplicaSet")
assert.Contains(t, output, "Rollout")
assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt")
}
func TestPrintTreeViewDetailedAppGet(t *testing.T) {
var nodes [3]v1alpha1.ResourceNode
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"}
nodes[0].Health = &v1alpha1.HealthStatus{Status: "Degraded", Message: "Readiness Gate failed"}
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"}}
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"}
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"}}
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"}
nodeMapping := make(map[string]v1alpha1.ResourceNode)
mapParentToChild := make(map[string][]string)
parentNode := make(map[string]struct{})
for _, node := range nodes {
nodeMapping[node.UID] = node
if len(node.ParentRefs) > 0 {
_, ok := mapParentToChild[node.ParentRefs[0].UID]
if !ok {
var temp []string
mapParentToChild[node.ParentRefs[0].UID] = temp
}
mapParentToChild[node.ParentRefs[0].UID] = append(mapParentToChild[node.ParentRefs[0].UID], node.UID)
} else {
parentNode[node.UID] = struct{}{}
}
}
output, _ := captureOutput(func() error {
printTreeViewDetailed(nodeMapping, mapParentToChild, parentNode, nil)
return nil
})
assert.Contains(t, output, "Pod")
assert.Contains(t, output, "ReplicaSet")
assert.Contains(t, output, "Rollout")
assert.Contains(t, output, "numalogic-rollout-demo-5dcd5457d5-6trpt")
assert.Contains(t, output, "Degraded")
assert.Contains(t, output, "Readiness Gate failed")
}
func TestFindRevisionHistoryWithoutPassedIdWithMultipleSources(t *testing.T) {
histories := v1alpha1.RevisionHistories{}
histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
histories = append(histories, v1alpha1.RevisionHistory{ID: 3})
status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.AppHealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}
application := v1alpha1.Application{
Status: status,
}
history, err := findRevisionHistory(&application, -1)
require.NoError(t, err, "Find revision history should fail without errors")
require.NotNil(t, history, "History should be found")
}
func TestDefaultWaitOptions(t *testing.T) {
watch := watchOpts{
sync: false,
health: false,
operation: false,
suspended: false,
}
opts := getWatchOpts(watch)
assert.True(t, opts.sync)
assert.True(t, opts.health)
assert.True(t, opts.operation)
assert.False(t, opts.suspended)
}
func TestOverrideWaitOptions(t *testing.T) {
watch := watchOpts{
sync: true,
health: false,
operation: false,
suspended: false,
}
opts := getWatchOpts(watch)
assert.True(t, opts.sync)
assert.False(t, opts.health)
assert.False(t, opts.operation)
assert.False(t, opts.suspended)
}
func TestFindRevisionHistoryWithoutPassedIdAndEmptyHistoryList(t *testing.T) {
histories := v1alpha1.RevisionHistories{}
status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.AppHealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}
application := v1alpha1.Application{
Status: status,
}
history, err := findRevisionHistory(&application, -1)
require.Error(t, err, "Find revision history should fail with errors")
require.Nil(t, history, "History should be empty")
require.EqualError(t, err, "application '' should have at least two successful deployments", "Find revision history should fail with correct error message")
}
func TestFindRevisionHistoryWithPassedId(t *testing.T) {
histories := v1alpha1.RevisionHistories{}
histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
histories = append(histories, v1alpha1.RevisionHistory{ID: 3, Revision: "123"})
status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.AppHealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}
application := v1alpha1.Application{
Status: status,
}
history, err := findRevisionHistory(&application, 3)
require.NoError(t, err, "Find revision history should fail without errors")
require.NotNil(t, history, "History should be found")
require.Equal(t, "123", history.Revision, "Failed to find correct history with correct revision")
}
func TestFindRevisionHistoryWithPassedIdThatNotExist(t *testing.T) {
histories := v1alpha1.RevisionHistories{}
histories = append(histories, v1alpha1.RevisionHistory{ID: 1})
histories = append(histories, v1alpha1.RevisionHistory{ID: 2})
histories = append(histories, v1alpha1.RevisionHistory{ID: 3, Revision: "123"})
status := v1alpha1.ApplicationStatus{
Resources: nil,
Sync: v1alpha1.SyncStatus{},
Health: v1alpha1.AppHealthStatus{},
History: histories,
Conditions: nil,
ReconciledAt: nil,
OperationState: nil,
ObservedAt: nil,
SourceType: "",
Summary: v1alpha1.ApplicationSummary{},
}
application := v1alpha1.Application{
Status: status,
}
history, err := findRevisionHistory(&application, 4)
require.Error(t, err, "Find revision history should fail with errors")
require.Nil(t, history, "History should be not found")
require.EqualError(t, err, "application '' does not have deployment id '4' in history", "Find revision history should fail with correct error message")
}
func Test_groupObjsByKey(t *testing.T) {
localObjs := []*unstructured.Unstructured{
{
Object: map[string]any{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]any{
"name": "pod-name",
"namespace": "default",
},
},
},
{
Object: map[string]any{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "CustomResourceDefinition",
"metadata": map[string]any{
"name": "certificates.cert-manager.io",
},
},
},
}
liveObjs := []*unstructured.Unstructured{
{
Object: map[string]any{
"apiVersion": "v1",
"kind": "Pod",
"metadata": map[string]any{
"name": "pod-name",
"namespace": "default",
},
},
},
{
Object: map[string]any{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "CustomResourceDefinition",
"metadata": map[string]any{
"name": "certificates.cert-manager.io",
},
},
},
}
expected := map[kube.ResourceKey]*unstructured.Unstructured{
{Group: "", Kind: "Pod", Namespace: "default", Name: "pod-name"}: localObjs[0],
{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition", Namespace: "", Name: "certificates.cert-manager.io"}: localObjs[1],
}
objByKey := groupObjsByKey(localObjs, liveObjs, "default")
assert.Equal(t, expected, objByKey)
}
func TestFormatSyncPolicy(t *testing.T) {
t.Run("Policy not defined", func(t *testing.T) {
app := v1alpha1.Application{}
policy := formatSyncPolicy(app)
require.Equalf(t, "Manual", policy, "Incorrect policy %q, should be Manual", policy)
})
t.Run("Auto policy", func(t *testing.T) {
app := v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{},
},
},
}
policy := formatSyncPolicy(app)
require.Equalf(t, "Auto", policy, "Incorrect policy %q, should be Auto", policy)
})
t.Run("Auto policy with prune", func(t *testing.T) {
app := v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
},
}
policy := formatSyncPolicy(app)
require.Equalf(t, "Auto-Prune", policy, "Incorrect policy %q, should be Auto-Prune", policy)
})
}
func TestFormatConditionSummary(t *testing.T) {
t.Run("No conditions are defined", func(t *testing.T) {
app := v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
},
}
summary := formatConditionsSummary(app)
require.Equalf(t, "<none>", summary, "Incorrect summary %q, should be <none>", summary)
})
t.Run("Few conditions are defined", func(t *testing.T) {
app := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{
Conditions: []v1alpha1.ApplicationCondition{
{
Type: "type1",
},
{
Type: "type1",
},
{
Type: "type2",
},
},
},
}
summary := formatConditionsSummary(app)
require.Equalf(t, "type1(2),type2", summary, "Incorrect summary %q, should be type1(2),type2", summary)
})
t.Run("Conditions are sorted for idempotent summary", func(t *testing.T) {
app := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{
Conditions: []v1alpha1.ApplicationCondition{
{
Type: "type2",
},
{
Type: "type1",
},
{
Type: "type1",
},
},
},
}
summary := formatConditionsSummary(app)
require.Equalf(t, "type1(2),type2", summary, "Incorrect summary %q, should be type1(2),type2", summary)
})
}
func TestPrintOperationResult(t *testing.T) {
t.Run("Operation state is empty", func(t *testing.T) {
output, _ := captureOutput(func() error {
printOperationResult(nil)
return nil
})
require.Emptyf(t, output, "Incorrect print operation output %q, should be ''", output)
})
t.Run("Operation state sync result is not empty", func(t *testing.T) {
time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
output, _ := captureOutput(func() error {
printOperationResult(&v1alpha1.OperationState{
SyncResult: &v1alpha1.SyncOperationResult{Revision: "revision"},
FinishedAt: &time,
})
return nil
})
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"
require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
})
t.Run("Operation state sync result with message is not empty", func(t *testing.T) {
time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
output, _ := captureOutput(func() error {
printOperationResult(&v1alpha1.OperationState{
SyncResult: &v1alpha1.SyncOperationResult{Revision: "revision"},
FinishedAt: &time,
Message: "test",
})
return nil
})
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"
require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
})
}
func TestPrintApplicationHistoryTable(t *testing.T) {
histories := []v1alpha1.RevisionHistory{
{
ID: 1,
Source: v1alpha1.ApplicationSource{
TargetRevision: "1",
RepoURL: "test",
},
},
{
ID: 2,
Source: v1alpha1.ApplicationSource{
TargetRevision: "2",
RepoURL: "test",
},
},
{
ID: 3,
Source: v1alpha1.ApplicationSource{
TargetRevision: "3",
RepoURL: "test",
},
},
}
output, _ := captureOutput(func() error {
printApplicationHistoryTable(histories)
return nil
})
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"
require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
}
func TestPrintApplicationHistoryTableWithMultipleSources(t *testing.T) {
histories := []v1alpha1.RevisionHistory{
{
ID: 0,
Source: v1alpha1.ApplicationSource{
TargetRevision: "0",
RepoURL: "test",
},
},
{
ID: 1,
Revisions: []string{
"1a",
"1b",
},
// added Source just for testing the fuction
Source: v1alpha1.ApplicationSource{
TargetRevision: "-1",
RepoURL: "ignore",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "1a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "1b",
},
},
},
{
ID: 2,
Revisions: []string{
"2a",
"2b",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "2a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "2b",
},
},
},
{
ID: 3,
Revisions: []string{
"3a",
"3b",
},
Sources: v1alpha1.ApplicationSources{
v1alpha1.ApplicationSource{
RepoURL: "test-1",
TargetRevision: "3a",
},
v1alpha1.ApplicationSource{
RepoURL: "test-2",
TargetRevision: "3b",
},
},
},
}
output, _ := captureOutput(func() error {
printApplicationHistoryTable(histories)
return nil
})
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"
require.Equalf(t, output, expectation, "Incorrect print operation output %q, should be %q", output, expectation)
}
func TestPrintAppSummaryTable(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
Source: &v1alpha1.ApplicationSource{
RepoURL: "test",
TargetRevision: "master",
Path: "/test",
Helm: &v1alpha1.ApplicationSourceHelm{
ValueFiles: []string{"path1", "path2"},
},
Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
},
},
Status: v1alpha1.ApplicationStatus{
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
},
Health: v1alpha1.AppHealthStatus{
Status: health.HealthStatusProgressing,
},
},
}
windows := &v1alpha1.SyncWindows{
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Applications: []string{
"*-prod",
},
ManualSync: true,
},
{
Kind: "deny",
Schedule: "0 0 * * *",
Duration: "24h",
Namespaces: []string{
"default",
},
},
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Clusters: []string{
"in-cluster",
"cluster1",
},
},
}
printAppSummaryTable(app, "url", windows)
return nil
})
expectation := `Name: argocd/test
Project: default
Server: local
Namespace: argocd
URL: url
Source:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
SyncWindow: Sync Denied
Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
Sync Policy: Automated (Prune)
Sync Status: OutOfSync from master
Health Status: Progressing
`
assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation)
}
func TestPrintAppSummaryTable_MultipleSources(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
Sources: v1alpha1.ApplicationSources{
{
RepoURL: "test",
TargetRevision: "master",
Path: "/test",
Helm: &v1alpha1.ApplicationSourceHelm{
ValueFiles: []string{"path1", "path2"},
},
Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
}, {
RepoURL: "test2",
TargetRevision: "master2",
Path: "/test2",
},
},
},
Status: v1alpha1.ApplicationStatus{
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
},
Health: v1alpha1.AppHealthStatus{
Status: health.HealthStatusProgressing,
},
},
}
windows := &v1alpha1.SyncWindows{
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Applications: []string{
"*-prod",
},
ManualSync: true,
},
{
Kind: "deny",
Schedule: "0 0 * * *",
Duration: "24h",
Namespaces: []string{
"default",
},
},
{
Kind: "allow",
Schedule: "0 0 * * *",
Duration: "24h",
Clusters: []string{
"in-cluster",
"cluster1",
},
},
}
printAppSummaryTable(app, "url", windows)
return nil
})
expectation := `Name: argocd/test
Project: default
Server: local
Namespace: argocd
URL: url
Sources:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
- Repo: test2
Target: master2
Path: /test2
SyncWindow: Sync Denied
Assigned Windows: allow:0 0 * * *:24h,deny:0 0 * * *:24h,allow:0 0 * * *:24h
Sync Policy: Automated (Prune)
Sync Status: OutOfSync from master
Health Status: Progressing
`
assert.Equalf(t, expectation, output, "Incorrect print app summary output %q, should be %q", output, expectation)
}
func TestPrintAppConditions(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{
Conditions: []v1alpha1.ApplicationCondition{
{
Type: v1alpha1.ApplicationConditionDeletionError,
Message: "test",
},
{
Type: v1alpha1.ApplicationConditionExcludedResourceWarning,
Message: "test2",
},
{
Type: v1alpha1.ApplicationConditionRepeatedResourceWarning,
Message: "test3",
},
},
},
}
printAppConditions(os.Stdout, app)
return nil
})
expectation := "CONDITION\tMESSAGE\tLAST TRANSITION\nDeletionError\ttest\t<nil>\nExcludedResourceWarning\ttest2\t<nil>\nRepeatedResourceWarning\ttest3\t<nil>\n"
require.Equalf(t, output, expectation, "Incorrect print app conditions output %q, should be %q", output, expectation)
}
func TestPrintParams(t *testing.T) {
testCases := []struct {
name string
app *v1alpha1.Application
sourcePosition int
expectedOutput string
}{
{
name: "Single Source application with valid helm parameters",
app: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
Helm: &v1alpha1.ApplicationSourceHelm{
Parameters: []v1alpha1.HelmParameter{
{
Name: "name1",
Value: "value1",
},
{
Name: "name2",
Value: "value2",
},
{
Name: "name3",
Value: "value3",
},
},
},
},
},
},
sourcePosition: -1,
expectedOutput: "\n\nNAME VALUE\nname1 value1\nname2 value2\nname3 value3\n",
},
{
name: "Multi-source application with a valid Source Position",
app: &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Sources: []v1alpha1.ApplicationSource{
{
Helm: &v1alpha1.ApplicationSourceHelm{
Parameters: []v1alpha1.HelmParameter{
{
Name: "nameA",
Value: "valueA",
},
},
},
},
{
Helm: &v1alpha1.ApplicationSourceHelm{
Parameters: []v1alpha1.HelmParameter{
{
Name: "nameB",
Value: "valueB",
},
},
},
},
},
},
},
sourcePosition: 1,
expectedOutput: "\n\nNAME VALUE\nnameA valueA\n",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
output, _ := captureOutput(func() error {
printParams(tc.app, tc.sourcePosition)
return nil
})
require.Equalf(t, tc.expectedOutput, output, "Incorrect print params output %q, should be %q\n", output, tc.expectedOutput)
})
}
}
func TestAppUrlDefault(t *testing.T) {
t.Run("Plain text", func(t *testing.T) {
result := appURLDefault(argocdclient.NewClientOrDie(&argocdclient.ClientOptions{
ServerAddr: "localhost:80",
PlainText: true,
}), "test")
expectation := "http://localhost:80/applications/test"
require.Equalf(t, result, expectation, "Incorrect url %q, should be %q", result, expectation)
})
t.Run("https", func(t *testing.T) {
result := appURLDefault(argocdclient.NewClientOrDie(&argocdclient.ClientOptions{
ServerAddr: "localhost:443",
PlainText: false,
}), "test")
expectation := "https://localhost/applications/test"
require.Equalf(t, result, expectation, "Incorrect url %q, should be %q", result, expectation)
})
}
func TestTruncateString(t *testing.T) {
result := truncateString("argocdtool", 2)
expectation := "ar..."
require.Equalf(t, result, expectation, "Incorrect truncate string %q, should be %q", result, expectation)
}
func TestGetService(t *testing.T) {
t.Run("Server", func(t *testing.T) {
app := &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "test-server",
},
},
}
result := getServer(app)
expectation := "test-server"
require.Equal(t, result, expectation, "Incorrect server %q, should be %q", result, expectation)
})
t.Run("Name", func(t *testing.T) {
app := &v1alpha1.Application{
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Name: "test-name",
},
},
}
result := getServer(app)
expectation := "test-name"
require.Equal(t, result, expectation, "Incorrect server name %q, should be %q", result, expectation)
})
}
func TestTargetObjects(t *testing.T) {
resources := []*v1alpha1.ResourceDiff{
{
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\":{}}}",
},
{
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\":{}}}",
},
}
objects, err := targetObjects(resources)
require.NoError(t, err, "operation should finish without error")
require.Lenf(t, objects, 2, "incorrect number of objects %v, should be 2", len(objects))
require.Equalf(t, "test-helm-guestbook", objects[0].GetName(), "incorrect name %q, should be %q", objects[0].GetName(), "test-helm-guestbook")
}
func TestTargetObjects_invalid(t *testing.T) {
resources := []*v1alpha1.ResourceDiff{{TargetState: "{"}}
_, err := targetObjects(resources)
assert.Error(t, err)
}
func TestCheckForDeleteEvent(t *testing.T) {
fakeClient := new(fakeAcdClient)
checkForDeleteEvent(t.Context(), fakeClient, "testApp")
}
func TestPrintApplicationNames(t *testing.T) {
output, _ := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
printApplicationNames([]v1alpha1.Application{*app, *app})
return nil
})
expectation := "test\ntest\n"
require.Equalf(t, output, expectation, "Incorrect print params output %q, should be %q", output, expectation)
}
func Test_unset(t *testing.T) {
kustomizeSource := &v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{
IgnoreMissingComponents: true,
NamePrefix: "some-prefix",
NameSuffix: "some-suffix",
Version: "123",
Images: v1alpha1.KustomizeImages{
"old1=new:tag",
"old2=new:tag",
},
Replicas: []v1alpha1.KustomizeReplica{
{
Name: "my-deployment",
Count: intstr.FromInt(2),
},
{
Name: "my-statefulset",
Count: intstr.FromInt(4),
},
},
},
}
helmSource := &v1alpha1.ApplicationSource{
Helm: &v1alpha1.ApplicationSourceHelm{
IgnoreMissingValueFiles: true,
Parameters: []v1alpha1.HelmParameter{
{
Name: "name-1",
Value: "value-1",
},
{
Name: "name-2",
Value: "value-2",
},
},
PassCredentials: true,
ValuesObject: &runtime.RawExtension{Raw: []byte("some: yaml")},
ValueFiles: []string{
"values-1.yaml",
"values-2.yaml",
},
},
}
pluginSource := &v1alpha1.ApplicationSource{
Plugin: &v1alpha1.ApplicationSourcePlugin{
Env: v1alpha1.Env{
{
Name: "env-1",
Value: "env-value-1",
},
{
Name: "env-2",
Value: "env-value-2",
},
},
},
}
assert.Equal(t, "some-prefix", kustomizeSource.Kustomize.NamePrefix)
updated, nothingToUnset := unset(kustomizeSource, unsetOpts{namePrefix: true})
assert.Empty(t, kustomizeSource.Kustomize.NamePrefix)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{namePrefix: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Equal(t, "some-suffix", kustomizeSource.Kustomize.NameSuffix)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{nameSuffix: true})
assert.Empty(t, kustomizeSource.Kustomize.NameSuffix)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{nameSuffix: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Equal(t, "123", kustomizeSource.Kustomize.Version)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeVersion: true})
assert.Empty(t, kustomizeSource.Kustomize.Version)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeVersion: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, kustomizeSource.Kustomize.Images, 2)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeImages: []string{"old1=new:tag"}})
assert.Len(t, kustomizeSource.Kustomize.Images, 1)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeImages: []string{"old1=new:tag"}})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, kustomizeSource.Kustomize.Replicas, 2)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}})
assert.Len(t, kustomizeSource.Kustomize.Replicas, 1)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{kustomizeReplicas: []string{"my-deployment"}})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.True(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
assert.False(t, kustomizeSource.Kustomize.IgnoreMissingComponents)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(kustomizeSource, unsetOpts{ignoreMissingComponents: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, helmSource.Helm.Parameters, 2)
updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
assert.Len(t, helmSource.Helm.Parameters, 1)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(helmSource, unsetOpts{parameters: []string{"name-1"}})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, helmSource.Helm.ValueFiles, 2)
updated, nothingToUnset = unset(helmSource, unsetOpts{valuesFiles: []string{"values-1.yaml"}})
assert.Len(t, helmSource.Helm.ValueFiles, 1)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(helmSource, unsetOpts{valuesFiles: []string{"values-1.yaml"}})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Equal(t, "some: yaml", helmSource.Helm.ValuesString())
updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true})
assert.Empty(t, helmSource.Helm.ValuesString())
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(helmSource, unsetOpts{valuesLiteral: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.True(t, helmSource.Helm.IgnoreMissingValueFiles)
updated, nothingToUnset = unset(helmSource, unsetOpts{ignoreMissingValueFiles: true})
assert.False(t, helmSource.Helm.IgnoreMissingValueFiles)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(helmSource, unsetOpts{ignoreMissingValueFiles: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.True(t, helmSource.Helm.PassCredentials)
updated, nothingToUnset = unset(helmSource, unsetOpts{passCredentials: true})
assert.False(t, helmSource.Helm.PassCredentials)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(helmSource, unsetOpts{passCredentials: true})
assert.False(t, updated)
assert.False(t, nothingToUnset)
assert.Len(t, pluginSource.Plugin.Env, 2)
updated, nothingToUnset = unset(pluginSource, unsetOpts{pluginEnvs: []string{"env-1"}})
assert.Len(t, pluginSource.Plugin.Env, 1)
assert.True(t, updated)
assert.False(t, nothingToUnset)
updated, nothingToUnset = unset(pluginSource, unsetOpts{pluginEnvs: []string{"env-1"}})
assert.False(t, updated)
assert.False(t, nothingToUnset)
}
func Test_unset_nothingToUnset(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
source v1alpha1.ApplicationSource
}{
{"kustomize", v1alpha1.ApplicationSource{Kustomize: &v1alpha1.ApplicationSourceKustomize{}}},
{"helm", v1alpha1.ApplicationSource{Helm: &v1alpha1.ApplicationSourceHelm{}}},
{"plugin", v1alpha1.ApplicationSource{Plugin: &v1alpha1.ApplicationSourcePlugin{}}},
}
for _, testCase := range testCases {
testCaseCopy := testCase
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
updated, nothingToUnset := unset(&testCaseCopy.source, unsetOpts{})
assert.False(t, updated)
assert.True(t, nothingToUnset)
})
}
}
func TestFilterAppResources(t *testing.T) {
// App resources
var (
appReplicaSet1 = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name1",
}
appReplicaSet2 = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name2",
}
appJob = v1alpha1.ResourceStatus{
Group: "batch",
Kind: "Job",
Namespace: "default",
Name: "job-name",
}
appService1 = v1alpha1.ResourceStatus{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name1",
}
appService2 = v1alpha1.ResourceStatus{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name2",
}
appDeployment = v1alpha1.ResourceStatus{
Group: "apps",
Kind: "Deployment",
Namespace: "default",
Name: "deployment-name",
}
)
app := v1alpha1.Application{
Status: v1alpha1.ApplicationStatus{
Resources: []v1alpha1.ResourceStatus{
appReplicaSet1, appReplicaSet2, appJob, appService1, appService2, appDeployment,
},
},
}
// Resource filters
var (
blankValues = v1alpha1.SyncOperationResource{
Group: "",
Kind: "",
Name: "",
Namespace: "",
Exclude: false,
}
// *:*:*
includeAllResources = v1alpha1.SyncOperationResource{
Group: "*",
Kind: "*",
Name: "*",
Namespace: "",
Exclude: false,
}
// !*:*:*
excludeAllResources = v1alpha1.SyncOperationResource{
Group: "*",
Kind: "*",
Name: "*",
Namespace: "",
Exclude: true,
}
// *:Service:*
includeAllServiceResources = v1alpha1.SyncOperationResource{
Group: "*",
Kind: "Service",
Name: "*",
Namespace: "",
Exclude: false,
}
// !*:Service:*
excludeAllServiceResources = v1alpha1.SyncOperationResource{
Group: "*",
Kind: "Service",
Name: "*",
Namespace: "",
Exclude: true,
}
// apps:ReplicaSet:*
includeAllReplicaSetResource = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Name: "*",
Namespace: "",
Exclude: false,
}
// apps:ReplicaSet:replicaSet-name1
includeReplicaSet1Resource = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Name: "replicaSet-name1",
Namespace: "",
Exclude: false,
}
// !apps:ReplicaSet:replicaSet-name2
excludeReplicaSet2Resource = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Name: "replicaSet-name2",
Namespace: "",
Exclude: true,
}
)
// Filtered resources
var (
replicaSet1 = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name1",
}
replicaSet2 = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "ReplicaSet",
Namespace: "default",
Name: "replicaSet-name2",
}
job = v1alpha1.SyncOperationResource{
Group: "batch",
Kind: "Job",
Namespace: "default",
Name: "job-name",
}
service1 = v1alpha1.SyncOperationResource{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name1",
}
service2 = v1alpha1.SyncOperationResource{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name2",
}
deployment = v1alpha1.SyncOperationResource{
Group: "apps",
Kind: "Deployment",
Namespace: "default",
Name: "deployment-name",
}
)
tests := []struct {
testName string
selectedResources []*v1alpha1.SyncOperationResource
expectedResult []*v1alpha1.SyncOperationResource
}{
// --resource apps:ReplicaSet:replicaSet-name1 --resource *:Service:*
{
testName: "Include ReplicaSet replicaSet-name1 resource and all service resources",
selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources, &includeReplicaSet1Resource},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &service1, &service2},
},
// --resource apps:ReplicaSet:replicaSet-name1 --resource !*:Service:*
{
testName: "Include ReplicaSet replicaSet-name1 resource and exclude all service resources",
selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources, &includeReplicaSet1Resource},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1},
},
// --resource !apps:ReplicaSet:replicaSet-name2 --resource !*:Service:*
{
testName: "Exclude ReplicaSet replicaSet-name2 resource and all service resources",
selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource, &excludeAllServiceResources},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &job, &deployment},
},
// --resource !apps:ReplicaSet:replicaSet-name2
{
testName: "Exclude ReplicaSet replicaSet-name2 resource",
selectedResources: []*v1alpha1.SyncOperationResource{&excludeReplicaSet2Resource},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &job, &service1, &service2, &deployment},
},
// --resource apps:ReplicaSet:replicaSet-name1
{
testName: "Include ReplicaSet replicaSet-name1 resource",
selectedResources: []*v1alpha1.SyncOperationResource{&includeReplicaSet1Resource},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1},
},
// --resource apps:ReplicaSet:* --resource !apps:ReplicaSet:replicaSet-name2
{
testName: "Include All ReplicaSet resource and exclude replicaSet-name1 resource",
selectedResources: []*v1alpha1.SyncOperationResource{&includeAllReplicaSetResource, &excludeReplicaSet2Resource},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1},
},
// --resource !*:Service:*
{
testName: "Exclude Service resources",
selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllServiceResources},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &deployment},
},
// --resource *:Service:*
{
testName: "Include Service resources",
selectedResources: []*v1alpha1.SyncOperationResource{&includeAllServiceResources},
expectedResult: []*v1alpha1.SyncOperationResource{&service1, &service2},
},
// --resource !*:*:*
{
testName: "Exclude all resources",
selectedResources: []*v1alpha1.SyncOperationResource{&excludeAllResources},
expectedResult: nil,
},
// --resource *:*:*
{
testName: "Include all resources",
selectedResources: []*v1alpha1.SyncOperationResource{&includeAllResources},
expectedResult: []*v1alpha1.SyncOperationResource{&replicaSet1, &replicaSet2, &job, &service1, &service2, &deployment},
},
{
testName: "No Filters",
selectedResources: []*v1alpha1.SyncOperationResource{&blankValues},
expectedResult: nil,
},
{
testName: "Empty Filter",
selectedResources: []*v1alpha1.SyncOperationResource{},
expectedResult: nil,
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
filteredResources := filterAppResources(&app, test.selectedResources)
assert.Equal(t, test.expectedResult, filteredResources)
})
}
}
func TestParseSelectedResources(t *testing.T) {
resources := []string{
"v1alpha:Application:test",
"v1alpha:Application:namespace/test",
"!v1alpha:Application:test",
"apps:Deployment:default/test",
"!*:*:*",
}
operationResources, err := parseSelectedResources(resources)
require.NoError(t, err)
assert.Len(t, operationResources, 5)
assert.Equal(t, v1alpha1.SyncOperationResource{
Namespace: "",
Name: "test",
Kind: application.ApplicationKind,
Group: "v1alpha",
}, *operationResources[0])
assert.Equal(t, v1alpha1.SyncOperationResource{
Namespace: "namespace",
Name: "test",
Kind: application.ApplicationKind,
Group: "v1alpha",
}, *operationResources[1])
assert.Equal(t, v1alpha1.SyncOperationResource{
Namespace: "",
Name: "test",
Kind: "Application",
Group: "v1alpha",
Exclude: true,
}, *operationResources[2])
assert.Equal(t, v1alpha1.SyncOperationResource{
Namespace: "default",
Name: "test",
Kind: "Deployment",
Group: "apps",
Exclude: false,
}, *operationResources[3])
assert.Equal(t, v1alpha1.SyncOperationResource{
Namespace: "",
Name: "*",
Kind: "*",
Group: "*",
Exclude: true,
}, *operationResources[4])
}
func TestParseSelectedResourcesIncorrect(t *testing.T) {
resources := []string{"v1alpha:test", "v1alpha:Application:namespace/test"}
_, err := parseSelectedResources(resources)
assert.ErrorContains(t, err, "v1alpha:test")
}
func TestParseSelectedResourcesIncorrectNamespace(t *testing.T) {
resources := []string{"v1alpha:Application:namespace/test/unknown"}
_, err := parseSelectedResources(resources)
assert.ErrorContains(t, err, "v1alpha:Application:namespace/test/unknown")
}
func TestParseSelectedResourcesEmptyList(t *testing.T) {
var resources []string
operationResources, err := parseSelectedResources(resources)
require.NoError(t, err)
assert.Empty(t, operationResources)
}
func TestPrintApplicationTableNotWide(t *testing.T) {
output, err := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "app-name",
},
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "http://localhost:8080",
Namespace: "default",
},
Project: "prj",
},
Status: v1alpha1.ApplicationStatus{
Sync: v1alpha1.SyncStatus{
Status: "OutOfSync",
},
Health: v1alpha1.AppHealthStatus{
Status: "Healthy",
},
},
}
output := "table"
printApplicationTable([]v1alpha1.Application{*app, *app}, &output)
return nil
})
require.NoError(t, err)
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"
assert.Equal(t, output, expectation)
}
func TestPrintApplicationTableWide(t *testing.T) {
output, err := captureOutput(func() error {
app := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "app-name",
},
Spec: v1alpha1.ApplicationSpec{
Destination: v1alpha1.ApplicationDestination{
Server: "http://localhost:8080",
Namespace: "default",
},
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps",
Path: "guestbook",
TargetRevision: "123",
},
Project: "prj",
},
Status: v1alpha1.ApplicationStatus{
Sync: v1alpha1.SyncStatus{
Status: "OutOfSync",
},
Health: v1alpha1.AppHealthStatus{
Status: "Healthy",
},
},
}
output := "wide"
printApplicationTable([]v1alpha1.Application{*app, *app}, &output)
return nil
})
require.NoError(t, err)
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"
assert.Equal(t, output, expectation)
}
func TestResourceStateKey(t *testing.T) {
rst := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
}
key := rst.Key()
assert.Equal(t, "group/kind/namespace/name", key)
}
func TestFormatItems(t *testing.T) {
rst := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
Status: "status",
Health: "health",
Hook: "hook",
Message: "message",
}
items := rst.FormatItems()
assert.Equal(t, "group", items[1])
assert.Equal(t, "kind", items[2])
assert.Equal(t, "namespace", items[3])
assert.Equal(t, "name", items[4])
assert.Equal(t, "status", items[5])
assert.Equal(t, "health", items[6])
assert.Equal(t, "hook", items[7])
assert.Equal(t, "message", items[8])
}
func TestMerge(t *testing.T) {
rst := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
Status: "status",
Health: "health",
Hook: "hook",
Message: "message",
}
rstNew := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
Status: "status",
Health: "health",
Hook: "hook2",
Message: "message2",
}
updated := rst.Merge(&rstNew)
assert.True(t, updated)
assert.Equal(t, rstNew.Hook, rst.Hook)
assert.Equal(t, rstNew.Message, rst.Message)
assert.Equal(t, rstNew.Status, rst.Status)
}
func TestMergeWitoutUpdate(t *testing.T) {
rst := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
Status: "status",
Health: "health",
Hook: "hook",
Message: "message",
}
rstNew := resourceState{
Group: "group",
Kind: "kind",
Namespace: "namespace",
Name: "name",
Status: "status",
Health: "health",
Hook: "hook",
Message: "message",
}
updated := rst.Merge(&rstNew)
assert.False(t, updated)
}
func TestCheckResourceStatus(t *testing.T) {
t.Run("Degraded, Suspended and health status passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: true,
degraded: true,
}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Degraded, Suspended and health status failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: true,
degraded: true,
}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.False(t, res)
})
t.Run("Suspended and health status passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: true,
}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Suspended and health status failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: true,
}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.False(t, res)
})
t.Run("Suspended passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: false,
}, string(health.HealthStatusSuspended), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Suspended failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: true,
health: false,
}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.False(t, res)
})
t.Run("Health passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: false,
health: true,
}, string(health.HealthStatusHealthy), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Health failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: false,
health: true,
}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.False(t, res)
})
t.Run("Synced passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Synced failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeOutOfSync), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Degraded passed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: false,
health: false,
degraded: true,
}, string(health.HealthStatusDegraded), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.True(t, res)
})
t.Run("Degraded failed", func(t *testing.T) {
res := checkResourceStatus(watchOpts{
suspended: false,
health: false,
degraded: true,
}, string(health.HealthStatusProgressing), string(v1alpha1.SyncStatusCodeSynced), &v1alpha1.Operation{}, true)
assert.False(t, res)
})
}
func Test_hasAppChanged(t *testing.T) {
type args struct {
appReq *v1alpha1.Application
appRes *v1alpha1.Application
upsert bool
}
tests := []struct {
name string
args args
want bool
}{
{
name: "App has changed - Labels, Annotations, Finalizers empty",
args: args{
appReq: testApp("foo", "default", map[string]string{}, map[string]string{}, []string{}),
appRes: testApp("foo", "foo", nil, nil, nil),
upsert: true,
},
want: true,
},
{
name: "App unchanged - Labels, Annotations, Finalizers populated",
args: args{
appReq: testApp("foo", "default", map[string]string{"foo": "bar"}, map[string]string{"foo": "bar"}, []string{"foo"}),
appRes: testApp("foo", "default", map[string]string{"foo": "bar"}, map[string]string{"foo": "bar"}, []string{"foo"}),
upsert: true,
},
want: false,
},
{
name: "Apps unchanged - Using empty maps/list locally versus server returning nil",
args: args{
appReq: testApp("foo", "default", map[string]string{}, map[string]string{}, []string{}),
appRes: testApp("foo", "default", nil, nil, nil),
upsert: true,
},
want: false,
},
{
name: "App unchanged - Using empty project locally versus server returning default",
args: args{
appReq: testApp("foo", "", map[string]string{}, map[string]string{}, []string{}),
appRes: testApp("foo", "default", nil, nil, nil),
},
want: false,
},
{
name: "App unchanged - From upsert=false",
args: args{
appReq: testApp("foo", "foo", map[string]string{}, map[string]string{}, []string{}),
appRes: testApp("foo", "default", nil, nil, nil),
upsert: false,
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := hasAppChanged(tt.args.appReq, tt.args.appRes, tt.args.upsert)
assert.Equalf(t, tt.want, got, "hasAppChanged() = %v, want %v", got, tt.want)
})
}
}
func testApp(name, project string, labels map[string]string, annotations map[string]string, finalizers []string) *v1alpha1.Application {
return &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: labels,
Annotations: annotations,
Finalizers: finalizers,
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
},
Project: project,
},
}
}
func TestWaitOnApplicationStatus_JSON_YAML_WideOutput(t *testing.T) {
acdClient := &customAcdClient{&fakeAcdClient{}}
ctx := t.Context()
var selectResource []*v1alpha1.SyncOperationResource
watch := watchOpts{
sync: false,
health: false,
operation: true,
suspended: false,
}
watch = getWatchOpts(watch)
output, err := captureOutput(func() error {
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "json")
return nil
},
)
require.NoError(t, err)
assert.True(t, json.Valid([]byte(output)))
output, err = captureOutput(func() error {
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "yaml")
return nil
})
require.NoError(t, err)
err = yaml.Unmarshal([]byte(output), &v1alpha1.Application{})
require.NoError(t, err)
output, _ = captureOutput(func() error {
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 0, watch, selectResource, "")
return nil
})
timeStr := time.Now().Format("2006-01-02T15:04:05-07:00")
expectation := `TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
%s Service default service-name1 Synced Healthy
%s apps Deployment default test Synced Healthy
Name: argocd/test
Project: default
Server: local
Namespace: argocd
URL: http://localhost:8080/applications/app-name
Source:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
SyncWindow: Sync Allowed
Sync Policy: Automated (Prune)
Sync Status: OutOfSync from master
Health Status: Progressing
Operation: Sync
Sync Revision: revision
Phase:
Start: 0001-01-01 00:00:00 +0000 UTC
Finished: 2020-11-10 23:00:00 +0000 UTC
Duration: 2333448h16m18.871345152s
Message: test
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default service-name1 Synced Healthy
apps Deployment default test Synced Healthy
`
expectation = fmt.Sprintf(expectation, timeStr, timeStr)
expectationParts := strings.Split(expectation, "\n")
slices.Sort(expectationParts)
expectationSorted := strings.Join(expectationParts, "\n")
outputParts := strings.Split(output, "\n")
slices.Sort(outputParts)
outputSorted := strings.Join(outputParts, "\n")
// Need to compare sorted since map entries may not keep a specific order during serialization, leading to flakiness.
assert.Equalf(t, expectationSorted, outputSorted, "Incorrect output %q, should be %q (items order doesn't matter)", output, expectation)
}
func TestWaitOnApplicationStatus_JSON_YAML_WideOutput_With_Timeout(t *testing.T) {
acdClient := &customAcdClient{&fakeAcdClient{simulateTimeout: 15}}
ctx := t.Context()
var selectResource []*v1alpha1.SyncOperationResource
watch := watchOpts{
sync: false,
health: false,
operation: true,
suspended: false,
}
watch = getWatchOpts(watch)
output, _ := captureOutput(func() error {
_, _, _ = waitOnApplicationStatus(ctx, acdClient, "app-name", 5, watch, selectResource, "")
return nil
})
timeStr := time.Now().Format("2006-01-02T15:04:05-07:00")
expectation := `TIMESTAMP GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
%s Service default service-name1 Synced Healthy
%s apps Deployment default test Synced Healthy
The command timed out waiting for the conditions to be met.
This is the state of the app after wait timed out:
Name: argocd/test
Project: default
Server: local
Namespace: argocd
URL: http://localhost:8080/applications/app-name
Source:
- Repo: test
Target: master
Path: /test
Helm Values: path1,path2
Name Prefix: prefix
SyncWindow: Sync Allowed
Sync Policy: Automated (Prune)
Sync Status: OutOfSync from master
Health Status: Progressing
Operation: Sync
Sync Revision: revision
Phase:
Start: 0001-01-01 00:00:00 +0000 UTC
Finished: 2020-11-10 23:00:00 +0000 UTC
Duration: 2333448h16m18.871345152s
Message: test
GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default service-name1 Synced Healthy
apps Deployment default test Synced Healthy
`
expectation = fmt.Sprintf(expectation, timeStr, timeStr)
expectationParts := strings.Split(expectation, "\n")
slices.Sort(expectationParts)
expectationSorted := strings.Join(expectationParts, "\n")
outputParts := strings.Split(output, "\n")
slices.Sort(outputParts)
outputSorted := strings.Join(outputParts, "\n")
// Need to compare sorted since map entries may not keep a specific order during serialization, leading to flakiness.
assert.Equalf(t, expectationSorted, outputSorted, "Incorrect output %q, should be %q (items order doesn't matter)", output, expectation)
}
type customAcdClient struct {
*fakeAcdClient
}
func (c *customAcdClient) WatchApplicationWithRetry(ctx context.Context, _ string, _ string) chan *v1alpha1.ApplicationWatchEvent {
appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
_, appClient := c.NewApplicationClientOrDie()
app, _ := appClient.Get(ctx, &applicationpkg.ApplicationQuery{})
newApp := v1alpha1.Application{
TypeMeta: app.TypeMeta,
ObjectMeta: app.ObjectMeta,
Spec: app.Spec,
Status: app.Status,
Operation: app.Operation,
}
go func() {
time.Sleep(time.Duration(c.simulateTimeout) * time.Second)
appEventsCh <- &v1alpha1.ApplicationWatchEvent{
Type: watch.Bookmark,
Application: newApp,
}
close(appEventsCh)
}()
return appEventsCh
}
func (c *customAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
return &fakeConnection{}, &fakeAppServiceClient{}
}
func (c *customAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
return &fakeConnection{}, &fakeSettingsServiceClient{}
}
type fakeConnection struct{}
func (c *fakeConnection) Close() error {
return nil
}
type fakeSettingsServiceClient struct{}
func (f fakeSettingsServiceClient) Get(_ context.Context, _ *settingspkg.SettingsQuery, _ ...grpc.CallOption) (*settingspkg.Settings, error) {
return &settingspkg.Settings{
URL: "http://localhost:8080",
}, nil
}
func (f fakeSettingsServiceClient) GetPlugins(_ context.Context, _ *settingspkg.SettingsQuery, _ ...grpc.CallOption) (*settingspkg.SettingsPluginsResponse, error) {
return nil, nil
}
type fakeAppServiceClient struct{}
func (c *fakeAppServiceClient) Get(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
time := metav1.Date(2020, time.November, 10, 23, 0, 0, 0, time.UTC)
return &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
SyncPolicy: &v1alpha1.SyncPolicy{
Automated: &v1alpha1.SyncPolicyAutomated{
Prune: true,
},
},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "local", Namespace: "argocd"},
Source: &v1alpha1.ApplicationSource{
RepoURL: "test",
TargetRevision: "master",
Path: "/test",
Helm: &v1alpha1.ApplicationSourceHelm{
ValueFiles: []string{"path1", "path2"},
},
Kustomize: &v1alpha1.ApplicationSourceKustomize{NamePrefix: "prefix"},
},
},
Status: v1alpha1.ApplicationStatus{
Resources: []v1alpha1.ResourceStatus{
{
Group: "",
Kind: "Service",
Namespace: "default",
Name: "service-name1",
Status: "Synced",
Health: &v1alpha1.HealthStatus{
Status: health.HealthStatusHealthy,
Message: "health-message",
},
},
{
Group: "apps",
Kind: "Deployment",
Namespace: "default",
Name: "test",
Status: "Synced",
Health: &v1alpha1.HealthStatus{
Status: health.HealthStatusHealthy,
Message: "health-message",
},
},
},
OperationState: &v1alpha1.OperationState{
SyncResult: &v1alpha1.SyncOperationResult{
Revision: "revision",
},
FinishedAt: &time,
Message: "test",
},
Sync: v1alpha1.SyncStatus{
Status: v1alpha1.SyncStatusCodeOutOfSync,
},
Health: v1alpha1.AppHealthStatus{
Status: health.HealthStatusProgressing,
},
},
}, nil
}
func (c *fakeAppServiceClient) List(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (*v1alpha1.ApplicationList, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ListResourceEvents(_ context.Context, _ *applicationpkg.ApplicationResourceEventsQuery, _ ...grpc.CallOption) (*corev1.EventList, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Watch(_ context.Context, _ *applicationpkg.ApplicationQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_WatchClient, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Create(_ context.Context, _ *applicationpkg.ApplicationCreateRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
return nil, nil
}
func (c *fakeAppServiceClient) GetApplicationSyncWindows(_ context.Context, _ *applicationpkg.ApplicationSyncWindowsQuery, _ ...grpc.CallOption) (*applicationpkg.ApplicationSyncWindowsResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) GetOCIMetadata(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.OCIMetadata, error) {
return nil, nil
}
func (c *fakeAppServiceClient) RevisionMetadata(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) {
return nil, nil
}
func (c *fakeAppServiceClient) RevisionChartDetails(_ context.Context, _ *applicationpkg.RevisionMetadataQuery, _ ...grpc.CallOption) (*v1alpha1.ChartDetails, error) {
return nil, nil
}
func (c *fakeAppServiceClient) GetManifests(_ context.Context, _ *applicationpkg.ApplicationManifestQuery, _ ...grpc.CallOption) (*apiclient.ManifestResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) GetManifestsWithFiles(_ context.Context, _ ...grpc.CallOption) (applicationpkg.ApplicationService_GetManifestsWithFilesClient, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Update(_ context.Context, _ *applicationpkg.ApplicationUpdateRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
return nil, nil
}
func (c *fakeAppServiceClient) UpdateSpec(_ context.Context, _ *applicationpkg.ApplicationUpdateSpecRequest, _ ...grpc.CallOption) (*v1alpha1.ApplicationSpec, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Patch(_ context.Context, _ *applicationpkg.ApplicationPatchRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Delete(_ context.Context, _ *applicationpkg.ApplicationDeleteRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Sync(_ context.Context, _ *applicationpkg.ApplicationSyncRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ManagedResources(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (*applicationpkg.ManagedResourcesResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ResourceTree(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (*v1alpha1.ApplicationTree, error) {
return nil, nil
}
func (c *fakeAppServiceClient) WatchResourceTree(_ context.Context, _ *applicationpkg.ResourcesQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_WatchResourceTreeClient, error) {
return nil, nil
}
func (c *fakeAppServiceClient) Rollback(_ context.Context, _ *applicationpkg.ApplicationRollbackRequest, _ ...grpc.CallOption) (*v1alpha1.Application, error) {
return nil, nil
}
func (c *fakeAppServiceClient) TerminateOperation(_ context.Context, _ *applicationpkg.OperationTerminateRequest, _ ...grpc.CallOption) (*applicationpkg.OperationTerminateResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) GetResource(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) PatchResource(_ context.Context, _ *applicationpkg.ApplicationResourcePatchRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResourceResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ListResourceActions(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.ResourceActionsListResponse, error) {
return nil, nil
}
// nolint:staticcheck // ResourceActionRunRequest is deprecated, but we still need to implement it to satisfy the server interface.
func (c *fakeAppServiceClient) RunResourceAction(_ context.Context, _ *applicationpkg.ResourceActionRunRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) RunResourceActionV2(_ context.Context, _ *applicationpkg.ResourceActionRunRequestV2, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) DeleteResource(_ context.Context, _ *applicationpkg.ApplicationResourceDeleteRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) PodLogs(_ context.Context, _ *applicationpkg.ApplicationPodLogsQuery, _ ...grpc.CallOption) (applicationpkg.ApplicationService_PodLogsClient, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ListLinks(_ context.Context, _ *applicationpkg.ListAppLinksRequest, _ ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ListResourceLinks(_ context.Context, _ *applicationpkg.ApplicationResourceRequest, _ ...grpc.CallOption) (*applicationpkg.LinksResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) ServerSideDiff(_ context.Context, _ *applicationpkg.ApplicationServerSideDiffQuery, _ ...grpc.CallOption) (*applicationpkg.ApplicationServerSideDiffResponse, error) {
return nil, nil
}
type fakeAcdClient struct {
simulateTimeout uint
}
func (c *fakeAcdClient) ClientOptions() argocdclient.ClientOptions {
return argocdclient.ClientOptions{}
}
func (c *fakeAcdClient) HTTPClient() (*http.Client, error) { return nil, nil }
func (c *fakeAcdClient) OIDCConfig(context.Context, *settingspkg.Settings) (*oauth2.Config, *oidc.Provider, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoClient() (io.Closer, repositorypkg.RepositoryServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoClientOrDie() (io.Closer, repositorypkg.RepositoryServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewRepoCredsClient() (io.Closer, repocredspkg.RepoCredsServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewRepoCredsClientOrDie() (io.Closer, repocredspkg.RepoCredsServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewCertClient() (io.Closer, certificatepkg.CertificateServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewCertClientOrDie() (io.Closer, certificatepkg.CertificateServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewClusterClient() (io.Closer, clusterpkg.ClusterServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewClusterClientOrDie() (io.Closer, clusterpkg.ClusterServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewGPGKeyClient() (io.Closer, gpgkeypkg.GPGKeyServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewGPGKeyClientOrDie() (io.Closer, gpgkeypkg.GPGKeyServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewApplicationClient() (io.Closer, applicationpkg.ApplicationServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewApplicationSetClient() (io.Closer, applicationsetpkg.ApplicationSetServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewApplicationClientOrDie() (io.Closer, applicationpkg.ApplicationServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewApplicationSetClientOrDie() (io.Closer, applicationsetpkg.ApplicationSetServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewNotificationClient() (io.Closer, notificationpkg.NotificationServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewNotificationClientOrDie() (io.Closer, notificationpkg.NotificationServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewSessionClient() (io.Closer, sessionpkg.SessionServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewSessionClientOrDie() (io.Closer, sessionpkg.SessionServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewSettingsClient() (io.Closer, settingspkg.SettingsServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewSettingsClientOrDie() (io.Closer, settingspkg.SettingsServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewVersionClient() (io.Closer, versionpkg.VersionServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewVersionClientOrDie() (io.Closer, versionpkg.VersionServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewProjectClient() (io.Closer, projectpkg.ProjectServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewProjectClientOrDie() (io.Closer, projectpkg.ProjectServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) NewAccountClient() (io.Closer, accountpkg.AccountServiceClient, error) {
return nil, nil, nil
}
func (c *fakeAcdClient) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceClient) {
return nil, nil
}
func (c *fakeAcdClient) WatchApplicationWithRetry(_ context.Context, _ string, _ string) chan *v1alpha1.ApplicationWatchEvent {
appEventsCh := make(chan *v1alpha1.ApplicationWatchEvent)
go func() {
modifiedEvent := new(v1alpha1.ApplicationWatchEvent)
modifiedEvent.Type = watch.Modified
appEventsCh <- modifiedEvent
deletedEvent := new(v1alpha1.ApplicationWatchEvent)
deletedEvent.Type = watch.Deleted
appEventsCh <- deletedEvent
}()
return appEventsCh
}