Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions test/e2e/admin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package e2e

import (
"context"
"testing"

"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

. "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture/admin"
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture/admin/utils"
appfixture "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app"
)

func TestBackupExportImport(t *testing.T) {
var exportRawOutput string
ctx := Given(t)
// Create application in argocd namespace
appctx := appfixture.GivenWithSameState(t)

// Create application in test namespace
appctx.
Path(guestbookPath).
Name("exported-app1").
When().
CreateApp().
Then().
And(func(app *Application) {
assert.Equal(t, "exported-app1", app.Name)
assert.Equal(t, fixture.TestNamespace(), app.Namespace)
})

// Create app in other namespace
appctx.
Path(guestbookPath).
Name("exported-app-other-namespace").
SetAppNamespace(fixture.AppNamespace()).
When().
CreateApp().
Then().
And(func(app *Application) {
assert.Equal(t, "exported-app-other-namespace", app.Name)
assert.Equal(t, fixture.AppNamespace(), app.Namespace)
})

ctx.
When().
RunExport().
Then().
AndCLIOutput(func(output string, err error) {
require.NoError(t, err, "export finished with error")
exportRawOutput = output
}).
AndExportedResources(func(exportResources *ExportedResources, err error) {
require.NoError(t, err, "export format not valid")
assert.True(t, exportResources.HasResource(kube.NewResourceKey("", "ConfigMap", "", "argocd-cm")), "argocd-cm not found in export")
assert.True(t, exportResources.HasResource(kube.NewResourceKey(ApplicationSchemaGroupVersionKind.Group, ApplicationSchemaGroupVersionKind.Kind, "", "exported-app1")), "test namespace application not in export")
assert.True(t, exportResources.HasResource(kube.NewResourceKey(ApplicationSchemaGroupVersionKind.Group, ApplicationSchemaGroupVersionKind.Kind, fixture.AppNamespace(), "exported-app-other-namespace")), "app namespace application not in export")
})

// Test import - clean state
ctx = Given(t)

ctx.
When().
RunImport(exportRawOutput).
Then().
AndCLIOutput(func(output string, err error) {
require.NoError(t, err, "import finished with error")
_, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.TestNamespace()).Get(context.Background(), "exported-app1", v1.GetOptions{})
require.NoError(t, err, "failed getting test namespace application after import")
_, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Get(context.Background(), "exported-app-other-namespace", v1.GetOptions{})
require.NoError(t, err, "failed getting app namespace application after import")
})
}
67 changes: 67 additions & 0 deletions test/e2e/fixture/admin/actions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package admin

import (
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
)

// this implements the "when" part of given/when/then
//
// none of the func implement error checks, and that is complete intended, you should check for errors
// using the Then()
type Actions struct {
context *Context
ignoreErrors bool
lastOutput string
lastError error
}

func (a *Actions) prepareExportCommand() []string {
a.context.t.Helper()
args := []string{"export", "--application-namespaces", fixture.AppNamespace()}

return args
}

func (a *Actions) prepareImportCommand() []string {
a.context.t.Helper()
args := []string{"import", "--application-namespaces", fixture.AppNamespace(), "-"}

return args
}

func (a *Actions) RunExport() *Actions {
a.context.t.Helper()
a.runCli(a.prepareExportCommand()...)
return a
}

func (a *Actions) RunImport(stdin string) *Actions {
a.context.t.Helper()
a.runCliWithStdin(stdin, a.prepareImportCommand()...)
return a
}

func (a *Actions) IgnoreErrors() *Actions {
a.ignoreErrors = true
return a
}

func (a *Actions) DoNotIgnoreErrors() *Actions {
a.ignoreErrors = false
return a
}

func (a *Actions) runCli(args ...string) {
a.context.t.Helper()
a.lastOutput, a.lastError = RunCli(args...)
}

func (a *Actions) runCliWithStdin(stdin string, args ...string) {
a.context.t.Helper()
a.lastOutput, a.lastError = RunCliWithStdin(stdin, args...)
}

func (a *Actions) Then() *Consequences {
a.context.t.Helper()
return &Consequences{a.context, a}
}
37 changes: 37 additions & 0 deletions test/e2e/fixture/admin/consequences.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package admin

import (
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture/admin/utils"
)

// this implements the "then" part of given/when/then
type Consequences struct {
context *Context
actions *Actions
}

func (c *Consequences) And(block func()) *Consequences {
c.context.t.Helper()
block()
return c
}

func (c *Consequences) AndCLIOutput(block func(output string, err error)) *Consequences {
c.context.t.Helper()
block(c.actions.lastOutput, c.actions.lastError)
return c
}

// For use after running export with the exported resources desirialized
func (c *Consequences) AndExportedResources(block func(resources *ExportedResources, err error)) {
result, err := GetExportedResourcesFromOutput(c.actions.lastOutput)
block(&result, err)
}

func (c *Consequences) Given() *Context {
return c.context
}

func (c *Consequences) When() *Actions {
return c.actions
}
41 changes: 41 additions & 0 deletions test/e2e/fixture/admin/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package admin

import (
"testing"

"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
"github.com/argoproj/argo-cd/v2/util/env"
)

// this implements the "given" part of given/when/then
type Context struct {
t *testing.T
// seconds
timeout int
name string
}

func Given(t *testing.T) *Context {
fixture.EnsureCleanState(t)
return GivenWithSameState(t)
}

func GivenWithSameState(t *testing.T) *Context {
// ARGOCE_E2E_DEFAULT_TIMEOUT can be used to override the default timeout
// for any context.
timeout := env.ParseNumFromEnv("ARGOCD_E2E_DEFAULT_TIMEOUT", 20, 0, 180)
return &Context{
t: t,
name: fixture.Name(),
timeout: timeout,
}
}

func (c *Context) And(block func()) *Context {
block()
return c
}

func (c *Context) When() *Actions {
return &Actions{context: c}
}
15 changes: 15 additions & 0 deletions test/e2e/fixture/admin/fixture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package admin

import (
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
)

// For admin CLI with kubernetes context
func RunCli(args ...string) (string, error) {
return RunCliWithStdin("", args...)
}

func RunCliWithStdin(stdin string, args ...string) (string, error) {
args = append([]string{"admin", "--namespace", fixture.TestNamespace()}, args...)
return fixture.RunCliWithStdin(stdin, true, args...)
}
48 changes: 48 additions & 0 deletions test/e2e/fixture/admin/utils/backup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package utils

import (
"fmt"
"strings"

kube "github.com/argoproj/gitops-engine/pkg/utils/kube"
yaml "gopkg.in/yaml.v3"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

type ExportedResources []unstructured.Unstructured

func GetExportedResourcesFromOutput(output string) (ExportedResources, error) {
var resources []unstructured.Unstructured
docs := strings.Split(output, "---")

for _, doc := range docs {
doc = strings.TrimSpace(doc)
if len(doc) == 0 {
continue
}

var resourceData map[string]interface{}

if err := yaml.Unmarshal([]byte(doc), &resourceData); err != nil {
return nil, fmt.Errorf("error unmarshaling YAML: %w", err)
}

resource := unstructured.Unstructured{Object: resourceData}
resources = append(resources, resource)
}

return resources, nil
}

func (e ExportedResources) HasResource(resource kube.ResourceKey) bool {
for _, res := range e {
if res.GetObjectKind().GroupVersionKind().Group == resource.Group &&
res.GetKind() == resource.Kind &&
res.GetName() == resource.Name &&
res.GetNamespace() == resource.Namespace {
return true
}
}

return false
}
19 changes: 16 additions & 3 deletions test/e2e/fixture/fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,15 +741,20 @@ func RunCliWithRetry(maxRetries int, args ...string) (string, error) {
}

func RunCli(args ...string) (string, error) {
return RunCliWithStdin("", args...)
return RunCliWithStdin("", false, args...)
}

func RunCliWithStdin(stdin string, args ...string) (string, error) {
func RunCliWithStdin(stdin string, isKubeConextOnlyCli bool, args ...string) (string, error) {
if plainText {
args = append(args, "--plaintext")
}

args = append(args, "--server", apiServerAddress, "--auth-token", token, "--insecure")
// For commands executed with Kubernetes context server argument causes a conflict (for those commands server argument is for KubeAPI server), also authentication is not required
if !isKubeConextOnlyCli {
args = append(args, "--server", apiServerAddress, "--auth-token", token)
}

args = append(args, "--insecure")

return RunWithStdin(stdin, "", "../../dist/argocd", args...)
}
Expand Down Expand Up @@ -1010,3 +1015,11 @@ func RecordTestRun(t *testing.T) {
t.Fatalf("could not write to %s: %v", rf, err)
}
}

func GetApiServerAddress() string {
return apiServerAddress
}

func GetToken() string {
return token
}
4 changes: 2 additions & 2 deletions test/e2e/project_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ func TestProjectCreation(t *testing.T) {
require.NoError(t, err)

// fail without upsert flag
_, err = fixture.RunCliWithStdin(stdinString, "proj", "create",
_, err = fixture.RunCliWithStdin(stdinString, false, "proj", "create",
"-f", "-")
require.Error(t, err)

// succeed with the upsert flag
_, err = fixture.RunCliWithStdin(stdinString, "proj", "create",
_, err = fixture.RunCliWithStdin(stdinString, false, "proj", "create",
"-f", "-", "--upsert")
require.NoError(t, err)
proj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
Expand Down