Skip to content

Commit

Permalink
teststep apply, assert and errors can now take urls, files or folder (#…
Browse files Browse the repository at this point in the history
…123)

Signed-off-by: Ken Sipe <[email protected]>
  • Loading branch information
kensipe authored Jun 2, 2020
1 parent e89c59d commit b85c5a0
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 29 deletions.
2 changes: 1 addition & 1 deletion pkg/file/files.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func ToRuntimeObjects(paths []string) ([]runtime.Object, error) {
apply := []runtime.Object{}

for _, path := range paths {
objs, err := testutils.LoadYAML(path)
objs, err := testutils.LoadYAMLFromFile(path)
if err != nil {
return nil, fmt.Errorf("file %q load yaml error", path)
}
Expand Down
57 changes: 57 additions & 0 deletions pkg/http/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package http

import (
"bytes"
"fmt"
"io"
coreHTTP "net/http"
"net/url"

"k8s.io/apimachinery/pkg/runtime"

testutils "github.com/kudobuilder/kuttl/pkg/test/utils"
)

// IsURL returns true if string is an URL
func IsURL(str string) bool {
u, err := url.Parse(str)
return err == nil && u.Scheme != "" && u.Host != ""
}

// ToRuntimeObjects takes a url, pulls the file and returns []runtime.Object
// url must be a full path to a manifest file. that file can have multiple runtime objects.
func ToRuntimeObjects(urlPath string) ([]runtime.Object, error) {
apply := []runtime.Object{}

buf, err := Read(urlPath)
if err != nil {
return nil, err
}

objs, err := testutils.LoadYAML(urlPath, buf)
if err != nil {
return nil, fmt.Errorf("url %q load yaml error", urlPath)
}
apply = append(apply, objs...)

return apply, nil
}

// Read returns a buffer for the file at the url
func Read(urlPath string) (*bytes.Buffer, error) {

response, err := coreHTTP.Get(urlPath) // nolint:gosec
if err != nil {
return nil, err
}
if response != nil {
defer response.Body.Close()
}
var buf bytes.Buffer
_, err = io.Copy(&buf, response.Body)
if err != nil {
return nil, err
}

return &buf, nil
}
43 changes: 43 additions & 0 deletions pkg/http/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package http

import (
"testing"
)

func TestIsURL(t *testing.T) {

tests := []struct {
name string
path string
want bool
}{
{
"path to folder",
"/opt/foo",
false,
},
{
"path to file",
"/opt/foo.txt",
false,
},
{
"http to file",
"http://kuttl.dev/foo.txt",
true,
},
{
"https to file",
"https://kuttl.dev/foo.txt",
true,
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
if got := IsURL(tt.path); got != tt.want {
t.Errorf("IsURL() = %v, want %v", got, tt.want)
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/kuttlctl/cmd/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ For more detailed documentation, visit: https://kudo.dev/docs/testing`,

// Load the configuration YAML into options.
if configPath != "" {
objects, err := testutils.LoadYAML(configPath)
objects, err := testutils.LoadYAMLFromFile(configPath)
if err != nil {
return err
}
Expand Down
50 changes: 30 additions & 20 deletions pkg/test/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

harness "github.com/kudobuilder/kuttl/pkg/apis/testharness/v1beta1"
kfile "github.com/kudobuilder/kuttl/pkg/file"
"github.com/kudobuilder/kuttl/pkg/http"
testutils "github.com/kudobuilder/kuttl/pkg/test/utils"
)

Expand Down Expand Up @@ -415,14 +416,14 @@ func (s *Step) String() string {
return fmt.Sprintf("%d-%s", s.Index, s.Name)
}

// LoadYAML loads the resources from a YAML file for a test step:
// LoadYAMLFromFile loads the resources from a YAML file for a test step:
// * If the YAML file is called "assert", then it contains objects to
// add to the test step's list of assertions.
// * If the YAML file is called "errors", then it contains objects that,
// if seen, mark a test immediately failed.
// * All other YAML files are considered resources to create.
func (s *Step) LoadYAML(file string) error {
objects, err := testutils.LoadYAML(file)
objects, err := testutils.LoadYAMLFromFile(file)
if err != nil {
return fmt.Errorf("loading %s: %s", file, err)
}
Expand Down Expand Up @@ -481,37 +482,25 @@ func (s *Step) LoadYAML(file string) error {
if s.Step != nil {
// process configured step applies
for _, applyPath := range s.Step.Apply {
paths, err := kfile.FromPath(filepath.Join(s.Dir, applyPath), "*.yaml")
apply, err := runtimeObjectsFromPath(s, applyPath)
if err != nil {
return fmt.Errorf("step %q apply %w", s.Name, err)
}
apply, err := kfile.ToRuntimeObjects(paths)
if err != nil {
return fmt.Errorf("step %q apply %w", s.Name, err)
return err
}
applies = append(applies, apply...)
}
// process configured step asserts
for _, assertPath := range s.Step.Assert {
paths, err := kfile.FromPath(filepath.Join(s.Dir, assertPath), "*.yaml")
if err != nil {
return fmt.Errorf("step %q assert %w", s.Name, err)
}
assert, err := kfile.ToRuntimeObjects(paths)
assert, err := runtimeObjectsFromPath(s, assertPath)
if err != nil {
return fmt.Errorf("step %q assert %w", s.Name, err)
return err
}
asserts = append(asserts, assert...)
}
// process configured errors
for _, errorPath := range s.Step.Error {
paths, err := kfile.FromPath(filepath.Join(s.Dir, errorPath), "*.yaml")
errObjs, err := runtimeObjectsFromPath(s, errorPath)
if err != nil {
return fmt.Errorf("step %q error %w", s.Name, err)
}
errObjs, err := kfile.ToRuntimeObjects(paths)
if err != nil {
return fmt.Errorf("step %q error %w", s.Name, err)
return err
}
s.Errors = append(s.Errors, errObjs...)
}
Expand All @@ -521,3 +510,24 @@ func (s *Step) LoadYAML(file string) error {
s.Asserts = asserts
return nil
}

func runtimeObjectsFromPath(s *Step, path string) ([]runtime.Object, error) {
if http.IsURL(path) {
apply, err := http.ToRuntimeObjects(path)
if err != nil {
return nil, fmt.Errorf("step %q apply %w", s.Name, err)
}
return apply, nil
}

// it's a directory or file
paths, err := kfile.FromPath(filepath.Join(s.Dir, path), "*.yaml")
if err != nil {
return nil, fmt.Errorf("step %q apply %w", s.Name, err)
}
apply, err := kfile.ToRuntimeObjects(paths)
if err != nil {
return nil, fmt.Errorf("step %q apply %w", s.Name, err)
}
return apply, nil
}
21 changes: 16 additions & 5 deletions pkg/test/utils/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -454,15 +454,19 @@ func MarshalObjectJSON(o runtime.Object, w io.Writer) error {
return json.NewSerializer(json.DefaultMetaFactory, nil, nil, false).Encode(copied, w)
}

// LoadYAML loads all objects from a YAML file.
func LoadYAML(path string) ([]runtime.Object, error) {
// LoadYAMLFromFile loads all objects from a YAML file.
func LoadYAMLFromFile(path string) ([]runtime.Object, error) {
opened, err := os.Open(path)
if err != nil {
return nil, err
}
defer opened.Close()

yamlReader := yaml.NewYAMLReader(bufio.NewReader(opened))
return LoadYAML(path, opened)
}

func LoadYAML(path string, r io.Reader) ([]runtime.Object, error) {
yamlReader := yaml.NewYAMLReader(bufio.NewReader(r))

objects := []runtime.Object{}

Expand All @@ -486,11 +490,18 @@ func LoadYAML(path string) ([]runtime.Object, error) {
if err != nil {
return nil, fmt.Errorf("error converting unstructured object %s (%s): %w", ResourceID(unstructuredObj), path, err)
}
// discovered reader will return empty objects if a number of lines are preceding a yaml separator (---)
// this detects that, logs and continues
if obj.GetObjectKind().GroupVersionKind().Kind == "" {
log.Println("object detected with no GVK Kind for path", path)
} else {
objects = append(objects, obj)
}

objects = append(objects, obj)
}

return objects, nil

}

// MatchesKind returns true if the Kubernetes kind of obj matches any of kinds.
Expand Down Expand Up @@ -532,7 +543,7 @@ func InstallManifests(ctx context.Context, client client.Client, dClient discove
return nil
}

objs, err := LoadYAML(path)
objs, err := LoadYAMLFromFile(path)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/test/utils/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ spec:
t.Fatal(err)
}

objs, err := LoadYAML(tmpfile.Name())
objs, err := LoadYAMLFromFile(tmpfile.Name())
assert.Nil(t, err)

assert.Equal(t, &unstructured.Unstructured{
Expand Down Expand Up @@ -227,7 +227,7 @@ metadata:
t.Fatal(err)
}

objs, err := LoadYAML(tmpfile.Name())
objs, err := LoadYAMLFromFile(tmpfile.Name())
assert.Nil(t, err)

crd := NewResource("apiextensions.k8s.io/v1beta1", "CustomResourceDefinition", "", "")
Expand Down

0 comments on commit b85c5a0

Please sign in to comment.