You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jmeter.apache.org by "vlsi (via GitHub)" <gi...@apache.org> on 2023/05/27 15:22:48 UTC

[GitHub] [jmeter] vlsi opened a new issue, #5946: Add API to declare TestElement schemas

vlsi opened a new issue, #5946:
URL: https://github.com/apache/jmeter/issues/5946

   ### Use case
   
   Currently, JMeter has two approaches for creating test elements:
   * `implements TestBean`
   * `implements TestElement`
   
   `TestBean`-based elements do not mange `JMeterProperty` themselves, and they rely on `Introspector` and `BeanInfo` to manage the properties.
   
   `TestElement`-based elements (e.g. the ones that extend `AbstractTestElement`) have manage their properties on their own.
   There are several issues with that:
   1. The is no clear way to see which properties are "well-known". Sometimes the elements declare something like `public static final String PORT = "HTTPSampler.port"`, however, it is unclear what is the expected property type, the default value is not there, and sometimes the strings are even `private` (see `TestPlan`, `private static final String FUNCTIONAL_MODE = "TestPlan.functional_mode";`)
   2. Currently, the default value should be passed on every property get and set. For instance, see `ResultCollector`, `getPropertyAsBoolean(SUCCESS_ONLY_LOGGING,false)`. In that case, all users of `SUCCESS_ONLY_LOGGING` should pass the same `false` default value.
   3. Test elements often provide getters and setters for primitive values only. For instance, `org.apache.jmeter.testelement.TestPlan#isSerialized() return boolean` and `org.apache.jmeter.testelement.TestPlan#setSerialized(boolean)` accept only `boolean` values, and they do not allow users to configure `FunctionProperty` for `isSerialized` property.
   
   ### Possible solution
   
   Add API so the plugin authors could configure schema for their elements:
   
   ```kotlin
   public interface PropertyDescriptor {
       public val propertyName: String
       public val defaultValue: Any?
   }
   
   public data class BooleanPropertyDescriptor(
       public override val propertyName: String,
       /** Default value, null means there's no default */
       public override val defaultValue: Boolean?
   ): PropertyDescriptor
   
   public data class StringPropertyDescriptor(
       public override val propertyName: String,
       /** Default value, null means there's no default */
       public override val defaultValue: String?
   ): PropertyDescriptor
   ```
   
   ```kotlin
   /** Similar to Java's Object */
   public abstract class JMeterElementClass {
       private val propertyDescriptors: MutableMap<String, PropertyDescriptor> = mutableMapOf()
       protected fun string(name: String): StringPropertyDescriptor =
           StringPropertyDescriptor(name, null).also {
               propertyDescriptors[name] = it
           }
   
       @JvmOverloads
       protected fun boolean(name: String, default: Boolean? = null): BooleanPropertyDescriptor =
           BooleanPropertyDescriptor(name, null).also {
               propertyDescriptors[name] = it
           }
   }
   
   
   public open class AbstractTestElementClass protected constructor(): JMeterElementClass() {
       public companion object {
           @JvmField
           public val INSTANCE: AbstractTestElementClass = AbstractTestElementClass()
       }
       public val name: StringPropertyDescriptor = string("TestElement.name")
       public val comments: StringPropertyDescriptor = string("TestElement.comments")
       public val guiClass: StringPropertyDescriptor = string("TestElement.gui_class")
       public val testClass: StringPropertyDescriptor = string("TestElement.testClass")
       public val enabled: BooleanPropertyDescriptor = boolean("TestElement.enabled", default = true)
   }
   
   public open class TestPlanClass protected constructor() : AbstractTestElementClass() {
       public companion object {
           @JvmField
           public val INSTANCE: TestPlanClass = TestPlanClass()
       }
       public val isSerialized: BooleanPropertyDescriptor = boolean("isserialized")
   }
   ```
   
   Then users would be able to access the properties like `TestPlanClass.INSTANCE.isSerialized` or `TestPlanClass.INSTANCE.comments`.
   
   `AbstractTestElement` could expose `JMeterElementClass` as well.
   
   For instance:
   
   ```java
   class AbstractTestElement {
       public JMeterElementClass getType() {
           return AbstractTestElementClass.INSTANCE;
       }
   }
   
   ...
   
   class TestPlan extends AbstractTestElement {
       public TestPlanClass getType() {
           return TestPlanClass.INSTANCE;
       }
   }
   ```
   
   Then it would be slightly easier to access the corresponding `JMeterClass`:
   
   ```java
   // kotlin
   val testPlan: TestPlan = ...;
   // type would return TestPlanClass, so IDE would autocomplete the possible property names
   testPlan.type.isSerialized
   ```
   
   ### Possible workarounds
   
   _No response_
   
   ### JMeter Version
   
   5.5
   
   ### Java Version
   
   _No response_
   
   ### OS Version
   
   _No response_


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@jmeter.apache.org.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [jmeter] vlsi commented on issue #5946: Add API to declare TestElement schemas

Posted by "vlsi (via GitHub)" <gi...@apache.org>.
vlsi commented on issue #5946:
URL: https://github.com/apache/jmeter/issues/5946#issuecomment-1578168295

   Partially implemented in https://github.com/apache/jmeter/pull/5944


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@jmeter.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [jmeter] vlsi commented on issue #5946: Add API to declare TestElement schemas

Posted by "vlsi (via GitHub)" <gi...@apache.org>.
vlsi commented on issue #5946:
URL: https://github.com/apache/jmeter/issues/5946#issuecomment-1565639598

   Java does not allow implementing interface with different type parameters: https://bugs.openjdk.org/browse/JDK-8030724
   That means we can't have something like `TestPlan implements DescribedBy<TestPlanClass>` and `TestElement implements DescribedBy<TestElementClass>` at the same time.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@jmeter.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [jmeter] vlsi commented on issue #5946: Add API to declare TestElement schemas

Posted by "vlsi (via GitHub)" <gi...@apache.org>.
vlsi commented on issue #5946:
URL: https://github.com/apache/jmeter/issues/5946#issuecomment-1567341770

   I've some progress in https://github.com/apache/jmeter/pull/5944.
   
   Sample usage in Kotlin.
   
   Note: BeanShellSampler has methods like `setScript(String)`, however, it sets plain Java field instead of passing the value to `setProperty(...)`.
   `props[{ script }] =...` sets a corresponding JMeter property.
   
   ```kotlin
   val sampler = BeanShellSampler().apply {
       name = "BeanShell Sampler"
       props[{ script }] = """ResponseMessage="COUNTER=${"$"}{__counter(FALSE)}""""
       props[{ filename }] = ""
       props[{ parameters }] = ""
       TestElementPropertyTransformer.USE_FUNCTIONS.visit(this)
       isRunningVersion = true
   }
   ```
   
   The same in Java:
   
   ```java
   BeanShellSampler sampler = new BeanShellSampler();
   sampler.setName("BeanShell Sampler");
   sampler.getProps().set(BeanShellSamplerClass::getScript, "ResponseMessage=\"COUNTER=${__counter(FALSE)}\"");
   sampler.getProps().set(BeanShellSamplerClass::getFilename, "");
   sampler.getProps().set(BeanShellSamplerClass::getParameters, "");
   TestElementPropertyTransformer.USE_FUNCTIONS.visit(sampler);
   sampler.setRunningVersion(true);
   ```
   
   In the ideal case, `BeanShellSampler` should expose the proper getters and setters on its own (e.g. `setScript(...)` that would propagate to `JMeterProperty`), however, having a common low-level API would be great.
   
   It would be nice to deprecate older "getPropertyAs(String, ..)` as they are unsafe form the `default value` point of view.
   In other words, if a property has a default value, then `getPropertyAs...` should return that default value instead of returning something else.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@jmeter.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


[GitHub] [jmeter] vlsi closed issue #5946: Add API to declare TestElement schemas

Posted by "vlsi (via GitHub)" <gi...@apache.org>.
vlsi closed issue #5946: Add API to declare TestElement schemas
URL: https://github.com/apache/jmeter/issues/5946


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@jmeter.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org