Skip to content

Commit

Permalink
[bugfix] - fixing forever parameter handling in group and loop elemen…
Browse files Browse the repository at this point in the history
…ts (#125)

- the forever parameter now works same as in jmeter gui, it overrides the number of loops in user group and loop controller making it infinite
  • Loading branch information
smicyk authored Jan 29, 2024
1 parent 07fe36c commit df124bc
Show file tree
Hide file tree
Showing 29 changed files with 340 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,8 +23,8 @@ import org.apache.jmeter.testelement.TestElement

import net.simonix.dsl.jmeter.factory.TestElementNodeFactory

import static net.simonix.dsl.jmeter.utils.ConfigUtils.readValue
import static net.simonix.dsl.jmeter.utils.ConfigUtils.hasValue
import static net.simonix.dsl.jmeter.utils.LoopControllerUtils.updateLoopConfig

/**
* The factory class responsible for building <code>loop</code> element in the test.
Expand Down Expand Up @@ -56,19 +56,6 @@ final class LoopFactory extends TestElementNodeFactory {
count = value
}

if (hasValue(config.forever)) {
testElement.continueForever = config.forever
} else {
testElement.continueForever = false
}

// if forever is set to true, we should set count to negative value
if (testElement.continueForever) {
testElement.loops = -1
} else {
// if it is missing or false we should set it to true but keep the value of count, otherwise it is not consistent with jmeter behaviour
testElement.loops = count
testElement.continueForever = true
}
updateLoopConfig(testElement, count, hasValue(config.forever), config.forever)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,9 @@ import org.apache.jmeter.threads.gui.ThreadGroupGui

import net.simonix.dsl.jmeter.factory.TestElementNodeFactory

import static net.simonix.dsl.jmeter.utils.ConfigUtils.hasValue
import static net.simonix.dsl.jmeter.utils.LoopControllerUtils.updateLoopConfig

/**
* The factory class responsible for building <code>group</code> element in the test.
*
Expand Down Expand Up @@ -85,8 +88,8 @@ final class GroupFactory extends TestElementNodeFactory {

// set default controller as loop (that seems to be jmeter defaults)
LoopController defaultLoopController = new LoopController()
defaultLoopController.continueForever = config.forever
defaultLoopController.loops = config.loops
updateLoopConfig(defaultLoopController, config.loops, hasValue(config.forever), config.forever)

defaultLoopController.setEnabled(true)
defaultLoopController.setProperty(TestElement.TEST_CLASS, LoopController.name)
defaultLoopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,9 @@ import org.apache.jmeter.threads.PostThreadGroup
import org.apache.jmeter.threads.ThreadGroup
import org.apache.jmeter.threads.gui.PostThreadGroupGui

import static net.simonix.dsl.jmeter.utils.ConfigUtils.hasValue
import static net.simonix.dsl.jmeter.utils.LoopControllerUtils.updateLoopConfig

/**
* The factory class responsible for building <code>after</code> element in the test.
*
Expand Down Expand Up @@ -81,8 +84,8 @@ final class PostGroupFactory extends TestElementNodeFactory {

// set default controller as loop (that seems to be jmeter defaults)
LoopController defaultLoopController = new LoopController()
defaultLoopController.loops = config.loops
defaultLoopController.continueForever = config.forever
updateLoopConfig(defaultLoopController, config.loops, hasValue(config.forever), config.forever)

defaultLoopController.setEnabled(true)
defaultLoopController.setProperty(TestElement.TEST_CLASS, LoopController.name)
defaultLoopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.name)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -26,6 +26,9 @@ import org.apache.jmeter.threads.SetupThreadGroup
import org.apache.jmeter.threads.ThreadGroup
import org.apache.jmeter.threads.gui.SetupThreadGroupGui

import static net.simonix.dsl.jmeter.utils.ConfigUtils.hasValue
import static net.simonix.dsl.jmeter.utils.LoopControllerUtils.updateLoopConfig

/**
* The factory class responsible for building <code>before</code> element in the test.
*
Expand Down Expand Up @@ -81,8 +84,8 @@ final class PreGroupFactory extends TestElementNodeFactory {

// set default controller as loop (that seems to be jmeter defaults)
LoopController defaultLoopController = new LoopController()
defaultLoopController.loops = config.loops
defaultLoopController.continueForever = config.forever
updateLoopConfig(defaultLoopController, config.loops, hasValue(config.forever), config.forever)

defaultLoopController.setEnabled(true)
defaultLoopController.setProperty(TestElement.TEST_CLASS, LoopController.name)
defaultLoopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ final class DslDefinition {
property(name: 'scheduler', type: Boolean, required: false, defaultValue: false)
property(name: 'delay', type: Integer, required: false, defaultValue: 0, constraints: range(0))
property(name: 'duration', type: Integer, required: false, defaultValue: 0, constraints: range(0))
property(name: 'loops', type: Integer, required: false, defaultValue: 1, constraints: range(1))
property(name: 'loops', type: Integer, required: false, defaultValue: 1, constraints: range(-1))
property(name: 'forever', type: Boolean, required: false, defaultValue: false)
property(name: 'onError', type: String, required: false, defaultValue: 'continue', constraints: inList(['continue', 'start_next', 'stop_user', 'stop_test', 'stop_now']))
}
Expand Down Expand Up @@ -137,7 +137,7 @@ final class DslDefinition {
// controllers
static final KeywordDefinition LOOP = keyword('loop', KeywordCategory.CONTROLLER) {
include(COMMON_PROPERTIES)
property(name: 'count', type: Integer, required: false, defaultValue: 1, constraints: range(1))
property(name: 'count', type: Integer, required: false, defaultValue: 1, constraints: range(-1))
property(name: 'forever', type: Boolean, required: false, defaultValue: false)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package net.simonix.dsl.jmeter.utils

import groovy.transform.CompileDynamic
import org.apache.jmeter.testelement.TestElement

@CompileDynamic
final class LoopControllerUtils {

static void updateLoopConfig(TestElement testElement, Object count, boolean hasForever, boolean forever) {
if (hasForever) {
if (forever) {
testElement.loops = -1
} else {
testElement.loops = count
}
} else {
testElement.loops = count
}
}
}
6 changes: 3 additions & 3 deletions src/test/groovy/net/simonix/dsl/jmeter/StatisticsSpec.groovy
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -75,7 +75,7 @@ class StatisticsSpec extends MockServerSpec {
statistics.'GET /context/get'.error == 0.0d
statistics.'GET /context/get'.throughput > 200
statistics.'GET /context/get'.receivedBytes < 45000
statistics.'GET /context/get'.sentBytes < 85000
statistics.'GET /context/get'.sentBytes < 90000
statistics.'GET /context/get'.averagePageBytes < 500
statistics.'GET /context/get'.totalBytes < 7500

Expand All @@ -87,7 +87,7 @@ class StatisticsSpec extends MockServerSpec {
statistics.'SAMPLE'.error == 1.0d
statistics.'SAMPLE'.throughput > 200
statistics.'SAMPLE'.receivedBytes < 60000
statistics.'SAMPLE'.sentBytes < 85000
statistics.'SAMPLE'.sentBytes < 90000
statistics.'SAMPLE'.averagePageBytes < 500
statistics.'SAMPLE'.totalBytes < 7500

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2023 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -174,4 +174,41 @@ class ControllerFactorySpec extends TempFileSpec {
then: 'check if both files are the same'
filesAreTheSame(resultFile, resultFileRaw)
}

def "Check loop controllers generation with infinite"() {
given: 'Test plan with controllers element'
def config = configure {
plan {
group {
loop count: 1, {
// default behaviour
}

loop forever: true, {
// count set to -1
}

loop count: 2, forever: true, {
// count set to -1, forever overrides
}

loop count: 2, forever: false, {
// count set to 2, forever not used
}

loop count: 0, {
// count 0, no execution
}
}
}
}

File resultFile = tempFolder.newFile('controllers_2.jmx')

when: 'save test to file'
save(config, resultFile)

then: 'both files matches'
filesAreTheSame('controllers_2.jmx', resultFile)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022 Szymon Micyk
* Copyright 2024 Szymon Micyk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -74,9 +74,9 @@ class GroupFactorySpec extends TempFileSpec {
'var_onError': 'stop_test'
]

before(users: '${var_users}', rampUp: '${var_rampUp}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: true, onError: '${var_onError}', keepUser: false)
group(users: '${var_users}', rampUp: '${var_delay}', delayedStart: '${var_delayedStart}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: true, onError: '${var_onError}', keepUser: false)
after(users: '${var_users}', rampUp: '${var_duration}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: true, onError: 'stop_test', keepUser: false)
before(users: '${var_users}', rampUp: '${var_rampUp}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: false, onError: '${var_onError}', keepUser: false)
group(users: '${var_users}', rampUp: '${var_delay}', delayedStart: '${var_delayedStart}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: false, onError: '${var_onError}', keepUser: false)
after(users: '${var_users}', rampUp: '${var_duration}', scheduler: true, delay: '${var_delay}', duration: '${var_duration}', loops: '${var_loops}', forever: false, onError: 'stop_test', keepUser: false)
}
}

Expand Down Expand Up @@ -110,4 +110,39 @@ class GroupFactorySpec extends TempFileSpec {
then: 'both files matches'
filesAreTheSame('group_3.jmx', resultFile)
}

def "Check group behaviour for infinite configuration"() {
given: 'Test plan with schedule element'
def config = configure {
plan {
group loops: 1, {
// default behaviour
}

group forever: true, {
// loops set to -1
}

group loops: 2, forever: true, {
// loops set to -1, forever overrides
}

group loops: 2, forever: false, {
// loops set to 2, forever not used
}

group loops: 0, {
// loops 0, no execution
}
}
}

File resultFile = tempFolder.newFile('group_4.jmx')

when: 'save test to file'
save(config, resultFile)

then: 'both files matches'
filesAreTheSame('group_4.jmx', resultFile)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2023 Szymon Micyk
Copyright 2024 Szymon Micyk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,8 +39,8 @@
<intProp name="ThreadGroup.duration">0</intProp>
<intProp name="ThreadGroup.delay">0</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2023 Szymon Micyk
Copyright 2024 Szymon Micyk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,8 +39,8 @@
<intProp name="ThreadGroup.duration">0</intProp>
<intProp name="ThreadGroup.delay">0</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2023 Szymon Micyk
Copyright 2024 Szymon Micyk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,8 +39,8 @@
<intProp name="ThreadGroup.duration">0</intProp>
<intProp name="ThreadGroup.delay">0</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2023 Szymon Micyk
Copyright 2024 Szymon Micyk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,8 +39,8 @@
<intProp name="ThreadGroup.duration">0</intProp>
<intProp name="ThreadGroup.delay">0</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<!--
Copyright 2023 Szymon Micyk
Copyright 2024 Szymon Micyk
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -39,8 +39,8 @@
<intProp name="ThreadGroup.duration">0</intProp>
<intProp name="ThreadGroup.delay">0</intProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<intProp name="LoopController.loops">1</intProp>
<boolProp name="LoopController.continue_forever">false</boolProp>
</elementProp>
</ThreadGroup>
<hashTree>
Expand Down
Loading

0 comments on commit df124bc

Please sign in to comment.