Skip to content

Commit

Permalink
Separate hooks for pre/post and setup/teardown
Browse files Browse the repository at this point in the history
Signed-off-by: Hasan Turken <[email protected]>
turkenh committed Oct 13, 2022

Verified

This commit was signed with the committer’s verified signature.
turkenh Hasan Turken
1 parent d002e09 commit ab09e8e
Showing 8 changed files with 123 additions and 86 deletions.
34 changes: 22 additions & 12 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -27,9 +27,10 @@ func main() {
"'provider-aws/examples/s3/bucket.yaml,provider-gcp/examples/storage/bucket.yaml': "+
"The comma separated resources are used as test inputs.\n"+
"If this option is not set, 'MANIFEST_LIST' env var is used as default.").Envar("MANIFEST_LIST").String()
dataSourcePath = e2e.Flag("data-source", "File path of data source that will be used for injection some values.").Default("").String()
defaultHooksDirectory = e2e.Flag("default-hooks-directory", "Path to hooks directory for default hooks to run for all examples.\n"+
"This could be overridden per resource using \"uptest.upbound.io/hooks-directory\" annotation.").String()
dataSourcePath = e2e.Flag("data-source", "File path of data source that will be used for injection some values.").Default("").String()
setupScript = e2e.Flag("setup-script", "Script that will be executed before running tests.").Default("").String()
teardownScript = e2e.Flag("teardown-script", "Script that will be executed after running tests.").Default("").String()

defaultTimeout = e2e.Flag("default-timeout", "Default timeout in seconds for the test.\n"+
"Timeout could be overridden per resource using \"uptest.upbound.io/timeout\" annotation.").Default("1200").Int()
defaultConditions = e2e.Flag("default-conditions", "Comma seperated list of default conditions to wait for a successful test.\n"+
@@ -49,19 +50,28 @@ func main() {
return
}

defaultHooksPath := ""
if *defaultHooksDirectory != "" {
defaultHooksPath, err = filepath.Abs(*defaultHooksDirectory)
setupPath := ""
if *setupScript != "" {
setupPath, err = filepath.Abs(*setupScript)
if err != nil {
kingpin.FatalIfError(err, "cannot get absolute path of setup script")
}
}

teardownPath := ""
if *teardownScript != "" {
teardownPath, err = filepath.Abs(*teardownScript)
if err != nil {
kingpin.FatalIfError(err, "cannot get absolute path of default hooks directory")
kingpin.FatalIfError(err, "cannot get absolute path of teardown script")
}
}
o := &config.AutomatedTest{
ManifestPaths: examplePaths,
DataSourcePath: *dataSourcePath,
DefaultHooksDirPath: defaultHooksPath,
DefaultConditions: strings.Split(*defaultConditions, ","),
DefaultTimeout: *defaultTimeout,
ManifestPaths: examplePaths,
DataSourcePath: *dataSourcePath,
SetupScriptPath: setupPath,
TeardownScriptPath: teardownPath,
DefaultConditions: strings.Split(*defaultConditions, ","),
DefaultTimeout: *defaultTimeout,
}

kingpin.FatalIfError(internal.RunTest(o), "cannot run e2e tests successfully")
33 changes: 20 additions & 13 deletions internal/config/config.go
Original file line number Diff line number Diff line change
@@ -2,16 +2,26 @@ package config

const (
AnnotationKeyTimeout = "uptest.upbound.io/timeout"
AnnotationKeyHooksDirectory = "uptest.upbound.io/hooks-directory"
AnnotationKeyConditions = "uptest.upbound.io/conditions"
AnnotationKeyPreAssertHook = "uptest.upbound.io/pre-assert-hook"
AnnotationKeyPostAssertHook = "uptest.upbound.io/post-assert-hook"
)

type AutomatedTest struct {
ManifestPaths []string
DataSourcePath string
DefaultTimeout int
DefaultHooksDirPath string
DefaultConditions []string
ManifestPaths []string
DataSourcePath string

SetupScriptPath string
TeardownScriptPath string

DefaultTimeout int
DefaultConditions []string
}

type TestCase struct {
Timeout int
SetupScriptPath string
TeardownScriptPath string
}

type Resource struct {
@@ -20,11 +30,8 @@ type Resource struct {
KindGroup string
Manifest string

Timeout int
HooksDirPath string
Conditions []string
}

type TestCase struct {
Timeout int
Timeout int
Conditions []string
PreAssertScriptPath string
PostAssertScriptPath string
}
19 changes: 10 additions & 9 deletions internal/prepare.go
Original file line number Diff line number Diff line change
@@ -53,18 +53,19 @@ type Preparer struct {
dataSourcePath string
}

func (p *Preparer) PrepareManifests() ([]*unstructured.Unstructured, error) {
func (p *Preparer) PrepareManifests() (map[string]*unstructured.Unstructured, error) {
if err := os.MkdirAll(caseDirectory, os.ModePerm); err != nil {
return nil, errors.Wrapf(err, "cannot create directory %s", caseDirectory)
}

manifestData, err := p.injectVariables()
injectedFiles, err := p.injectVariables()
if err != nil {
return nil, errors.Wrap(err, "cannot inject variables")
}
var manifests []*unstructured.Unstructured
for _, file := range manifestData {
decoder := kyaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(file), 1024)

manifests := make(map[string]*unstructured.Unstructured, len(injectedFiles))
for path, data := range injectedFiles {
decoder := kyaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(data), 1024)
for {
u := &unstructured.Unstructured{}
if err := decoder.Decode(&u); err != nil {
@@ -78,14 +79,14 @@ func (p *Preparer) PrepareManifests() ([]*unstructured.Unstructured, error) {
fmt.Printf("Skipping %s with name %s since it requires the following manual intervention: %s\n", u.GroupVersionKind().String(), u.GetName(), v)
continue
}
manifests = append(manifests, u)
manifests[path] = u
}
}
}
return manifests, nil
}

func (p *Preparer) injectVariables() ([]string, error) {
func (p *Preparer) injectVariables() (map[string]string, error) {
dataSourceMap := make(map[string]string)
if p.dataSourcePath != "" {
dataSource, err := ioutil.ReadFile(p.dataSourcePath)
@@ -97,7 +98,7 @@ func (p *Preparer) injectVariables() ([]string, error) {
}
}

var inputs []string
inputs := make(map[string]string, len(p.testFilePaths))
for _, f := range p.testFilePaths {
manifestData, err := ioutil.ReadFile(f)
if err != nil {
@@ -107,7 +108,7 @@ func (p *Preparer) injectVariables() ([]string, error) {
if err != nil {
return nil, errors.Wrap(err, "cannot inject data source values")
}
inputs = append(inputs, inputData)
inputs[f] = inputData
}
return inputs, nil
}
8 changes: 7 additions & 1 deletion internal/templates/00-apply.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{{ range $resource := .Resources -}}
{{ if .TestCase.SetupScriptPath -}}
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: {{ .TestCase.SetupScriptPath }}
{{ end }}
{{- range $resource := .Resources -}}
---
{{ $resource.Manifest }}
{{- end }}
8 changes: 4 additions & 4 deletions internal/templates/00-assert.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@ timeout: {{ .TestCase.Timeout }}
commands:
- command: ${KUBECTL} annotate managed --all upjet.upbound.io/test=true --overwrite
{{- range $resource := .Resources }}
{{- if $resource.HooksDirPath }}
- script: if [ -f {{ $resource.HooksDirPath }}/pre.sh ]; then {{ $resource.HooksDirPath }}/pre.sh; else echo "No pre hook provided..."; fi
{{- if $resource.PreAssertScriptPath }}
- command: {{ $resource.PreAssertScriptPath }}
{{- end }}
{{- range $condition := $resource.Conditions }}
{{- if $resource.Namespace }}
@@ -14,7 +14,7 @@ commands:
- command: ${KUBECTL} wait {{ $resource.KindGroup }}/{{ $resource.Name }} --for=condition={{ $condition }} --timeout 10s
{{- end }}
{{- end }}
{{- if $resource.HooksDirPath }}
- script: if [ -f {{ $resource.HooksDirPath }}/post.sh ]; then {{ $resource.HooksDirPath }}/post.sh; else echo "No post hook provided..."; fi
{{- if $resource.PostAssertScriptPath }}
- command: {{ $resource.PostAssertScriptPath }}
{{- end }}
{{- end }}
3 changes: 3 additions & 0 deletions internal/templates/01-assert.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -10,3 +10,6 @@ commands:
{{- end }}
{{- end }}
- command: ${KUBECTL} wait managed --all --for=delete --timeout 10s
{{- if .TestCase.TeardownScriptPath }}
- command: {{ .TestCase.TeardownScriptPath }}
{{- end }}
60 changes: 31 additions & 29 deletions internal/templates/renderer_test.go
Original file line number Diff line number Diff line change
@@ -35,8 +35,8 @@ func TestRender(t *testing.T) {
resources []config.Resource
}
type want struct {
want map[string]string
err error
out map[string]string
err error
}
tests := map[string]struct {
args args
@@ -49,25 +49,22 @@ func TestRender(t *testing.T) {
},
resources: []config.Resource{
{
Name: "example-bucket",
KindGroup: "s3.aws.upbound.io",
Manifest: bucketManifest,
HooksDirPath: "test/bucket-hooks",
Conditions: []string{"Test"},
Name: "example-bucket",
KindGroup: "s3.aws.upbound.io",
Manifest: bucketManifest,
Conditions: []string{"Test"},
},
},
},
want: want{
want: map[string]string{
out: map[string]string{
"00-apply.yaml": "---\n" + bucketManifest,
"00-assert.yaml": `apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 10
commands:
- command: ${KUBECTL} annotate managed --all upjet.upbound.io/test=true --overwrite
- script: if [ -f test/bucket-hooks/pre.sh ]; then test/bucket-hooks/pre.sh; else echo "No pre hook provided..."; fi
- command: ${KUBECTL} wait s3.aws.upbound.io/example-bucket --for=condition=Test --timeout 10s
- script: if [ -f test/bucket-hooks/post.sh ]; then test/bucket-hooks/post.sh; else echo "No post hook provided..."; fi
`,
"01-delete.yaml": `apiVersion: kuttl.dev/v1beta1
kind: TestStep
@@ -87,41 +84,45 @@ commands:
"SuccessMultipleResource": {
args: args{
tc: &config.TestCase{
Timeout: 10,
Timeout: 10,
SetupScriptPath: "/tmp/setup.sh",
TeardownScriptPath: "/tmp/teardown.sh",
},
resources: []config.Resource{
{
Manifest: bucketManifest,
Name: "example-bucket",
KindGroup: "s3.aws.upbound.io",
HooksDirPath: "test/bucket-hooks",
Conditions: []string{"Test"},
Manifest: bucketManifest,
Name: "example-bucket",
KindGroup: "s3.aws.upbound.io",
PreAssertScriptPath: "/tmp/bucket/pre-assert.sh",
Conditions: []string{"Test"},
},
{
Name: "test-cluster-claim",
KindGroup: "cluster.gcp.platformref.upbound.io",
Namespace: "upbound-system",
Manifest: claimManifest,
HooksDirPath: "test/claim-hooks",
Conditions: []string{"Ready", "Synced"},
Manifest: claimManifest,
Name: "test-cluster-claim",
KindGroup: "cluster.gcp.platformref.upbound.io",
Namespace: "upbound-system",
PostAssertScriptPath: "/tmp/claim/post-assert.sh",
Conditions: []string{"Ready", "Synced"},
},
},
},
want: want{
want: map[string]string{
"00-apply.yaml": "---\n" + bucketManifest + "---\n" + claimManifest,
out: map[string]string{
"00-apply.yaml": `apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: /tmp/setup.sh
` + "---\n" + bucketManifest + "---\n" + claimManifest,
"00-assert.yaml": `apiVersion: kuttl.dev/v1beta1
kind: TestAssert
timeout: 10
commands:
- command: ${KUBECTL} annotate managed --all upjet.upbound.io/test=true --overwrite
- script: if [ -f test/bucket-hooks/pre.sh ]; then test/bucket-hooks/pre.sh; else echo "No pre hook provided..."; fi
- command: /tmp/bucket/pre-assert.sh
- command: ${KUBECTL} wait s3.aws.upbound.io/example-bucket --for=condition=Test --timeout 10s
- script: if [ -f test/bucket-hooks/post.sh ]; then test/bucket-hooks/post.sh; else echo "No post hook provided..."; fi
- script: if [ -f test/claim-hooks/pre.sh ]; then test/claim-hooks/pre.sh; else echo "No pre hook provided..."; fi
- command: ${KUBECTL} wait cluster.gcp.platformref.upbound.io/test-cluster-claim --for=condition=Ready --timeout 10s --namespace upbound-system
- command: ${KUBECTL} wait cluster.gcp.platformref.upbound.io/test-cluster-claim --for=condition=Synced --timeout 10s --namespace upbound-system
- script: if [ -f test/claim-hooks/post.sh ]; then test/claim-hooks/post.sh; else echo "No post hook provided..."; fi
- command: /tmp/claim/post-assert.sh
`,
"01-delete.yaml": `apiVersion: kuttl.dev/v1beta1
kind: TestStep
@@ -136,6 +137,7 @@ commands:
- command: ${KUBECTL} wait s3.aws.upbound.io/example-bucket --for=delete --timeout 10s
- command: ${KUBECTL} wait cluster.gcp.platformref.upbound.io/test-cluster-claim --for=delete --timeout 10s --namespace upbound-system
- command: ${KUBECTL} wait managed --all --for=delete --timeout 10s
- command: /tmp/teardown.sh
`,
},
},
@@ -147,7 +149,7 @@ commands:
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
t.Errorf("Render(...): -want error, +got error:\n%s", diff)
}
if diff := cmp.Diff(tc.want.want, got); diff != "" {
if diff := cmp.Diff(tc.want.out, got); diff != "" {
t.Errorf("Render(...): -want, +got:\n%s", diff)
}
})
44 changes: 26 additions & 18 deletions internal/tester.go
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ import (
"github.com/upbound/uptest/internal/config"
)

func NewTester(manifests []*unstructured.Unstructured, opts *config.AutomatedTest) *Tester {
func NewTester(manifests map[string]*unstructured.Unstructured, opts *config.AutomatedTest) *Tester {
return &Tester{
options: opts,
manifests: manifests,
@@ -27,7 +27,7 @@ func NewTester(manifests []*unstructured.Unstructured, opts *config.AutomatedTes

type Tester struct {
options *config.AutomatedTest
manifests []*unstructured.Unstructured
manifests map[string]*unstructured.Unstructured
}

func (t *Tester) ExecuteTests() error {
@@ -50,11 +50,13 @@ func (t *Tester) ExecuteTests() error {

func (t *Tester) prepareConfig() (*config.TestCase, []config.Resource, error) {
tc := &config.TestCase{
Timeout: t.options.DefaultTimeout,
Timeout: t.options.DefaultTimeout,
SetupScriptPath: t.options.SetupScriptPath,
TeardownScriptPath: t.options.TeardownScriptPath,
}
examples := make([]config.Resource, len(t.manifests))
examples := make([]config.Resource, 0, len(t.manifests))

for i, m := range t.manifests {
for fp, m := range t.manifests {
if m.GroupVersionKind().String() == "/v1, Kind=Secret" {
continue
}
@@ -66,13 +68,12 @@ func (t *Tester) prepareConfig() (*config.TestCase, []config.Resource, error) {
}

example := config.Resource{
Name: m.GetName(),
Namespace: m.GetNamespace(),
KindGroup: kg,
Manifest: string(d),
Timeout: t.options.DefaultTimeout,
HooksDirPath: t.options.DefaultHooksDirPath,
Conditions: t.options.DefaultConditions,
Name: m.GetName(),
Namespace: m.GetNamespace(),
KindGroup: kg,
Manifest: string(d),
Timeout: t.options.DefaultTimeout,
Conditions: t.options.DefaultConditions,
}

if v, ok := m.GetAnnotations()[config.AnnotationKeyTimeout]; ok {
@@ -85,18 +86,25 @@ func (t *Tester) prepareConfig() (*config.TestCase, []config.Resource, error) {
}
}

if v, ok := m.GetAnnotations()[config.AnnotationKeyHooksDirectory]; ok {
example.HooksDirPath, err = filepath.Abs(v)
if v, ok := m.GetAnnotations()[config.AnnotationKeyConditions]; ok {
example.Conditions = strings.Split(v, ",")
}

if v, ok := m.GetAnnotations()[config.AnnotationKeyPreAssertHook]; ok {
example.PreAssertScriptPath, err = filepath.Abs(filepath.Join(filepath.Dir(fp), filepath.Clean(v)))
if err != nil {
return nil, nil, errors.Wrap(err, "cannot find absolute path for hooks directory")
return nil, nil, errors.Wrap(err, "cannot find absolute path for pre assert hook")
}
}

if v, ok := m.GetAnnotations()[config.AnnotationKeyConditions]; ok {
example.Conditions = strings.Split(v, ",")
if v, ok := m.GetAnnotations()[config.AnnotationKeyPostAssertHook]; ok {
example.PostAssertScriptPath, err = filepath.Abs(filepath.Join(filepath.Dir(fp), filepath.Clean(v)))
if err != nil {
return nil, nil, errors.Wrap(err, "cannot find absolute path for post assert hook")
}
}

examples[i] = example
examples = append(examples, example)
}

return tc, examples, nil

0 comments on commit ab09e8e

Please sign in to comment.