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
2 changes: 1 addition & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion common/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type InstallParameters struct {
ControllerName string
ControllerImage string
ServiceAccount string
SkipController bool
}

// Installer allows to install ArgoCD resources.
Expand All @@ -38,7 +39,9 @@ type Installer struct {
// Install performs installation
func (installer *Installer) Install(parameters InstallParameters) {
installer.installAppCRD(parameters.DryRun)
installer.installController(parameters)
if !parameters.SkipController {
installer.installController(parameters)
}
}

// NewInstaller creates new instance of Installer
Expand Down
1 change: 0 additions & 1 deletion controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type ApplicationController struct {
applicationClientset appclientset.Interface
appQueue workqueue.RateLimitingInterface
appInformer cache.SharedIndexInformer
config *ApplicationControllerConfig
}

type ApplicationControllerConfig struct {
Expand Down
4 changes: 2 additions & 2 deletions pkg/apis/application/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,10 @@ type RepositoryList struct {

// Equals compares two instances of ApplicationSource and return true if instances are equal.
func (source ApplicationSource) Equals(other ApplicationSource) bool {
return (source.TargetRevision == other.TargetRevision &&
return source.TargetRevision == other.TargetRevision &&
source.RepoURL == other.RepoURL &&
source.Path == other.Path &&
source.Environment == other.Environment)
source.Environment == other.Environment
}

// RESTConfig returns a go-client REST config from cluster
Expand Down
66 changes: 66 additions & 0 deletions test/e2e/controller_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package e2e

import (
"context"
"testing"

"fmt"

"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestController(t *testing.T) {
testApp := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{GenerateName: "e2e-test"},
Spec: v1alpha1.ApplicationSpec{Source: v1alpha1.ApplicationSource{
RepoURL: "https://github.com/ksonnet/ksonnet.git", Path: ".", Environment: "default",
}},
}

t.Run("TestComparisonErrorIfRepoDoesNotExist", func(t *testing.T) {
ctrl := fixture.CreateController()
ctx, cancel := context.WithCancel(context.Background())
go ctrl.Run(ctx, 1)
defer cancel()
app := fixture.CreateApp(t, testApp)

PollUntil(t, func() (done bool, err error) {
app, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
return err == nil && app.Status.ComparisonResult.Status != v1alpha1.ComparisonStatusUnknown, err
})

app, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(fmt.Sprintf("Unable to get app %v", err))
}

assert.Equal(t, app.Status.ComparisonResult.Status, v1alpha1.ComparisonStatusError)
})

t.Run("TestComparisonSuccessful", func(t *testing.T) {
ctrl := fixture.CreateController()
ctx, cancel := context.WithCancel(context.Background())
go ctrl.Run(ctx, 1)
defer cancel()
_, err := fixture.RepoService.Create(context.Background(), &v1alpha1.Repository{Repo: testApp.Spec.Source.RepoURL, Username: "", Password: ""})
if err != nil {
t.Fatal(fmt.Sprintf("Unable to create repo %v", err))
}
app := fixture.CreateApp(t, testApp)

PollUntil(t, func() (done bool, err error) {
app, err := fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
return err == nil && app.Status.ComparisonResult.Status != v1alpha1.ComparisonStatusUnknown, err
})

app, err = fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(fmt.Sprintf("Unable to get app %v", err))
}

assert.NotEqual(t, app.Status.ComparisonResult.Status, v1alpha1.ComparisonStatusError)
})

}
159 changes: 159 additions & 0 deletions test/e2e/fixture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package e2e

import (
"os/exec"
"testing"

"github.com/argoproj/argo-cd/cmd/argocd/commands"
"github.com/argoproj/argo-cd/common"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
"k8s.io/api/core/v1"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"time"

"fmt"

"github.com/argoproj/argo-cd/application"
"github.com/argoproj/argo-cd/controller"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/server/repository"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)

const (
TestTimeout = time.Second * 3
)

// Fixture represents e2e tests fixture.
type Fixture struct {
AppManager *application.Manager
KubeClient *kubernetes.Clientset
ExtensionsClient *apiextensionsclient.Clientset
AppClient *appclientset.Clientset
RepoService repository.RepositoryServiceServer
Namespace string
InstanceID string
}

func createNamespace(kubeClient *kubernetes.Clientset) (string, error) {
ns := &v1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "argo-e2e-test-",
},
}
cns, err := kubeClient.CoreV1().Namespaces().Create(ns)
if err != nil {
return "", err
}
return cns.Name, nil
}

func (f *Fixture) setup() error {
common.NewInstaller(f.ExtensionsClient, f.KubeClient).Install(common.InstallParameters{
DryRun: false,
SkipController: true,
})
return nil
}

// TearDown deletes fixture resources.
func (f *Fixture) TearDown() {
err := f.KubeClient.CoreV1().Namespaces().Delete(f.Namespace, &metav1.DeleteOptions{})
if err != nil {
println("Unable to tear down fixture")
}
}

// NewFixture creates e2e tests fixture.
func NewFixture() (*Fixture, error) {
config := commands.GetKubeConfig("", clientcmd.ConfigOverrides{})
extensionsClient := apiextensionsclient.NewForConfigOrDie(config)
appClient := appclientset.NewForConfigOrDie(config)
kubeClient := kubernetes.NewForConfigOrDie(config)
namespace, err := createNamespace(kubeClient)
appManager := application.NewAppManager(
&FakeGitClient{},
repository.NewServer(namespace, kubeClient, appClient),
application.NewKsonnetAppComparator(),
time.Second)
if err != nil {
return nil, err
}
fixture := &Fixture{
ExtensionsClient: extensionsClient,
AppClient: appClient,
KubeClient: kubeClient,
Namespace: namespace,
InstanceID: namespace,
RepoService: repository.NewServer(namespace, kubeClient, appClient),
AppManager: appManager,
}
err = fixture.setup()
if err != nil {
return nil, err
}
return fixture, nil
}

// CreateApp creates application with appropriate controller instance id.
func (f *Fixture) CreateApp(t *testing.T, application *v1alpha1.Application) *v1alpha1.Application {
labels := application.ObjectMeta.Labels
if labels == nil {
labels = make(map[string]string)
application.ObjectMeta.Labels = labels
}
labels[common.LabelKeyApplicationControllerInstanceID] = f.InstanceID

app, err := f.AppClient.ArgoprojV1alpha1().Applications(f.Namespace).Create(application)
if err != nil {
t.Fatal(fmt.Sprintf("Unable to create app %v", err))
}
return app
}

// CreateController creates new controller instance
func (f *Fixture) CreateController() *controller.ApplicationController {
return controller.NewApplicationController(f.KubeClient, f.AppClient, f.AppManager, time.Second, &controller.ApplicationControllerConfig{
Namespace: f.Namespace,
InstanceID: f.InstanceID,
})
}

// PollUntil periodically executes specified condition until it returns true.
func PollUntil(t *testing.T, condition wait.ConditionFunc) {
stop := make(chan struct{})
isClosed := false
makeSureClosed := func() {
if !isClosed {
close(stop)
isClosed = true
}
}
defer makeSureClosed()
go func() {
time.Sleep(TestTimeout)
makeSureClosed()
}()
err := wait.PollUntil(time.Second, condition, stop)
if err != nil {
t.Fatal("Failed to wait for expected condition")
}
}

// FakeGitClient is a test git client implementation which always clone local test repo.
type FakeGitClient struct {
}

func (c *FakeGitClient) CloneOrFetch(repo string, username string, password string, repoPath string) error {
_, err := exec.Command("cp", "-r", "functional/ks-example", repoPath).Output()
return err
}

func (c *FakeGitClient) Checkout(repoPath string, sha string) error {
// do nothing
return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
apiVersion: "0.1"
gitVersion:
commitSha: 422d521c05aa905df949868143b26445f5e4eda5
refSpec: master
kind: ksonnet.io/registry
libraries:
apache:
path: apache
version: master
efk:
path: efk
version: master
mariadb:
path: mariadb
version: master
memcached:
path: memcached
version: master
mongodb:
path: mongodb
version: master
mysql:
path: mysql
version: master
nginx:
path: nginx
version: master
node:
path: node
version: master
postgres:
path: postgres
version: master
redis:
path: redis
version: master
tomcat:
path: tomcat
version: master
11 changes: 11 additions & 0 deletions test/e2e/functional/ks-example/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: 0.0.1
kind: ksonnet.io/app
name: ks-example
registries:
incubator:
gitVersion:
commitSha: 422d521c05aa905df949868143b26445f5e4eda5
refSpec: master
protocol: github
uri: github.com/ksonnet/parts/tree/master/incubator
version: 0.0.1
28 changes: 28 additions & 0 deletions test/e2e/functional/ks-example/components/guestbook-ui.jsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
local params = std.extVar("__ksonnet/params").components["guestbook-ui"];
local k = import "k.libsonnet";
local deployment = k.apps.v1beta1.deployment;
local container = k.apps.v1beta1.deployment.mixin.spec.template.spec.containersType;
local containerPort = container.portsType;
local service = k.core.v1.service;
local servicePort = k.core.v1.service.mixin.spec.portsType;

local targetPort = params.containerPort;
local labels = {app: params.name};

local appService = service
.new(
params.name,
labels,
servicePort.new(params.servicePort, targetPort))
.withType(params.type);

local appDeployment = deployment
.new(
params.name,
params.replicas,
container
.new(params.name, params.image)
.withPorts(containerPort.new(targetPort)),
labels);

k.core.v1.list.new([appService, appDeployment])
18 changes: 18 additions & 0 deletions test/e2e/functional/ks-example/components/params.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
global: {
// User-defined global parameters; accessible to all component and environments, Ex:
// replicas: 4,
},
components: {
// Component-level parameters, defined initially from 'ks prototype use ...'
// Each object below should correspond to a component in the components/ directory
"guestbook-ui": {
containerPort: 80,
image: "gcr.io/heptio-images/ks-guestbook-demo:0.1",
name: "guestbook-ui",
replicas: 1,
servicePort: 80,
type: "ClusterIP",
},
},
}
4 changes: 4 additions & 0 deletions test/e2e/functional/ks-example/environments/base.libsonnet
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
local components = std.extVar("__ksonnet/components");
components + {
// Insert user-specified overrides here.
}
Loading