3

From a JSR223 Sampler, I can get access to the current test element using the sampler variable.

From there, how can I navigate the tree of TestElement objects? For example, how can I get access to the parent test element (and then it’s parent, etc) or how can I get access to the TestPlan test element?

Background:

I want to dynamically create a JDBC Connection Configuration element from a JSR223 Sampler using Groovy.

From other questions (e.g., here) and web searches (e.g., here), I know how to create test plan elements from the top down (e.g., how to create a test plan and build the tree down from there). So I know how to do the new DataSourceElement() which is a TestElement but I don’t know how to add that new element to the test plan. In the sampler script I have access to the sampler (Sampler) and the ctx (JMeterContext) variables but I don’t know how to navigate the test element tree.

I tried just using sampler.addTestElement but a config element isn’t really valid under a sampler element. Still, I did try but the config element was not found when I tried to use it in a JDBC Request (error: "No pool found named: 'myDatabaseThreadPool', ensure Variable Name matches Variable Name of JDBC Connection Configuration").

I’m hoping that if I can get the TestPlan element and add the config element to that, then it would work.

FWIW, my test plan looks like this:

  • Test Plan
    • Thread Group 1 (could be a setup thread group)
      • JSR223 Sampler (this is where I want to create the dynamic config)
    • Thread Group 2 (multiple threads)
      • JDBC Request (uses the pool variable name specified in the dynamic config)
    • View Results Tree

I can go into further detail about why I want to dynamically create the JDBC Connection Configuration, but if there’s an easy answer about how to navigate the test element tree from inside my sampler script I’d like to know that anyway.

Community
  • 1
  • 1
jonathan.s
  • 349
  • 3
  • 5

1 Answers1

1

As you have mentioned you have access to JMeterContext via ctx shorthand. Hence you have access to StandardJMeterEngine class instance via ctx.getEngine(); method.

Looking into StandardJMeterEngine source you can see that test plan is being stored as HashTree structure:

private HashTree test;

So the choices are in:

Reference code:

import org.apache.jmeter.engine.StandardJMeterEngine;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jorphan.collections.HashTree;
import org.apache.jorphan.collections.SearchByClass;

import java.lang.reflect.Field;
import java.util.Collection;

StandardJMeterEngine engine = ctx.getEngine();
Field test = engine.getClass().getDeclaredField("test");
test.setAccessible(true);
HashTree testPlanTree = (HashTree) test.get(engine);

SearchByClass testPlans = new SearchByClass(TestPlan.class);
testPlanTree.traverse(testPlans);
Collection testPlansRes = testPlans.getSearchResults();

TestPlan testPlan = (TestPlan)testPlansRes.toArray()[0];
//do what you need with "testPlanTree" and/or "testPlan"

Check out How to Use BeanShell: JMeter's Favorite Built-in Component guide for more information using JMeter and Java API from scripting test elements.

Dmitri T
  • 159,985
  • 5
  • 83
  • 133
  • It's worth noting that groovy doesn't care about private fields, so if you're using the groovy script engine (which is recommended) then you can just access the ctx.getEngine().test field like it's nobody's business. – Jake Turner Jun 25 '19 at 14:32
  • It's normal [Java Reflection](https://docs.oracle.com/javase/tutorial/reflect/index.html) mechanism functionality, you can access private fields and invoke private methods from core Java as well as from any scripting language. – Dmitri T Jun 25 '19 at 15:22