mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
688 lines
24 KiB
Go
688 lines
24 KiB
Go
package argo
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/argoproj/gitops-engine/pkg/utils/io"
|
|
"github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/mock"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/watch"
|
|
testcore "k8s.io/client-go/testing"
|
|
"k8s.io/client-go/tools/cache"
|
|
|
|
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
|
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/fake"
|
|
"github.com/argoproj/argo-cd/pkg/client/informers/externalversions/application/v1alpha1"
|
|
applisters "github.com/argoproj/argo-cd/pkg/client/listers/application/v1alpha1"
|
|
"github.com/argoproj/argo-cd/reposerver/apiclient"
|
|
"github.com/argoproj/argo-cd/reposerver/apiclient/mocks"
|
|
dbmocks "github.com/argoproj/argo-cd/util/db/mocks"
|
|
)
|
|
|
|
func TestRefreshApp(t *testing.T) {
|
|
var testApp argoappv1.Application
|
|
testApp.Name = "test-app"
|
|
testApp.Namespace = "default"
|
|
appClientset := appclientset.NewSimpleClientset(&testApp)
|
|
appIf := appClientset.ArgoprojV1alpha1().Applications("default")
|
|
_, err := RefreshApp(appIf, "test-app", argoappv1.RefreshTypeNormal)
|
|
assert.Nil(t, err)
|
|
// For some reason, the fake Application interface doesn't reflect the patch status after Patch(),
|
|
// so can't verify it was set in unit tests.
|
|
//_, ok := newApp.Annotations[common.AnnotationKeyRefresh]
|
|
//assert.True(t, ok)
|
|
}
|
|
|
|
func TestGetAppProjectWithNoProjDefined(t *testing.T) {
|
|
projName := "default"
|
|
namespace := "default"
|
|
|
|
testProj := &argoappv1.AppProject{
|
|
ObjectMeta: metav1.ObjectMeta{Name: projName, Namespace: namespace},
|
|
}
|
|
|
|
var testApp argoappv1.Application
|
|
testApp.Name = "test-app"
|
|
testApp.Namespace = namespace
|
|
appClientset := appclientset.NewSimpleClientset(testProj)
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}
|
|
informer := v1alpha1.NewAppProjectInformer(appClientset, namespace, 0, indexers)
|
|
go informer.Run(ctx.Done())
|
|
cache.WaitForCacheSync(ctx.Done(), informer.HasSynced)
|
|
proj, err := GetAppProject(&testApp.Spec, applisters.NewAppProjectLister(informer.GetIndexer()), namespace)
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, proj.Name, projName)
|
|
}
|
|
|
|
func TestWaitForRefresh(t *testing.T) {
|
|
appClientset := appclientset.NewSimpleClientset()
|
|
|
|
// Verify timeout
|
|
appIf := appClientset.ArgoprojV1alpha1().Applications("default")
|
|
oneHundredMs := 100 * time.Millisecond
|
|
app, err := WaitForRefresh(context.Background(), appIf, "test-app", &oneHundredMs)
|
|
assert.NotNil(t, err)
|
|
assert.Nil(t, app)
|
|
assert.Contains(t, strings.ToLower(err.Error()), "deadline exceeded")
|
|
|
|
// Verify success
|
|
var testApp argoappv1.Application
|
|
testApp.Name = "test-app"
|
|
testApp.Namespace = "default"
|
|
appClientset = appclientset.NewSimpleClientset()
|
|
|
|
appIf = appClientset.ArgoprojV1alpha1().Applications("default")
|
|
watcher := watch.NewFake()
|
|
appClientset.PrependWatchReactor("applications", testcore.DefaultWatchReactor(watcher, nil))
|
|
// simulate add/update/delete watch events
|
|
go watcher.Add(&testApp)
|
|
app, err = WaitForRefresh(context.Background(), appIf, "test-app", &oneHundredMs)
|
|
assert.Nil(t, err)
|
|
assert.NotNil(t, app)
|
|
}
|
|
|
|
func TestContainsSyncResource(t *testing.T) {
|
|
var (
|
|
blankUnstructured unstructured.Unstructured
|
|
blankResource argoappv1.SyncOperationResource
|
|
helloResource = argoappv1.SyncOperationResource{Name: "hello"}
|
|
)
|
|
tables := []struct {
|
|
u *unstructured.Unstructured
|
|
rr []argoappv1.SyncOperationResource
|
|
expected bool
|
|
}{
|
|
{&blankUnstructured, []argoappv1.SyncOperationResource{}, false},
|
|
{&blankUnstructured, []argoappv1.SyncOperationResource{blankResource}, true},
|
|
{&blankUnstructured, []argoappv1.SyncOperationResource{helloResource}, false},
|
|
}
|
|
|
|
for _, table := range tables {
|
|
if out := ContainsSyncResource(table.u.GetName(), table.u.GetNamespace(), table.u.GroupVersionKind(), table.rr); out != table.expected {
|
|
t.Errorf("Expected %t for slice %+v contains resource %+v; instead got %t", table.expected, table.rr, table.u, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestNilOutZerValueAppSources verifies we will nil out app source specs when they are their zero-value
|
|
func TestNilOutZerValueAppSources(t *testing.T) {
|
|
var spec *argoappv1.ApplicationSpec
|
|
{
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Kustomize: &argoappv1.ApplicationSourceKustomize{NamePrefix: "foo"}}})
|
|
assert.NotNil(t, spec.Source.Kustomize)
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Kustomize: &argoappv1.ApplicationSourceKustomize{NamePrefix: ""}}})
|
|
assert.Nil(t, spec.Source.Kustomize)
|
|
}
|
|
{
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Kustomize: &argoappv1.ApplicationSourceKustomize{NameSuffix: "foo"}}})
|
|
assert.NotNil(t, spec.Source.Kustomize)
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Kustomize: &argoappv1.ApplicationSourceKustomize{NameSuffix: ""}}})
|
|
assert.Nil(t, spec.Source.Kustomize)
|
|
}
|
|
{
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Helm: &argoappv1.ApplicationSourceHelm{ValueFiles: []string{"values.yaml"}}}})
|
|
assert.NotNil(t, spec.Source.Helm)
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Helm: &argoappv1.ApplicationSourceHelm{ValueFiles: []string{}}}})
|
|
assert.Nil(t, spec.Source.Helm)
|
|
}
|
|
{
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Ksonnet: &argoappv1.ApplicationSourceKsonnet{Environment: "foo"}}})
|
|
assert.NotNil(t, spec.Source.Ksonnet)
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Ksonnet: &argoappv1.ApplicationSourceKsonnet{Environment: ""}}})
|
|
assert.Nil(t, spec.Source.Ksonnet)
|
|
}
|
|
{
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}}})
|
|
assert.NotNil(t, spec.Source.Directory)
|
|
spec = NormalizeApplicationSpec(&argoappv1.ApplicationSpec{Source: argoappv1.ApplicationSource{Directory: &argoappv1.ApplicationSourceDirectory{Recurse: false}}})
|
|
assert.Nil(t, spec.Source.Directory)
|
|
}
|
|
}
|
|
|
|
func TestValidatePermissionsEmptyDestination(t *testing.T) {
|
|
conditions, err := ValidatePermissions(context.Background(), &argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{RepoURL: "https://github.com/argoproj/argo-cd", Path: "."},
|
|
}, &argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
SourceRepos: []string{"*"},
|
|
Destinations: []argoappv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
|
},
|
|
}, nil)
|
|
assert.NoError(t, err)
|
|
assert.ElementsMatch(t, conditions, []argoappv1.ApplicationCondition{{Type: argoappv1.ApplicationConditionInvalidSpecError, Message: "Destination server and/or namespace missing from app spec"}})
|
|
}
|
|
|
|
func TestValidateChartWithoutRevision(t *testing.T) {
|
|
conditions, err := ValidatePermissions(context.Background(), &argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{RepoURL: "https://kubernetes-charts-incubator.storage.googleapis.com/", Chart: "myChart", TargetRevision: ""},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: "https://kubernetes.default.svc", Namespace: "default",
|
|
},
|
|
}, &argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
SourceRepos: []string{"*"},
|
|
Destinations: []argoappv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
|
},
|
|
}, nil)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, 1, len(conditions))
|
|
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, conditions[0].Type)
|
|
assert.Equal(t, "spec.source.targetRevision is required if the manifest source is a helm chart", conditions[0].Message)
|
|
}
|
|
|
|
func Test_enrichSpec(t *testing.T) {
|
|
t.Run("Empty", func(t *testing.T) {
|
|
spec := &argoappv1.ApplicationSpec{}
|
|
enrichSpec(spec, &apiclient.RepoAppDetailsResponse{})
|
|
assert.Empty(t, spec.Destination.Server)
|
|
assert.Empty(t, spec.Destination.Namespace)
|
|
})
|
|
t.Run("Ksonnet", func(t *testing.T) {
|
|
spec := &argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
Ksonnet: &argoappv1.ApplicationSourceKsonnet{
|
|
Environment: "qa",
|
|
},
|
|
},
|
|
}
|
|
response := &apiclient.RepoAppDetailsResponse{
|
|
Ksonnet: &apiclient.KsonnetAppSpec{
|
|
Environments: map[string]*apiclient.KsonnetEnvironment{
|
|
"prod": {
|
|
Destination: &apiclient.KsonnetEnvironmentDestination{
|
|
Server: "my-server",
|
|
Namespace: "my-namespace",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
enrichSpec(spec, response)
|
|
assert.Empty(t, spec.Destination.Server)
|
|
assert.Empty(t, spec.Destination.Namespace)
|
|
|
|
spec.Source.Ksonnet.Environment = "prod"
|
|
enrichSpec(spec, response)
|
|
assert.Equal(t, "my-server", spec.Destination.Server)
|
|
assert.Equal(t, "my-namespace", spec.Destination.Namespace)
|
|
})
|
|
}
|
|
|
|
func TestAPIGroupsToVersions(t *testing.T) {
|
|
versions := APIGroupsToVersions([]metav1.APIGroup{{
|
|
Versions: []metav1.GroupVersionForDiscovery{{GroupVersion: "apps/v1beta1"}, {GroupVersion: "apps/v1beta2"}},
|
|
}, {
|
|
Versions: []metav1.GroupVersionForDiscovery{{GroupVersion: "extensions/v1beta1"}},
|
|
}})
|
|
|
|
assert.EqualValues(t, []string{"apps/v1beta1", "apps/v1beta2", "extensions/v1beta1"}, versions)
|
|
}
|
|
|
|
func TestValidateRepo(t *testing.T) {
|
|
repoPath, err := filepath.Abs("./../..")
|
|
assert.NoError(t, err)
|
|
|
|
apiGroups := []metav1.APIGroup{{Versions: []metav1.GroupVersionForDiscovery{{GroupVersion: "apps/v1beta1"}, {GroupVersion: "apps/v1beta2"}}}}
|
|
kubeVersion := "v1.16"
|
|
kustomizeOptions := &argoappv1.KustomizeOptions{BuildOptions: "sample options"}
|
|
repo := &argoappv1.Repository{Repo: fmt.Sprintf("file://%s", repoPath)}
|
|
cluster := &argoappv1.Cluster{Server: "sample server"}
|
|
app := &argoappv1.Application{
|
|
Spec: argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: repo.Repo,
|
|
},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: cluster.Server,
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
}
|
|
helmRepos := []*argoappv1.Repository{{Repo: "sample helm repo"}}
|
|
|
|
repoClient := &mocks.RepoServerServiceClient{}
|
|
repoClient.On("GetAppDetails", context.Background(), &apiclient.RepoServerAppDetailsQuery{
|
|
Repo: repo,
|
|
Source: &app.Spec.Source,
|
|
Repos: helmRepos,
|
|
KustomizeOptions: kustomizeOptions,
|
|
}).Return(&apiclient.RepoAppDetailsResponse{}, nil)
|
|
|
|
repoClientSet := &mocks.Clientset{}
|
|
repoClientSet.On("NewRepoServerClient").Return(io.NopCloser, repoClient, nil)
|
|
|
|
db := &dbmocks.ArgoDB{}
|
|
|
|
db.On("GetRepository", context.Background(), app.Spec.Source.RepoURL).Return(repo, nil)
|
|
db.On("ListHelmRepositories", context.Background()).Return(helmRepos, nil)
|
|
db.On("GetCluster", context.Background(), app.Spec.Destination.Server).Return(cluster, nil)
|
|
|
|
var receivedRequest *apiclient.ManifestRequest
|
|
|
|
repoClient.On("GenerateManifest", context.Background(), mock.MatchedBy(func(req *apiclient.ManifestRequest) bool {
|
|
receivedRequest = req
|
|
return true
|
|
})).Return(nil, nil)
|
|
|
|
conditions, err := ValidateRepo(context.Background(), app, repoClientSet, db, kustomizeOptions, nil, &kubetest.MockKubectlCmd{Version: kubeVersion, APIGroups: apiGroups})
|
|
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, conditions)
|
|
assert.ElementsMatch(t, []string{"apps/v1beta1", "apps/v1beta2"}, receivedRequest.ApiVersions)
|
|
assert.Equal(t, kubeVersion, receivedRequest.KubeVersion)
|
|
assert.Equal(t, app.Spec.Destination.Namespace, receivedRequest.Namespace)
|
|
assert.Equal(t, &app.Spec.Source, receivedRequest.ApplicationSource)
|
|
assert.Equal(t, kustomizeOptions, receivedRequest.KustomizeOptions)
|
|
}
|
|
|
|
func TestFormatAppConditions(t *testing.T) {
|
|
conditions := []argoappv1.ApplicationCondition{
|
|
{
|
|
Type: EventReasonOperationCompleted,
|
|
Message: "Foo",
|
|
},
|
|
{
|
|
Type: EventReasonResourceCreated,
|
|
Message: "Bar",
|
|
},
|
|
}
|
|
|
|
t.Run("Single Condition", func(t *testing.T) {
|
|
res := FormatAppConditions(conditions[0:1])
|
|
assert.NotEmpty(t, res)
|
|
assert.Equal(t, fmt.Sprintf("%s: Foo", EventReasonOperationCompleted), res)
|
|
})
|
|
|
|
t.Run("Multiple Conditions", func(t *testing.T) {
|
|
res := FormatAppConditions(conditions)
|
|
assert.NotEmpty(t, res)
|
|
assert.Equal(t, fmt.Sprintf("%s: Foo;%s: Bar", EventReasonOperationCompleted, EventReasonResourceCreated), res)
|
|
})
|
|
|
|
t.Run("Empty Conditions", func(t *testing.T) {
|
|
res := FormatAppConditions([]argoappv1.ApplicationCondition{})
|
|
assert.Empty(t, res)
|
|
})
|
|
}
|
|
|
|
func TestFilterByProjects(t *testing.T) {
|
|
apps := []argoappv1.Application{
|
|
{
|
|
Spec: argoappv1.ApplicationSpec{
|
|
Project: "fooproj",
|
|
},
|
|
},
|
|
{
|
|
Spec: argoappv1.ApplicationSpec{
|
|
Project: "barproj",
|
|
},
|
|
},
|
|
}
|
|
|
|
t.Run("No apps in single project", func(t *testing.T) {
|
|
res := FilterByProjects(apps, []string{"foobarproj"})
|
|
assert.Empty(t, res)
|
|
})
|
|
|
|
t.Run("Single app in single project", func(t *testing.T) {
|
|
res := FilterByProjects(apps, []string{"fooproj"})
|
|
assert.Len(t, res, 1)
|
|
})
|
|
|
|
t.Run("Single app in multiple project", func(t *testing.T) {
|
|
res := FilterByProjects(apps, []string{"fooproj", "foobarproj"})
|
|
assert.Len(t, res, 1)
|
|
})
|
|
|
|
t.Run("Multiple apps in multiple project", func(t *testing.T) {
|
|
res := FilterByProjects(apps, []string{"fooproj", "barproj"})
|
|
assert.Len(t, res, 2)
|
|
})
|
|
}
|
|
|
|
func TestValidatePermissions(t *testing.T) {
|
|
t.Run("Empty Repo URL result in condition", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{}
|
|
db := &dbmocks.ArgoDB{}
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, conditions[0].Type)
|
|
assert.Contains(t, conditions[0].Message, "are required")
|
|
})
|
|
|
|
t.Run("Incomplete Path/Chart combo result in condition", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{}
|
|
db := &dbmocks.ArgoDB{}
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, conditions[0].Type)
|
|
assert.Contains(t, conditions[0].Message, "are required")
|
|
})
|
|
|
|
t.Run("Helm chart requires targetRevision", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "somechart",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{}
|
|
db := &dbmocks.ArgoDB{}
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Equal(t, argoappv1.ApplicationConditionInvalidSpecError, conditions[0].Type)
|
|
assert.Contains(t, conditions[0].Message, "is required if the manifest source is a helm chart")
|
|
})
|
|
|
|
t.Run("Application source is not permitted in project", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "somechart",
|
|
TargetRevision: "1.4.1",
|
|
},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Namespace: "testns",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
Destinations: []argoappv1.ApplicationDestination{
|
|
{
|
|
Server: "*",
|
|
Namespace: "*",
|
|
},
|
|
},
|
|
SourceRepos: []string{"http://some/where/else"},
|
|
},
|
|
}
|
|
cluster := &argoappv1.Cluster{Server: "https://127.0.0.1:6443"}
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("GetCluster", context.Background(), spec.Destination.Server).Return(cluster, nil)
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Contains(t, conditions[0].Message, "application repo http://some/where is not permitted")
|
|
})
|
|
|
|
t.Run("Application destination is not permitted in project", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "somechart",
|
|
TargetRevision: "1.4.1",
|
|
},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Namespace: "testns",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
Destinations: []argoappv1.ApplicationDestination{
|
|
{
|
|
Server: "*",
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
SourceRepos: []string{"http://some/where"},
|
|
},
|
|
}
|
|
cluster := &argoappv1.Cluster{Server: "https://127.0.0.1:6443"}
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("GetCluster", context.Background(), spec.Destination.Server).Return(cluster, nil)
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Contains(t, conditions[0].Message, "application destination")
|
|
})
|
|
|
|
t.Run("Destination cluster does not exist", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "somechart",
|
|
TargetRevision: "1.4.1",
|
|
},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Namespace: "default",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
Destinations: []argoappv1.ApplicationDestination{
|
|
{
|
|
Server: "*",
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
SourceRepos: []string{"http://some/where"},
|
|
},
|
|
}
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("GetCluster", context.Background(), spec.Destination.Server).Return(nil, status.Errorf(codes.NotFound, "Cluster does not exist"))
|
|
conditions, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, conditions, 1)
|
|
assert.Contains(t, conditions[0].Message, "has not been configured")
|
|
})
|
|
|
|
t.Run("Cannot get cluster info from DB", func(t *testing.T) {
|
|
spec := argoappv1.ApplicationSpec{
|
|
Source: argoappv1.ApplicationSource{
|
|
RepoURL: "http://some/where",
|
|
Path: "",
|
|
Chart: "somechart",
|
|
TargetRevision: "1.4.1",
|
|
},
|
|
Destination: argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Namespace: "default",
|
|
},
|
|
}
|
|
proj := argoappv1.AppProject{
|
|
Spec: argoappv1.AppProjectSpec{
|
|
Destinations: []argoappv1.ApplicationDestination{
|
|
{
|
|
Server: "*",
|
|
Namespace: "default",
|
|
},
|
|
},
|
|
SourceRepos: []string{"http://some/where"},
|
|
},
|
|
}
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("GetCluster", context.Background(), spec.Destination.Server).Return(nil, fmt.Errorf("Unknown error occurred"))
|
|
_, err := ValidatePermissions(context.Background(), &spec, &proj, db)
|
|
assert.Error(t, err)
|
|
})
|
|
}
|
|
|
|
func TestSetAppOperations(t *testing.T) {
|
|
t.Run("Application not existing", func(t *testing.T) {
|
|
appIf := appclientset.NewSimpleClientset().ArgoprojV1alpha1().Applications("default")
|
|
app, err := SetAppOperation(appIf, "someapp", &argoappv1.Operation{Sync: &argoappv1.SyncOperation{Revision: "aaa"}})
|
|
assert.Error(t, err)
|
|
assert.Nil(t, app)
|
|
})
|
|
|
|
t.Run("Operation already in progress", func(t *testing.T) {
|
|
a := argoappv1.Application{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "someapp",
|
|
Namespace: "default",
|
|
},
|
|
Operation: &argoappv1.Operation{Sync: &argoappv1.SyncOperation{Revision: "aaa"}},
|
|
}
|
|
appIf := appclientset.NewSimpleClientset(&a).ArgoprojV1alpha1().Applications("default")
|
|
app, err := SetAppOperation(appIf, "someapp", &argoappv1.Operation{Sync: &argoappv1.SyncOperation{Revision: "aaa"}})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "operation is already in progress")
|
|
assert.Nil(t, app)
|
|
})
|
|
|
|
t.Run("Operation unspecified", func(t *testing.T) {
|
|
a := argoappv1.Application{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "someapp",
|
|
Namespace: "default",
|
|
},
|
|
}
|
|
appIf := appclientset.NewSimpleClientset(&a).ArgoprojV1alpha1().Applications("default")
|
|
app, err := SetAppOperation(appIf, "someapp", &argoappv1.Operation{Sync: nil})
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), "Operation unspecified")
|
|
assert.Nil(t, app)
|
|
})
|
|
|
|
t.Run("Success", func(t *testing.T) {
|
|
a := argoappv1.Application{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "someapp",
|
|
Namespace: "default",
|
|
},
|
|
}
|
|
appIf := appclientset.NewSimpleClientset(&a).ArgoprojV1alpha1().Applications("default")
|
|
app, err := SetAppOperation(appIf, "someapp", &argoappv1.Operation{Sync: &argoappv1.SyncOperation{Revision: "aaa"}})
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, app)
|
|
})
|
|
|
|
}
|
|
|
|
func TestValidateDestination(t *testing.T) {
|
|
t.Run("Validate destination with server url", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Namespace: "default",
|
|
}
|
|
|
|
appCond := ValidateDestination(context.Background(), &dest, nil)
|
|
assert.Nil(t, appCond)
|
|
assert.False(t, dest.IsServerInferred())
|
|
})
|
|
|
|
t.Run("Validate destination with server name", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Name: "minikube",
|
|
}
|
|
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("ListClusters", context.Background()).Return(&argoappv1.ClusterList{
|
|
Items: []argoappv1.Cluster{
|
|
{
|
|
Name: "minikube",
|
|
Server: "https://127.0.0.1:6443",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
appCond := ValidateDestination(context.Background(), &dest, db)
|
|
assert.Nil(t, appCond)
|
|
assert.Equal(t, "https://127.0.0.1:6443", dest.Server)
|
|
assert.True(t, dest.IsServerInferred())
|
|
})
|
|
|
|
t.Run("Error when having both server url and name", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Server: "https://127.0.0.1:6443",
|
|
Name: "minikube",
|
|
Namespace: "default",
|
|
}
|
|
|
|
err := ValidateDestination(context.Background(), &dest, nil)
|
|
assert.Equal(t, "application destination can't have both name and server defined: minikube https://127.0.0.1:6443", err.Error())
|
|
assert.False(t, dest.IsServerInferred())
|
|
})
|
|
|
|
t.Run("List clusters fails", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Name: "minikube",
|
|
}
|
|
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("ListClusters", context.Background()).Return(nil, fmt.Errorf("an error occured"))
|
|
|
|
err := ValidateDestination(context.Background(), &dest, db)
|
|
assert.Equal(t, "unable to find destination server: an error occured", err.Error())
|
|
assert.False(t, dest.IsServerInferred())
|
|
})
|
|
|
|
t.Run("Destination cluster does not exist", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Name: "minikube",
|
|
}
|
|
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("ListClusters", context.Background()).Return(&argoappv1.ClusterList{
|
|
Items: []argoappv1.Cluster{
|
|
{
|
|
Name: "dind",
|
|
Server: "https://127.0.0.1:6443",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
err := ValidateDestination(context.Background(), &dest, db)
|
|
assert.Equal(t, "unable to find destination server: there are no clusters with this name: minikube", err.Error())
|
|
assert.False(t, dest.IsServerInferred())
|
|
})
|
|
|
|
t.Run("Validate too many clusters with the same name", func(t *testing.T) {
|
|
dest := argoappv1.ApplicationDestination{
|
|
Name: "dind",
|
|
}
|
|
|
|
db := &dbmocks.ArgoDB{}
|
|
db.On("ListClusters", context.Background()).Return(&argoappv1.ClusterList{
|
|
Items: []argoappv1.Cluster{
|
|
{
|
|
Name: "dind",
|
|
Server: "https://127.0.0.1:2443",
|
|
},
|
|
{
|
|
Name: "dind",
|
|
Server: "https://127.0.0.1:8443",
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
err := ValidateDestination(context.Background(), &dest, db)
|
|
assert.Equal(t, "unable to find destination server: there are 2 clusters with the same name: [https://127.0.0.1:2443 https://127.0.0.1:8443]", err.Error())
|
|
assert.False(t, dest.IsServerInferred())
|
|
})
|
|
|
|
}
|