Skip to content

Commit

Permalink
Discard execution metadata option from old archives
Browse files Browse the repository at this point in the history
  • Loading branch information
na-- committed Aug 14, 2019
1 parent e3c279f commit c202415
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 17 deletions.
86 changes: 71 additions & 15 deletions lib/archive.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,76 @@ func (arc *Archive) getFs(name string) afero.Fs {
return fs
}

// cleanUpWrongMetadataJSON fixes issues with the metadata.json contents before
// they are unmarshalled in the Archive struct.
//
// Currently, the only fix this function performs is the discarding of the
// derived `execution` config value in the consolidated options that was wrongly
// saved by k6 in the archive metadata.json files until commit
// 83193f8a96e06a190325b838b2cc451119d6b836. This basically means k6 v0.24.0 and
// surrounding master commits. We filter these out by the value of the k6version
// property, saved in the metadata.json since the previous to the above commit.
func cleanUpWrongMetadataJSON(data []byte) ([]byte, error) {
var tmpArc map[string]interface{}
if err := json.Unmarshal(data, &tmpArc); err != nil {
return nil, err
}

k6Version := ""
if k6RawVersion, ok := tmpArc["k6version"]; ok {
if k6Version, ok = k6RawVersion.(string); !ok {
return nil, fmt.Errorf("k6version is present in the archive metadata, but it's not a string")
}
}

// TODO: semantically parse the k6version and compare it with the current
// one, log a warning if the current k6 version in lib/consts is lower than
// the k6 version that generated the archive.

if k6Version != "" && k6Version != "0.24.0" {
return data, nil
}

if rawOptions, ok := tmpArc["options"]; !ok {
return nil, fmt.Errorf("missing options key in the archive metadata.json")
} else if options, ok := rawOptions.(map[string]interface{}); !ok {
return nil, fmt.Errorf("wrong options type in metadata.json")
} else if _, hasExecution := options["execution"]; !hasExecution {
return data, nil // no need to fix anything
} else {
delete(options, "execution")
tmpArc["options"] = options
}

return json.Marshal(tmpArc)
}

func (arc *Archive) loadMetadataJSON(data []byte) error {
data, err := cleanUpWrongMetadataJSON(data)
if err != nil {
return err
}

if err = json.Unmarshal(data, &arc); err != nil {
return err
}
// Path separator normalization for older archives (<=0.20.0)
if arc.K6Version == "" {
arc.Filename = NormalizeAndAnonymizePath(arc.Filename)
arc.Pwd = NormalizeAndAnonymizePath(arc.Pwd)
}
arc.PwdURL, err = loader.Resolve(&url.URL{Scheme: "file", Path: "/"}, arc.Pwd)
if err != nil {
return err
}
arc.FilenameURL, err = loader.Resolve(&url.URL{Scheme: "file", Path: "/"}, arc.Filename)
if err != nil {
return err
}

return nil
}

// ReadArchive reads an archive created by Archive.Write from a reader.
func ReadArchive(in io.Reader) (*Archive, error) {
r := tar.NewReader(in)
Expand All @@ -131,23 +201,9 @@ func ReadArchive(in io.Reader) (*Archive, error) {

switch hdr.Name {
case "metadata.json":
if err = json.Unmarshal(data, &arc); err != nil {
return nil, err
}
// Path separator normalization for older archives (<=0.20.0)
if arc.K6Version == "" {
arc.Filename = NormalizeAndAnonymizePath(arc.Filename)
arc.Pwd = NormalizeAndAnonymizePath(arc.Pwd)
}
arc.PwdURL, err = loader.Resolve(&url.URL{Scheme: "file", Path: "/"}, arc.Pwd)
if err != nil {
if err = arc.loadMetadataJSON(data); err != nil {
return nil, err
}
arc.FilenameURL, err = loader.Resolve(&url.URL{Scheme: "file", Path: "/"}, arc.Filename)
if err != nil {
return nil, err
}

continue
case "data":
arc.Data = data
Expand Down
84 changes: 82 additions & 2 deletions lib/old_archive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/loadimpact/k6/lib/fsext"
"github.com/loadimpact/k6/lib/scheduler"
"github.com/spf13/afero"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -69,7 +70,7 @@ func TestOldArchive(t *testing.T) {
for filename, data := range testCases {
filename, data := filename, data
t.Run(filename, func(t *testing.T) {
metadata := `{"filename": "` + filename + `"}`
metadata := `{"filename": "` + filename + `", "options": {}}`
fs := makeMemMapFs(t, map[string][]byte{
// files
"/files/github.com/loadimpact/k6/samples/example.js": []byte(`github file`),
Expand Down Expand Up @@ -187,7 +188,8 @@ func TestFilenamePwdResolve(t *testing.T) {
metadata := `{
"filename": "` + test.Filename + `",
"pwd": "` + test.Pwd + `",
"k6version": "` + test.version + `"
"k6version": "` + test.version + `",
"options": {}
}`

buf, err := dumpMemMapFsToBuf(makeMemMapFs(t, map[string][]byte{
Expand All @@ -206,3 +208,81 @@ func TestFilenamePwdResolve(t *testing.T) {
}
}
}

func TestDerivedExecutionDiscarding(t *testing.T) {
var emptyConfigMap scheduler.ConfigMap
var tests = []struct {
metadata string
expExecution interface{}
expError string
}{
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"options": { "execution": { "something": "invalid" } }
}`,
expExecution: emptyConfigMap,
},
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"k6version": "0.24.0",
"options": { "execution": { "something": "invalid" } }
}`,
expExecution: emptyConfigMap,
},
{
metadata: `blah`,
expError: "invalid character",
},
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"k6version": "0.24.0"
}`,
expError: "missing options key",
},
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"k6version": "0.24.0",
"options": "something invalid"
}`,
expError: "wrong options type in metadata.json",
},
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"k6version": "0.25.0",
"options": { "execution": { "something": "invalid" } }
}`,
expError: "cannot unmarshal string",
},
{
metadata: `{
"filename": "/test.js", "pwd": "/",
"k6version": "0.25.0",
"options": { "execution": { "default": { "type": "per-vu-iterations" } } }
}`,
expExecution: scheduler.ConfigMap{
DefaultSchedulerName: scheduler.NewPerVUIterationsConfig(DefaultSchedulerName),
},
},
}

for _, test := range tests {
buf, err := dumpMemMapFsToBuf(makeMemMapFs(t, map[string][]byte{
"/metadata.json": []byte(test.metadata),
}))
require.NoError(t, err)

arc, err := ReadArchive(buf)
if test.expError != "" {
require.Error(t, err)
require.Contains(t, err.Error(), test.expError)
} else {
require.NoError(t, err)
require.Equal(t, test.expExecution, arc.Options.Execution)
}
}
}

0 comments on commit c202415

Please sign in to comment.