Skip to content

Commit

Permalink
test: add bundle files test
Browse files Browse the repository at this point in the history
  • Loading branch information
b4nst committed Jul 6, 2023
1 parent 040c262 commit b8f7959
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 76 deletions.
62 changes: 46 additions & 16 deletions cmd/timoni/bundle_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ package main

import (
"fmt"
"os"
"path/filepath"
"io/ioutil"
"strings"
"testing"

Expand Down Expand Up @@ -31,35 +30,66 @@ func Test_BundleBuild(t *testing.T) {
))
g.Expect(err).ToNot(HaveOccurred())

bundleData := fmt.Sprintf(`
bundleCue := fmt.Sprintf(`
appName: string @timoni(env:string:TEST_BBUILD_NAME)
bundle: {
apiVersion: "v1alpha1"
name: "%[1]s"
name: string
instances: {
"\(appName)": {
module: {
url: "oci://%[2]s"
version: "%[3]s"
url: "oci://%[1]s"
version: "%[2]s"
}
namespace: "%[4]s"
namespace: "%[3]s"
values: server: enabled: false
values: domain: string @timoni(env:string:TEST_BBUILD_HOST)
}
backend: {
module: {
url: "oci://%[2]s"
version: "%[3]s"
url: "oci://%[1]s"
version: "%[2]s"
}
namespace: "%[4]s"
namespace: string
values: client: enabled: bool @timoni(env:bool:TEST_BBUILD_ENABLED)
}
}
}
`, bundleName, modURL, modVer, namespace)
`, modURL, modVer, namespace)

bundlePath := filepath.Join(t.TempDir(), "bundle.cue")
err = os.WriteFile(bundlePath, []byte(bundleData), 0644)
bundleData := bundleCue + fmt.Sprintf(`
bundle: name: "%[1]s"
bundle: instances: backend: namespace: "%[2]s"
`, bundleName, namespace)

bundleJson := fmt.Sprintf(`
{
"bundle": {
"name": "%[1]s"
}
}
`, bundleName)

bundleYaml := fmt.Sprintf(`
bundle:
instances:
backend:
namespace: %[1]s
`, namespace)

cuef, err := ioutil.TempFile(t.TempDir(), "*.cue")
g.Expect(err).ToNot(HaveOccurred())
_, err = cuef.Write([]byte(bundleCue))
g.Expect(err).ToNot(HaveOccurred())

yamlf, err := ioutil.TempFile(t.TempDir(), "*.yaml")
g.Expect(err).ToNot(HaveOccurred())
_, err = yamlf.Write([]byte(bundleYaml))
g.Expect(err).ToNot(HaveOccurred())

jsonf, err := ioutil.TempFile(t.TempDir(), "*.json")
g.Expect(err).ToNot(HaveOccurred())
_, err = jsonf.Write([]byte(bundleJson))
g.Expect(err).ToNot(HaveOccurred())

t.Setenv("TEST_BBUILD_NAME", "frontend")
Expand All @@ -68,10 +98,10 @@ bundle: {

t.Run("builds instances from bundle", func(t *testing.T) {
execCommands := map[string]func() (string, error){
"using a file": func() (string, error) {
"using files": func() (string, error) {
return executeCommand(fmt.Sprintf(
"bundle build -f %s -p main",
bundlePath,
"bundle build -f %s -f %s -f %s -p main",
cuef.Name(), yamlf.Name(), jsonf.Name(),
))
},
"using stdin": func() (string, error) {
Expand Down
93 changes: 34 additions & 59 deletions internal/engine/bundle_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@ limitations under the License.
package engine

import (
"bytes"
"errors"
"fmt"
"os"
"path/filepath"
"io"

"cuelang.org/go/cue"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"cuelang.org/go/cue/parser"
"cuelang.org/go/encoding/json"
"cuelang.org/go/encoding/yaml"
cp "github.com/otiai10/copy"

apiv1 "github.com/stefanprodan/timoni/api/v1alpha1"
)
Expand Down Expand Up @@ -75,23 +72,45 @@ func (b *BundleBuilder) InitWorkspace(workspace string) error {
var files []string
for i, file := range b.files {
_, fn := filepath.Split(file)
dstFile := filepath.Join(workspace, fmt.Sprintf("%v.%s", i, fn))
files = append(files, dstFile)
if err := cp.Copy(file, dstFile); err != nil {
return err
content, err := os.ReadFile(file)
if err != nil {
return fmt.Errorf("failed to read %s: %w", fn, err)
}
}

for _, f := range files {
_, fn := filepath.Split(f)
data, err := b.injector.Inject(f)
var node ast.Node

ext := filepath.Ext(file)
switch ext {
case ".yaml", ".yml":
node, err = yaml.Extract(file, content)
if err != nil {
return fmt.Errorf("failed to extract %s: %w", fn, err)
}
case ".json":
node, err = json.Extract(file, content)
if err != nil {
return fmt.Errorf("failed to extract %s: %w", fn, err)
}
case ".cue":
node, err = parser.ParseFile(file, content, parser.ParseComments)
if err != nil {
return fmt.Errorf("failed to parse %s: %w", fn, err)
}
default:
return fmt.Errorf("unsupported file extension %s", ext)
}

data, err := b.injector.InjectNode(node)
if err != nil {
return fmt.Errorf("failed to inject %s: %w", fn, err)
}

if err := os.WriteFile(f, data, os.ModePerm); err != nil {
return fmt.Errorf("failed to inject %s: %w", fn, err)
dstFile := filepath.Join(workspace, fmt.Sprintf("%v.%s.cue", i, fn))
if err := os.WriteFile(dstFile, data, os.ModePerm); err != nil {
return fmt.Errorf("failed to write %s: %w", fn, err)
}

files = append(files, dstFile)
}

schemaFile := filepath.Join(workspace, fmt.Sprintf("%v.schema.cue", len(b.files)+1))
Expand Down Expand Up @@ -124,26 +143,6 @@ func (b *BundleBuilder) Build() (cue.Value, error) {
}

v := b.ctx.BuildInstance(inst)
for _, f := range inst.OrphanedFiles {
switch f.Encoding {
case build.YAML:
a, err := yaml.Extract(f.Filename, f.Source)
if err != nil {
return value, err
}
v = v.Unify(b.ctx.BuildFile(a))
case build.JSON:
src, err := readSource(f.Filename, f.Source)
if err != nil {
return value, err
}
exp, err := json.Extract(f.Filename, src)
if err != nil {
return value, err
}
v = v.Unify(b.ctx.BuildExpr(exp))
}
}
if v.Err() != nil {
return value, v.Err()
}
Expand All @@ -155,30 +154,6 @@ func (b *BundleBuilder) Build() (cue.Value, error) {
return v, nil
}

func readSource(filename string, src interface{}) ([]byte, error) {
if src != nil {
switch s := src.(type) {
case string:
return []byte(s), nil
case []byte:
return s, nil
case *bytes.Buffer:
// is io.Reader, but src is already available in []byte form
if s != nil {
return s.Bytes(), nil
}
case io.Reader:
var buf bytes.Buffer
if _, err := io.Copy(&buf, s); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
return nil, errors.New("invalid source")
}
return os.ReadFile(filename)
}

// GetBundle returns a Bundle from the bundle CUE value.
func (b *BundleBuilder) GetBundle(v cue.Value) (*Bundle, error) {
bundleNameValue := v.LookupPath(cue.ParsePath(apiv1.BundleName.String()))
Expand Down
6 changes: 5 additions & 1 deletion internal/engine/injector.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ func (in *Injector) Inject(src string) ([]byte, error) {
return nil, err
}

return in.InjectNode(tree)
}

func (in *Injector) InjectNode(tree ast.Node) ([]byte, error) {
output, err := in.injectFromEnv(tree)
if err != nil {
return nil, err
Expand All @@ -67,7 +71,7 @@ func (in *Injector) Inject(src string) ([]byte, error) {
return data, nil
}

func (in *Injector) injectFromEnv(tree *ast.File) (ast.Node, error) {
func (in *Injector) injectFromEnv(tree ast.Node) (ast.Node, error) {
var re error
f := func(c astutil.Cursor) bool {
n := c.Node()
Expand Down

0 comments on commit b8f7959

Please sign in to comment.