diff --git a/js/modules/k6/execution/execution.go b/js/modules/k6/execution/execution.go index 56e944499ca3..ed2bca31e483 100644 --- a/js/modules/k6/execution/execution.go +++ b/js/modules/k6/execution/execution.go @@ -193,7 +193,19 @@ func (mi *ModuleInstance) newVUInfo() (*goja.Object, error) { }, } - return newInfoObj(rt, vi) + o, err := newInfoObj(rt, vi) + if err != nil { + return nil, err + } + + err = o.Set("tags", rt.NewDynamicObject(&tagsDynamicObject{ + Runtime: rt, + Tags: vuState.Tags, + })) + if err != nil { + return nil, err + } + return o, nil } func newInfoObj(rt *goja.Runtime, props map[string]func() interface{}) (*goja.Object, error) { @@ -208,3 +220,49 @@ func newInfoObj(rt *goja.Runtime, props map[string]func() interface{}) (*goja.Ob return o, nil } + +type tagsDynamicObject struct { + Runtime *goja.Runtime + Tags *lib.TagMap +} + +// Get a property value for the key. May return nil if the property does not exist. +func (o *tagsDynamicObject) Get(key string) goja.Value { + tag, ok := o.Tags.Get(key) + if !ok { + return nil + } + return o.Runtime.ToValue(tag) +} + +// Set a property value for the key. Return true if succeed. +func (o *tagsDynamicObject) Set(key string, val goja.Value) bool { + o.Tags.Set(key, val.String()) + return true +} + +// Has returns true if the property exists. +func (o *tagsDynamicObject) Has(key string) bool { + _, ok := o.Tags.Get(key) + return ok +} + +// Delete deletes the property for the key. It returns true on success (note, that includes missing property). +func (o *tagsDynamicObject) Delete(key string) bool { + o.Tags.Delete(key) + return true +} + +// Keys returns a slice with all existing property keys. The order is not deterministic. +func (o *tagsDynamicObject) Keys() []string { + if o.Tags.Len() < 1 { + return nil + } + + tags := o.Tags.Clone() + keys := make([]string, 0, len(tags)) + for k := range tags { + keys = append(keys, k) + } + return keys +} diff --git a/js/modules/k6/execution/execution_test.go b/js/modules/k6/execution/execution_test.go new file mode 100644 index 000000000000..ec32a13e03f1 --- /dev/null +++ b/js/modules/k6/execution/execution_test.go @@ -0,0 +1,81 @@ +/* + * + * k6 - a next-generation load testing tool + * Copyright (C) 2021 Load Impact + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +package execution + +import ( + "context" + "testing" + + "github.com/dop251/goja" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.k6.io/k6/js/common" + "go.k6.io/k6/js/modulestest" + "go.k6.io/k6/lib" + "go.k6.io/k6/stats" +) + +func TestVUTags(t *testing.T) { + t.Parallel() + + rt := goja.New() + ctx := common.WithRuntime(context.Background(), rt) + ctx = lib.WithState(ctx, &lib.State{ + Options: lib.Options{ + SystemTags: stats.NewSystemTagSet(stats.TagVU), + }, + Tags: lib.NewTagMap(map[string]string{ + "vu": "42", + }), + }) + m, ok := New().NewModuleInstance( + &modulestest.InstanceCore{ + Runtime: rt, + InitEnv: &common.InitEnvironment{}, + Ctx: ctx, + }, + ).(*ModuleInstance) + require.True(t, ok) + require.NoError(t, rt.Set("exec", m.GetExports().Default)) + + // overwrite a system tag is allowed + _, err := rt.RunString(`exec.vu.tags["vu"] = 101`) + require.NoError(t, err) + + // asserts get of tag and that the sys tag set has been discarded + val, err := rt.RunString(`exec.vu.tags["vu"]`) + require.NoError(t, err) + assert.Equal(t, "101", val.String()) + + // not found + tag, err := rt.RunString(`exec.vu.tags["not-existing-tag"]`) + require.NoError(t, err) + assert.Equal(t, "undefined", tag.String()) + + // set + _, err = rt.RunString(`exec.vu.tags["custom-tag"] = "mytag"`) + require.NoError(t, err) + + // get + tag, err = rt.RunString(`exec.vu.tags["custom-tag"]`) + require.NoError(t, err) + assert.Equal(t, "mytag", tag.String()) +}