grafana / jmeter-to-k6

Converts JMeter .jmx files to k6 JS code
Apache License 2.0
69 stars 22 forks source link

Implement jmeter-to-k6 #2

Closed bookmoons closed 5 years ago

bookmoons commented 5 years ago

Adds v1 implementation of the converter. Converts all elements listed in #1.

Closes #1.

robingustafsson commented 5 years ago

@bookmoons Fantastic! I'll start reviewing this. Will begin by trying to convert a bunch of JMeter tests.

robingustafsson commented 5 years ago

Ok, I've played around with the converter a bit. This first round of feedback is just based on what I experienced while using the tool, I haven't looked much at the code yet. Great job overall from what I've seen so far! 🎉

General

JSON Path Assertion/Extraction

Error: Unrecognized element: JSONPathAssertion at element (/Users//jmeter-to-k6/src/element.js:48:27) at module.exports.args (/Users//jmeter-to-k6/src/element.js:1:102) at elements (/Users//jmeter-to-k6/src/elements.js:17:43) at module.exports.args (/Users//jmeter-to-k6/src/elements.js:1:102) at Object.hashTree (/Users//jmeter-to-k6/src/element/hashTree.js:4:10) at element (/Users//jmeter-to-k6/src/element.js:50:21) at module.exports.args (/Users//jmeter-to-k6/src/element.js:1:102) at elements (/Users//jmeter-to-k6/src/elements.js:17:43) at module.exports.args (/Users//jmeter-to-k6/src/elements.js:1:102) at Object.ThreadGroup (/Users//jmeter-to-k6/src/element/ThreadGroup.js:16:17)


## Random Controller
* Only seems to generate 1 case (`case 0: ...`), and throws `Error: Unexpected random index: 1` for all other possible options (see JMX and generated JS: https://gist.github.com/robingustafsson/7eae7a30a438f074de8a1c36cdbaa99b)

## Thread group
* Could the `if (__VU >= max_vus && __VU <= max_vus) { ... } else throw new Error('Unexpected VU: ' + __VU)` code be removed if only 1 thread group is used? (see JMX and generated JS: https://gist.github.com/robingustafsson/16979a21fcedbff9766cee7a48dd9d4a)
    * Also, I think we can skip the `else throw new Error('Unexpected VU: ' + __VU)` in all cases
* If `forever` is not selected and instead an iteration count (`loops`) has been specified there should be a statement like this in the generated script:
```js
export default function() {
    if (__ITER < whatever_iteration_count_specified) {
        // All thread group code
    }
}

Stepping thread group

bookmoons commented 5 years ago

Really nice. Updating all of this.

bookmoons commented 5 years ago

These were really good bug reports. Everything but the SteppingThreadGroup is fixed/updated. Will be getting into that stepping logic tomorrow.

bookmoons commented 5 years ago

The SteppingThreadGroup is converting as specified. Also added all the test files to examples.

robingustafsson commented 5 years ago

Good stuff! I'll do a second review tomorrow.

robingustafsson commented 5 years ago

Sorry for the delay. Have now done a second pass after your fixes, found some more issues:

General

If controller

Stepping thread group

bookmoons commented 5 years ago

Thanks for that. Have updated all of it.

Not sure what caused Babel requirement, but I added it as a dependency. The only package I've added to bundle was papaparse for the CSV update.


When I have a statement like ${someVariable}=="Some string" in JMeter it converts to something like this in k6 JS

I think this piece is following JMeter. The IfController has a special flag for the condition, it seemed to be the only one that has it.

Interpret Condition as Variable Expression?
If this is selected, then the condition must be an expression that evaluates to "true" (case is ignored).

(Expression here meaning a JMeter expression). If you uncheck that flag then it's meant to be JavaScript, and it should render with an eval.


When running this the JSON extraction block (JSONPostProcessor) that is defined above the if-controller is also included inside the if-statement in the generated JS.

I think this one is correct. Processors and assertions are supposed to apply to all descendants of the parent element. So it caches them up in the context and duplicates for all samplers in that section of the tree.

bookmoons commented 5 years ago

It looks like that Babel requirement comes from yaml, only necessary when bundling. So I think it's OK:

It runs on Node.js 6 and later with no external dependencies, and in browsers from IE 11 upwards using @babel/runtime (Note: not included in dependencies, install separately).

That package is used by JSONPathAssertion JSONPathExtractor to support YAML data in a response body.

robingustafsson commented 5 years ago

Ah, you're right about the IFController and var expression vs JS code. I'd missed unchecking that flag.

Regarding the post processors and assertions you're also correct that they apply to all samplers in the same scope. Think I found another issue here though:

bookmoons commented 5 years ago

It seems that even when I add the post-processor to be a child of the sampler, the post-processor is still applied to children of the grandparent

Think I know just where I did this. Looking into it.

bookmoons commented 5 years ago

Not what I thought it was, but I've just pushed a fix.

robingustafsson commented 5 years ago

Ok @bookmoons. I've looked through the code as well and I think it looks good; structure, style and tests. Well done, thanks for your work on this 👏Now, go claim the bounty!

PS. I sent you a message on k6 slack if you can have a look when you get a chance.

bookmoons commented 5 years ago

Very nice, thank you very much. Submitted a claim and will open slack.