Skip to content

Commit

Permalink
Fix for broken backticks in manifest
Browse files Browse the repository at this point in the history
Having a manifest with Go template expressions, but where all
expressions only use backticks, would lead to the Go template not being
executed, since such a manifest was also by coincidence a perfectly
valid JSON array that was executed right away.

Fixed by always executing the Go template, regardless of whether the
input already is valid JSON.
  • Loading branch information
Lucas Hinderberger committed Jun 4, 2024
1 parent c38e421 commit d348fdf
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 47 deletions.
92 changes: 45 additions & 47 deletions api_testsuite.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,19 @@ func (ats *Suite) parseAndRunTest(v any, manifestDir, testFilePath string, k, re
loader.ServerURL = serverURL
loader.OAuthClient = ats.Config.OAuthClient

// Get the (optional) number of repititions from the test path spec
isParallelPathSpec := false
switch t := v.(type) {
case string:
isParallelPathSpec = util.IsParallelPathSpec(t)
parallelRepititions := 1
if isParallelPathSpec {
switch t := v.(type) {
case string:
parallelRepititions, _ = util.GetParallelPathSpec(t)

// FIXME - Shouldn't this be > 1 (also in util.IsParallelPathSpec)?
// If so, the declaration in L.6 can be removed and this can be turned
// into a declaration and moved to after the if block.
isParallelPathSpec = parallelRepititions > 0
}
}

//Get the Manifest with @ logic
Expand All @@ -245,6 +254,22 @@ func (ats *Suite) parseAndRunTest(v any, manifestDir, testFilePath string, k, re
return false
}

// Parse as template always
requestBytes, lErr := loader.Render(testObj, filepath.Join(manifestDir, dir), nil)
if lErr != nil {
r.SaveToReportLog(lErr.Error())
logrus.Error(fmt.Errorf("can not render template (%s): %s", testFilePath, lErr))
return false
}

// If objects are different, we did have a Go template, recurse one level deep
if string(requestBytes) != string(testObj) {
return ats.parseAndRunTest([]byte(requestBytes), filepath.Join(manifestDir, dir),
testFilePath, k, parallelRepititions, isParallelPathSpec, r, loader)
}

testObj = requestBytes

//Try to directly unmarshal the manifest into testcase array
var testCases []json.RawMessage
err = util.Unmarshal(testObj, &testCases)
Expand Down Expand Up @@ -280,57 +305,30 @@ func (ats *Suite) parseAndRunTest(v any, manifestDir, testFilePath string, k, re
} else {
// We were not able unmarshal into array, so we try to unmarshal into raw message

// Get the (optional) number of repititions from the test path spec
parallelRepititions := 1
if isParallelPathSpec {
switch t := v.(type) {
case string:
parallelRepititions, _ = util.GetParallelPathSpec(t)
}
}

// Parse as template always
requestBytes, lErr := loader.Render(testObj, filepath.Join(manifestDir, dir), nil)
if lErr != nil {
r.SaveToReportLog(lErr.Error())
logrus.Error(fmt.Errorf("can not render template (%s): %s", testFilePath, lErr))
return false
}

// If objects are different, we did have a Go template, recurse one level deep
if string(requestBytes) != string(testObj) {
return ats.parseAndRunTest([]byte(requestBytes), filepath.Join(manifestDir, dir),
testFilePath, k, parallelRepititions, isParallelPathSpec, r, loader)
}

// Its a JSON at this point, assign and proceed to parse
testObj = requestBytes

var singleTest json.RawMessage
err = util.Unmarshal(testObj, &singleTest)
if err == nil {

//Check if is @ and if so load the test
if util.IsPathSpec(string(testObj)) {
var sS string

err := util.Unmarshal(testObj, &sS)
if err != nil {
r.SaveToReportLog(err.Error())
logrus.Error(fmt.Errorf("can not unmarshal (%s): %s", testFilePath, err))
return false
}

return ats.parseAndRunTest(sS, filepath.Join(manifestDir, dir), testFilePath, k, parallelRepititions, isParallelPathSpec, r, template.Loader{})
} else {
return ats.runSingleTest(TestContainer{CaseByte: testObj, Path: filepath.Join(manifestDir, dir)}, r, testFilePath, loader, k, runParallel)
}
} else {
if err != nil {
// Malformed json
r.SaveToReportLog(err.Error())
logrus.Error(fmt.Errorf("can not unmarshal (%s): %s", testFilePath, err))
return false
}

//Check if is @ and if so load the test
if util.IsPathSpec(string(testObj)) {
var sS string

err := util.Unmarshal(testObj, &sS)
if err != nil {
r.SaveToReportLog(err.Error())
logrus.Error(fmt.Errorf("can not unmarshal (%s): %s", testFilePath, err))
return false
}

return ats.parseAndRunTest(sS, filepath.Join(manifestDir, dir), testFilePath, k, parallelRepititions, isParallelPathSpec, r, template.Loader{})
} else {
return ats.runSingleTest(TestContainer{CaseByte: testObj, Path: filepath.Join(manifestDir, dir)}, r, testFilePath, loader, k, runParallel)
}
}

return true
Expand Down
13 changes: 13 additions & 0 deletions pkg/lib/template/template_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ type delimiters struct {

var delimsRE = regexp.MustCompile(`(?m)^[\t ]*(?://|/\*)[\t ]*template-delims:[\t ]*([^\t ]+)[\t ]+([^\t\n ]+).*$`)

// Loader loads and executes a manifest template.
//
// A manifest template is a customized version of Go's text/template, plus
// custom template functions (which are initialized with the Loader's
// properties, where applicable).
type Loader struct {
datastore *datastore.Datastore
HTTPServerHost string
Expand All @@ -50,6 +55,14 @@ func NewLoader(datastore *datastore.Datastore) Loader {
return Loader{datastore: datastore}
}

// Render loads and executes a manifest template.
//
// For a description of the manifest template, refer to Loader's docstring.
//
// - tmplBytes is the manifest template, as loaded from disk.
// - rootDir is the path of the directory in which manifest resides.
// - ctx is the data passed on to the template's Execute function.
// Contrary to what convention may suggest, it is not a context.Context.
func (loader *Loader) Render(
tmplBytes []byte,
rootDir string,
Expand Down

0 comments on commit d348fdf

Please sign in to comment.