Skip to content

Commit

Permalink
feat: add reloader scenario tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Azhovan committed Oct 17, 2023
1 parent d7d7043 commit 0be0015
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 4 deletions.
92 changes: 92 additions & 0 deletions apptests/appscenarios/appscenarios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Package appscenarios provides a set of application test scenarios that can be executed
// in a Kubernetes environment. The package defines an AppScenario interface that specifies the
// behavior and name of each scenario, and a List type that implements methods to execute, get,
// and check scenarios.
//
// The package currently supports one scenario for the reloader application, but more scenarios can be
// added by implementing the AppScenario interface and registering them in the scenariosList variable.
package appscenarios

import (
"context"
"fmt"
"os"
"path/filepath"

"github.com/mesosphere/kommander-applications/apptests/environment"
)

// AppScenario defines the behavior and name of an application test scenario
type AppScenario interface {
Execute(context.Context, *environment.Env) error // logic implemented by a scenario
Name() string // scenario name
}

type List map[string]AppScenario

// Execute runs all the scenarios in the list and returns the first error encountered, if any.
func (s List) Execute(ctx context.Context, env *environment.Env) error {
for _, sc := range s {
if err := sc.Execute(ctx, env); err != nil {
return err
}
}
return nil
}

// Get returns the associated scenario for the given application name, or nil if it does not exist.
func Get(application string) AppScenario {
s, ok := scenariosList[application]
if !ok {
return nil
}
return s
}

// Has checks if the associated scenario for the given application exist.
func Has(application string) bool {
_, ok := scenariosList[application]
return ok
}

// absolutePathTo returns the absolute path to the given application directory.
func absolutePathTo(application string) (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}

// determining the execution path.
var base string
_, err = os.Stat(filepath.Join(wd, "services"))
if os.IsNotExist(err) {
base = "../.."
} else {
base = ""
}

dir, err := filepath.Abs(filepath.Join(wd, base, "services", application))
if err != nil {
return "", err
}

// filepath.Glob returns a sorted slice of matching paths
matches, err := filepath.Glob(filepath.Join(dir, "*"))
if err != nil {
return "", err
}

if len(matches) == 0 {
return "", fmt.Errorf(
"no application directory found for %s in the given path:%s",
application, dir)
}

return matches[0], nil

}

// This is the ScenarioList of all available scenarios.
var scenariosList = List{
"reloader": reloader{},
}
17 changes: 17 additions & 0 deletions apptests/appscenarios/appscenarios_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package appscenarios

import (
"path/filepath"
"testing"

"github.com/stretchr/testify/assert"
)

func TestAbsolutePathTo(t *testing.T) {
absAppPath, err := absolutePathTo("reloader")
assert.NoError(t, err)

expected := filepath.Join("kommander-applications", "services", "reloader")
assert.Contains(t, absAppPath, expected)
assert.NotEmpty(t, filepath.Base(absAppPath))
}
84 changes: 84 additions & 0 deletions apptests/appscenarios/reloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package appscenarios

import (
"context"
"path/filepath"
"time"

fluxhelmv2beta1 "github.com/fluxcd/helm-controller/api/v2beta1"
"github.com/mesosphere/kommander-applications/apptests/environment"
"github.com/mesosphere/kommander-applications/apptests/flux"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
genericCLient "sigs.k8s.io/controller-runtime/pkg/client"
)

type reloader struct{}

func (r reloader) Name() string {
return "reloader"
}

var _ AppScenario = (*reloader)(nil)

const (
pollInterval = 2 * time.Second
kommanderNamespace = "kommander"
kommanderFluxNamespace = "kommander-flux"
)

func (r reloader) Execute(ctx context.Context, env *environment.Env) error {
appPath, err := absolutePathTo(r.Name())
if err != nil {
return err
}

// apply defaults config maps first
defaultKustomizations := filepath.Join(appPath, "/defaults")
err = env.ApplyKustomizations(ctx, defaultKustomizations, map[string]string{
"releaseNamespace": kommanderNamespace,
})
if err != nil {
return err
}
// apply the rest of kustomizations
err = env.ApplyKustomizations(ctx, appPath, map[string]string{
"releaseNamespace": kommanderNamespace,
})
if err != nil {
return err
}

client, err := genericCLient.New(env.K8sClient.Config(), genericCLient.Options{Scheme: flux.NewScheme()})
if err != nil {
return err
}

hr := &fluxhelmv2beta1.HelmRelease{
TypeMeta: metav1.TypeMeta{
Kind: fluxhelmv2beta1.HelmReleaseKind,
APIVersion: fluxhelmv2beta1.GroupVersion.Version,
},
ObjectMeta: metav1.ObjectMeta{
Name: r.Name(),
Namespace: kommanderNamespace,
},
}

err = wait.PollUntilContextCancel(ctx, pollInterval, true, func(ctx context.Context) (done bool, err error) {
err = client.Get(ctx, genericCLient.ObjectKeyFromObject(hr), hr)
if err != nil {
return false, err
}

for _, cond := range hr.Status.Conditions {
if cond.Status == metav1.ConditionTrue &&
cond.Type == fluxhelmv2beta1.ReleasedCondition {
return true, nil
}
}
return false, nil
})

return err
}
22 changes: 22 additions & 0 deletions apptests/appscenarios/reloader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package appscenarios

import (
"context"
"testing"

"github.com/mesosphere/kommander-applications/apptests/environment"
"github.com/stretchr/testify/assert"
)

func TestListExecute(t *testing.T) {
env := &environment.Env{}
ctx := context.Background()

err := env.Provision(ctx)
assert.NoError(t, err)
defer env.Destroy(ctx)

r := reloader{}
err = r.Execute(ctx, env)
assert.NoError(t, err)
}
24 changes: 20 additions & 4 deletions apptests/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"time"

Expand Down Expand Up @@ -49,7 +50,7 @@ type Env struct {
func (e *Env) Provision(ctx context.Context) error {
var err error

kustomizePath, err := AbsolutePathToBase()
kustomizePath, err := absolutePathToBase()
if err != nil {
return err
}
Expand Down Expand Up @@ -184,6 +185,7 @@ func (e *Env) SetK8sClient(k8sClient *typedclient.Client) {

// ApplyKustomizations applies the kustomizations located in the given path.
func (e *Env) ApplyKustomizations(ctx context.Context, path string, substitutions map[string]string) error {
fmt.Println(">>", path)
if path == "" {
return fmt.Errorf("requirement argument: path is not specified")
}
Expand Down Expand Up @@ -217,7 +219,21 @@ func (e *Env) ApplyKustomizations(ctx context.Context, path string, substitution
return nil
}

// AbsolutePathToBase returns the absolute path to common/base directory.
func AbsolutePathToBase() (string, error) {
return filepath.Abs("../../common/base")
// absolutePathToBase returns the absolute path to common/base directory from the given working directory.
func absolutePathToBase() (string, error) {
wd, err := os.Getwd()
if err != nil {
return "", err
}

// determining the execution path.
var base string
_, err = os.Stat(filepath.Join(wd, "common", "base"))
if os.IsNotExist(err) {
base = "../.."
} else {
base = ""
}

return filepath.Join(wd, base, "common", "base"), nil
}
6 changes: 6 additions & 0 deletions apptests/environment/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ func TestProvision(t *testing.T) {
}

}

func TestAbsolutePathToBase(t *testing.T) {
s, err := absolutePathToBase()
assert.NoError(t, err)
assert.Contains(t, s, "kommander-applications/common/base")
}

0 comments on commit 0be0015

Please sign in to comment.