Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check data returned from setup() to ensure it contains only data, no functions. #558

Closed
vtanakas opened this issue Mar 22, 2018 · 5 comments
Assignees

Comments

@vtanakas
Copy link

vtanakas commented Mar 22, 2018

Apparently, if the object returned from setup() is an object that contains a function, or contains an object that contains a function (etc...) then that function is quietly stripped from the object, making it unavailable in the default() function call.

Instead, between the call to setup() and default(), the object returned from setup() should be examined and if it contains any non basic data type fields, an exception should be raised and the test aborted.

Alternatively, the data object could be provided to default() with its functions intact, but I imagine there may be other problems with that.

From eventdb.js

export class EventDB {
    constructor(dbHost) {
        this.dbHost = dbHost;
    }

    writeLogin(serverId, userId) {
        writeEvent(this.dbHost, {
            eventType:"login",
            serverId:serverId,
            userId:userId,
            time:Date.now()
        });
    }
}

From test.js

export function setup() {
    let eventDb = new eventdb.EventDB(EVENT_DB_HOST);
    let my_retval = {"db":eventDb };
    return my_retval;
}

export function default(globalData) {
    // Throws errror message, because of undefined member writeLogin.
    globalData["db"].writeLogin("server1", "user1");
}
@robingustafsson
Copy link
Member

Ah, good catch. Yes, we should definitely raise an exception if data returned by setup() contains anything but plain old data.

We need the data returned by setup() to be independent from the machine and k6 instance/process where setup() is executed. When running in a clustered/distributed execution mode there might be several hundred machines involved in running the test, and only one server will run the setup()/teardown() but all machines will need the data returned by setup() to be passed to the default function.

@robingustafsson robingustafsson added this to the v1.0.0 milestone May 8, 2018
@luizbafilho
Copy link
Contributor

I don't think to raise an exception would be the better approach, since the data in that object is still accessible. So, if you try the following you would get a response:

export default function(globalData) {
  console.log(globalData["db"].dbHost)
};

I guess a better way would document that functions won't be available as part of the data passed to the default function via setup return.

@luizbafilho
Copy link
Contributor

@robingustafsson and @na-- what do you think?

@na--
Copy link
Member

na-- commented Jun 26, 2018

It seems that currently the data returned by setup() is intentionally marshaled to JSON and straight back to a Go interface{}. It's not very clear why from the commit (:smile:) message, but it's fairly obvious that this is used as a way to remove any non-data parts of the result. As @robingustafsson mentioned, for cloud/clustered execution the returned data needs to be independent from the actual machine. I'd say that even for local execution, if setup() returns a purely JS function, it probably won't work correctly if it's directly passed from the original goja runtime that executed setup() to the other VU runtimes.

@luizbafilho, I agree that we should update the docs to mention this, but I think that it's also probably worth it to either emit a warning or exit with an error if users return non-data values from setup()... We can't "throw an exception" since this would be better handled outside of the JS runtime. My only concern is that it would be somewhat complicated and ugly to implement - we probably have to recursively use reflection on v.Export() or use the properties of the v goja Object to look for functions, which doesn't sound like a fun exercise... I'm also somewhat concerned about correctly handling corner cases like the difference between returning pure JS functions and objects (which is bad) and returning k6 Go objects that have methods, which may be bad, but maybe it's not - the http.response object for example...

@na--
Copy link
Member

na-- commented Oct 10, 2018

Closing this, since #799 was merged today. I also updated the docs to mention that only data is passed from setup and created this issue for the remaining incorrect JSON encoding of internal k6 objects.

@na-- na-- closed this as completed Oct 10, 2018
@na-- na-- removed this from the v1.0.0 milestone Jul 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants