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
remove ProxyControl dependency on GuiPackage #3491
Comments
Jaroslaw Fuks (migrated from Bugzilla):
|
@pmouawad (migrated from Bugzilla): Regards |
Wyatt Epp (migrated from Bugzilla): |
Wyatt Epp (migrated from Bugzilla): The method I was using for 2.13 was a shortcut that worked fine, but I had to rewrite it to create JMeterTreeNode.parent relations after updating. But that caused this to become an issue at runtime. The posted patch still applies mostly clean; needs two small changes. I'll attach an updated version. |
Wyatt Epp (migrated from Bugzilla): newpatch.diffdiff --git a/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java b/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
index f0e8cb8..fc79fdc 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
@@ -222,6 +222,8 @@ public class ProxyControl extends GenericController {
// If this is defined, it is assumed to be the alias of a user-supplied certificate; overrides dynamic mode
static final String CERT_ALIAS = JMeterUtils.getProperty("proxy.cert.alias"); // $NON-NLS-1$
+ private static JMeterTreeModel treeModel = null;
+
public enum KeystoreMode {
USER_KEYSTORE, // user-provided keystore
JMETER_KEYSTORE, // keystore generated by JMeter; single entry
@@ -246,6 +248,10 @@ public class ProxyControl extends GenericController {
log.warn("HTTP(S) Test Script Recorder SSL Proxy will use keys that may not work for embedded resources in file " + CERT_PATH_ABS);
}
}
+
+ if (GuiPackage.getInstance() != null) {
+ treeModel = GuiPackage.getInstance().getTreeModel();
+ }
}
// Whether to use the redirect disabling feature (can be switched off if it does not work)
@@ -300,6 +306,14 @@ public class ProxyControl extends GenericController {
setCaptureHttpHeaders(true); // maintain original behaviour
}
+ /**
+ * When working without GUI required for operation
+ * @param treeModel JMeterTreeModel used for recording
+ */
+ public static void setGlobalTreeRoot(JMeterTreeModel treeModel) {
+ ProxyControl.treeModel = treeModel;
+ }
+
public void setPort(int port) {
this.setProperty(new IntegerProperty(PORT, port));
}
@@ -485,6 +499,7 @@ public class ProxyControl extends GenericController {
try {
server = new Daemon(getPort(), this);
server.start();
+ if (GuiPackage.getInstance() != null)
GuiPackage.getInstance().register(server);
} catch (IOException e) {
log.error("Could not create Proxy daemon", e);
@@ -674,6 +689,7 @@ public class ProxyControl extends GenericController {
public void stopProxy() {
if (server != null) {
server.stopServer();
+ if (GuiPackage.getInstance() != null)
GuiPackage.getInstance().unregister(server);
try {
server.join(1000); // wait for server to stop
@@ -972,7 +988,6 @@ public class ProxyControl extends GenericController {
* <code>null</code> if none was found.
*/
private JMeterTreeNode findFirstNodeOfType(Class<?> type) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
List<JMeterTreeNode> nodes = treeModel.getNodesOfType(type);
for (JMeterTreeNode node : nodes) {
if (node.isEnabled()) {
@@ -1038,7 +1053,6 @@ public class ProxyControl extends GenericController {
*/
// TODO - could be converted to generic class?
private Collection<?> findApplicableElements(JMeterTreeNode myTarget, Class<? extends TestElement> myClass, boolean ascending) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
LinkedList<TestElement> elements = new LinkedList<>();
// Look for elements directly within the HTTP proxy:
@@ -1096,8 +1110,6 @@ public class ProxyControl extends GenericController {
private void placeSampler(final HTTPSamplerBase sampler, final TestElement[] subConfigs,
JMeterTreeNode myTarget) {
try {
- final JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
-
boolean firstInBatch = false;
long now = System.currentTimeMillis();
long deltaT = now - lastTime;
@@ -1288,7 +1300,6 @@ public class ProxyControl extends GenericController {
* sampling event to be delivered
*/
private void notifySampleListeners(SampleEvent event) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) {
@@ -1307,7 +1318,6 @@ public class ProxyControl extends GenericController {
* (here meaning the proxy recording) has started.
*/
private void notifyTestListenersOfStart() {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) {
@@ -1326,7 +1336,6 @@ public class ProxyControl extends GenericController {
* (here meaning the proxy recording) has ended.
*/
private void notifyTestListenersOfEnd() {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) { |
@pmouawad (migrated from Bugzilla):
Thanks for patch. |
Wyatt Epp (migrated from Bugzilla):
It's just an update of Jarek's patch, so usage is unchanged from Comment 2 (only necessary when you're running headless). |
@pmouawad (migrated from Bugzilla): |
Wyatt Epp (migrated from Bugzilla):
Complete example of using... what, exactly? It's not clear what you're looking for.
Well... yes? I mean, that's the only way to record headless, right now. BTW, would it be asking too much to get this patch added to the 3.1 branch? |
@pmouawad (migrated from Bugzilla):
Of using JMeter in headless mode to record.
So my request is to have an example of using the API.
Yes if you are able to provide this example :-) |
Wyatt Epp (migrated from Bugzilla):
Please clarify your definition of "complete", then? Anyway, the sample in Comment 2 should be plenty for anyone deep enough into the code that they're legitimately affected by this bug (especially prior to 3.0, where you didn't have to properly establish JMeterTreeNode.parent relations on your RecordingController et al to capture properly). |
@pmouawad (migrated from Bugzilla):
If snipped above is fine, then that's what I mean by complete :-) |
Wyatt Epp (migrated from Bugzilla):
Well, it was more than enough for me, so great! It'll be very nice to have this; I had to reopen a bug in our internal tracker when I rolled back to 2.13. Thanks! |
@pmouawad (migrated from Bugzilla):
Hi, If we add this patch to core, we need to provide a complete and working example and in this case see which API should be made public. That's why I am asking for those information. Thanks |
Wyatt Epp (migrated from Bugzilla):
What, you didn't expect that to run as-is, did you?
Oh, moving the goalposts on me? Rude. I'll play along, but only because we actually need this patch merged so we don't have to maintain our own version of JMeter internally.
What? No. Stop. The method this patch adds must be public; anything else would be completely useless. Created attachment MinimalProxy(1).java: "complete and working" example MinimalProxy(1).javaimport org.apache.jmeter.exceptions.IllegalUserActionException;
import org.apache.jmeter.gui.tree.JMeterTreeModel;
import org.apache.jmeter.gui.tree.JMeterTreeNode;
import org.apache.jmeter.protocol.http.proxy.ProxyControl;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.ListedHashTree;
import java.io.IOException;
public class MinimalProxy {
public static void main(String args[]) throws IOException, IllegalUserActionException {
// Without these, no ResourceBundle is made, and you get an NPE
// at org.apache.jmeter.util.JMeterUtils.getResStringDefault(JMeterUtils.java:505)
JMeterUtils.setJMeterHome("/opt/jmeter"); // Or wherever you put it.
JMeterUtils.loadJMeterProperties(JMeterUtils.getJMeterBinDir() + "/jmeter.properties");
JMeterUtils.initLocale();
TestPlan testPlan = new TestPlan();
ThreadGroup threadGroup = new ThreadGroup();
ListedHashTree testPlanTree = new ListedHashTree();
testPlanTree.add(testPlan);
testPlanTree.add(threadGroup, testPlan);
JMeterTreeModel treeModel = new JMeterTreeModel(new Object());
ProxyControl.setGlobalTreeRoot(treeModel);
JMeterTreeNode root = (JMeterTreeNode) treeModel.getRoot();
treeModel.addSubTree(testPlanTree, root);
ProxyControl proxy = new ProxyControl();
proxy.setTarget(treeModel.getNodeOf(threadGroup));
treeModel.addComponent(proxy, (JMeterTreeNode) root.getChildAt(1));
proxy.startProxy();
}
} |
@pmouawad (migrated from Bugzilla):
I did :-)
:-)
Of course for this one. Thanks for patch and example |
@pmouawad (migrated from Bugzilla): Few questions:
I suppose you have some custom development to do that ? Any chance you contribute more ?
Regards |
Wyatt Epp (migrated from Bugzilla):
That's far beyond the scope of this bug. Think of it as an exercise for the reader. ;)
I'd like to, but we've been over this before: I can't actually release/upstream our full headless recording daemon until the release has been cleared with legal. I'm still making noise about it, but it's not up to me and I don't have an ETA. I'm in a bit of a grey area already for cleaning up that patch and sample.
Maybe. In practice, we've found it works best to have the recorder be a daemon that accepts commands from a TCP client and gives feedback. (Similar to how jcmd or jfr work, I think.) BTW, can you be update the milestone? I don't have permissions for that. |
@FSchumacher (migrated from Bugzilla): @wyatt @Team Created attachment 0001-Allow-to-override-the-JMeterTreeModel-for-non-GUI-mo.patch: Allow to use ProxyControl in non GUI mode 0001-Allow-to-override-the-JMeterTreeModel-for-non-GUI-mo.patchFrom f49e763a418f230c9755056a7e935b008e6893d2 Mon Sep 17 00:00:00 2001
From: Felix Schumacher <felix.schumacher@internetallee.de>
Date: Thu, 20 Oct 2016 22:11:36 +0200
Subject: [PATCH] Allow to override the JMeterTreeModel for non-GUI mode
---
.../jmeter/protocol/http/proxy/ProxyControl.java | 51 ++++++++++++++++++----
1 file changed, 42 insertions(+), 9 deletions(-)
diff --git a/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java b/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
index c9a2e10..989cba8 100644
--- a/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
+++ b/src/protocol/http/org/apache/jmeter/protocol/http/proxy/ProxyControl.java
@@ -301,6 +301,8 @@ public class ProxyControl extends GenericController {
private String keyPassword;
+ private JMeterTreeModel nonGuiTreeModel;
+
public ProxyControl() {
setPort(DEFAULT_PORT);
setExcludeList(new HashSet<String>());
@@ -308,6 +310,19 @@ public class ProxyControl extends GenericController {
setCaptureHttpHeaders(true); // maintain original behaviour
}
+ /**
+ * Set a {@link JMeterTreeModel} to be used by the ProxyControl, when used
+ * in a non-GUI environment, where the {@link JMeterTreeModel} can't be
+ * acquired through {@link GuiPackage#getTreeModel()}
+ *
+ * @param treeModel
+ * the {@link JMeterTreeModel} to be used, or {@code null} when
+ * the GUI model should be used
+ */
+ public void setNonGuiTreeModel(JMeterTreeModel treeModel) {
+ this.nonGuiTreeModel = treeModel;
+ }
+
public void setPort(int port) {
this.setProperty(new IntegerProperty(PORT, port));
}
@@ -475,6 +490,13 @@ public class ProxyControl extends GenericController {
return getPropertyAsString(CONTENT_TYPE_INCLUDE);
}
+ /**
+ * @return the {@link JMeterTreeModel} used when run in non-GUI mode, or {@code null} when run in GUI mode
+ */
+ public JMeterTreeModel getNonGuiTreeModel() {
+ return nonGuiTreeModel;
+ }
+
public void addConfigElement(ConfigElement config) {
// NOOP
}
@@ -493,7 +515,9 @@ public class ProxyControl extends GenericController {
try {
server = new Daemon(getPort(), this);
server.start();
- GuiPackage.getInstance().register(server);
+ if (GuiPackage.getInstance() != null) {
+ GuiPackage.getInstance().register(server);
+ }
} catch (IOException e) {
log.error("Could not create Proxy daemon", e);
throw e;
@@ -682,7 +706,9 @@ public class ProxyControl extends GenericController {
public void stopProxy() {
if (server != null) {
server.stopServer();
- GuiPackage.getInstance().unregister(server);
+ if (GuiPackage.getInstance() != null) {
+ GuiPackage.getInstance().unregister(server);
+ }
try {
server.join(1000); // wait for server to stop
} catch (InterruptedException e) {
@@ -819,7 +845,7 @@ public class ProxyControl extends GenericController {
* @param target {@link JMeterTreeNode}
*/
private void setAuthorization(Authorization authorization, JMeterTreeNode target) {
- JMeterTreeModel jmeterTreeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel jmeterTreeModel = getJmeterTreeModel();
List<JMeterTreeNode> authManagerNodes = jmeterTreeModel.getNodesOfType(AuthManager.class);
if (authManagerNodes.size() == 0) {
try {
@@ -835,6 +861,13 @@ public class ProxyControl extends GenericController {
}
}
+ private JMeterTreeModel getJmeterTreeModel() {
+ if (this.nonGuiTreeModel == null) {
+ return GuiPackage.getInstance().getTreeModel();
+ }
+ return this.nonGuiTreeModel;
+ }
+
/**
* Helper method to add a Response Assertion
* Called from AWT Event thread
@@ -980,7 +1013,7 @@ public class ProxyControl extends GenericController {
* <code>null</code> if none was found.
*/
private JMeterTreeNode findFirstNodeOfType(Class<?> type) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel treeModel = getJmeterTreeModel();
List<JMeterTreeNode> nodes = treeModel.getNodesOfType(type);
for (JMeterTreeNode node : nodes) {
if (node.isEnabled()) {
@@ -1046,7 +1079,7 @@ public class ProxyControl extends GenericController {
*/
// TODO - could be converted to generic class?
private Collection<?> findApplicableElements(JMeterTreeNode myTarget, Class<? extends TestElement> myClass, boolean ascending) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel treeModel = getJmeterTreeModel();
LinkedList<TestElement> elements = new LinkedList<>();
// Look for elements directly within the HTTP proxy:
@@ -1104,7 +1137,7 @@ public class ProxyControl extends GenericController {
private void placeSampler(final HTTPSamplerBase sampler, final TestElement[] testElements,
JMeterTreeNode myTarget) {
try {
- final JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ final JMeterTreeModel treeModel = getJmeterTreeModel();
boolean firstInBatch = false;
long now = System.currentTimeMillis();
@@ -1326,7 +1359,7 @@ public class ProxyControl extends GenericController {
* sampling event to be delivered
*/
private void notifySampleListeners(SampleEvent event) {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel treeModel = getJmeterTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) {
@@ -1345,7 +1378,7 @@ public class ProxyControl extends GenericController {
* (here meaning the proxy recording) has started.
*/
private void notifyTestListenersOfStart() {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel treeModel = getJmeterTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) {
@@ -1364,7 +1397,7 @@ public class ProxyControl extends GenericController {
* (here meaning the proxy recording) has ended.
*/
private void notifyTestListenersOfEnd() {
- JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
+ JMeterTreeModel treeModel = getJmeterTreeModel();
JMeterTreeNode myNode = treeModel.getNodeOf(this);
Enumeration<JMeterTreeNode> kids = myNode.children();
while (kids.hasMoreElements()) {
--
2.7.4
|
Wyatt Epp (migrated from Bugzilla):
That's just how the original patch posted by the reporter did things-- all I did was fix up his patch to apply clean on the 3.0 source tree. If I had to guess it's just because he thought it was more natural to set things up by calling a static method. (I happen to disagree.) I'm pretty sure it'll be fine if it's not static.
We would appreciate it greatly. |
@pmouawad (migrated from Bugzilla):
Hi Felix, Thanks for review and patch |
Wyatt Epp (migrated from Bugzilla):
Eh? The whole API is already public (if largely undocumented)-- I wouldn't have been able to write any of our tooling otherwise.
That's because there isn't one. For all that it only ends up being about twenty lines of code, it was really annoying to write that part, in fact. (It would be quite grand if there were a simple way to dump a JMeterTreeNode or JMeterTreeModel to JMX via SaveService. But there isn't. Has anyone filed a bug about that...?) |
@FSchumacher (migrated from Bugzilla): Date: Fri Oct 28 17:56:25 2016 URL: http://svn.apache.org/viewvc?rev=1767048&view=rev Added: |
Lars H (migrated from Bugzilla): It would be very useful for me (and others too, I think) if this could be exposed as a script, useable out of the box (similar to bin/mirror-server). Perhaps it could trigger writing the test plan on receiving SIGINT/CTRL-C from the user. |
Wyatt Epp (migrated from Bugzilla):
I'd recommend filing a bug about that separately. |
Lars H (migrated from Bugzilla):
Yes that makes sense. Added separate issue for the script: #4164 |
Jaroslaw Fuks (Bug 57305):
I'm running proxy without UI.
Main problem is that ProxyControl class uses
GuiPackage.getInstance().getTreeModel() as source of tree model
to fix this i've added static member to ProxyControl,
witch can be overridden by user.
Created attachment jmeter.patch: patch implementing this feature
jmeter.patch
Votes in Bugzilla: 2
OS: All
The text was updated successfully, but these errors were encountered: