Jmeter: unable to use multiple conditional statements in If Controller - if-statement

ANSWER TO THE QUESTION
Please, dear reader, if you wish, you can proceed further and read through the question. But at the most top I'm willing to provide Dmitri's answer, so that others won't waste time playing around with Jmeter If Controller.
If you wish to use multiple condition statement in If Controller,
specifically if you want to check that variables equal some strings,
DON'T USE ${__javaScript()} FUNTION!!! Dmitri suggested to use instead
${__groovy()} function, which worked in my situation. Correct syntax
below. Pay attention to opening parenthesis, comma location and closing curly brackets:
${__groovy((vars.get('yourVariable').equals('someString') &&
vars.get('yourAnotherVariable').equals('someOtherString')),)}
Addition
If you want to save your time while trying to make If Controller working with multiple conditions, always uncheck Interpret Condition as Variable Expression checkbox. Otherwise you will have to stuck with those __javaScript, __groovy or other functions, as there is no way to understand how the hell they suppose to work and why they don't resolve to true or false (log file is always clean at this situation). This is how you do without help of those "functions". Please see my example below
${yourVariable} != 'not_found' && ${youAnotherVariable_matchNr} == 1
That's it, no need to use any functions.
INITIAL QUESTION
In Jmeter v4.0 r 1823414 I can use If Controller only with single statement, but not with multiple. Example of using multiple statements I have taken from here and it was suggested to use
${__javaScript("${responsecode}"=="404")} &&
${__javaScript("${responseMessage}" == "Not Found")}
I have also checked blazemeter tutorial page, but it says nothing about multiple conditional statements inside If Controller.
Example of my Test Plan is below
In my Debug Sampler I can see following
At some place in the Test Plan I put IF Controller to check that both variables are equal to not_found...
${__javaScript(vars.get('manual_bug')=='not_found')} && ${__javaScript(vars.get('integration_bug')=='not_found')}
...so all the subsequent actions are executed. However, this IF Controller either never gets executed or always return FALSE. Not sure what's happening with it.
Before blaming me :-) that I didn't do enough research and rushed to ask a question on SO, I will provide below samples of what I've already tried and that didn't help:
With double quotes around variables
${__javaScript(vars.get("manual_bug")=="not_found")} && ${__javaScript(vars.get("integration_bug")=="not_found")}
With additional space between equal sign
${__javaScript(vars.get('manual_bug') == 'not_found')} &&
${__javaScript(vars.get('integration_bug') == 'not_found')}
Avoid using vars.get
${__javaScript(${manual_bug} == 'not_found')} && ${__javaScript(${integration_bug} == 'not_found')}
Using double quotes without vars.get
${__javaScript(${manual_bug} == "not_found")} && ${__javaScript(${integration_bug} == "not_found")}
My log file looks completely fine, no errors
Please advise if someone was able to execute multiple conditional statements in the Jmeter tool? Thanks!

In the link you're referencing the 2 clauses are in a single __javaScript() function and you have 2 different functions so JMeter doesn't know what does your && means especially given Interpret Condition as Variable Expression? default mode of the If Controller.
Also if you open If Controller GUI you will see the following warning:
For performance it is advised to check "Interpret Condition as Variable Expression"
and use __jexl3 or __groovy evaluating to true or false or a variable that contains true or false.
${JMeterThread.last_sample_ok} can be used to test if last sampler was successful
Therefore I would recommend reconsidering your approach and use __groovy() function, the relevant syntax would be:
${__groovy((vars.get('responseCode').equals('404') && vars.get('responseMessage').equals('Not Found')),)}
Demo:

The following syntax (with double quotes) works too, however it also requires that you uncheck the 'Interpret Condition as Variable Expression' setting.
"${yourVariable}" != "not_found" && "${youAnotherVariable_matchNr}" == "1"

Related

Ignoring cookies list efficiently in NGINX reverse proxy setup

I am currently working/testing microcache feature in NGINX reverse proxy setup for dynamic content.
One big issue that occurs is sessions/cookies that need to be ignored otherwise people will logon with random accounts on the site(s).
Currently I am ignoring popular CMS cookies like this:
if ($http_cookie ~* "(joomla_[a-zA-Z0-9_]+|userID|wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|wordpress_logged_in_[a-zA-Z0-9]+|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|sid_customer_|sid_admin_|PrestaShop-[a-zA-Z0-9]+")
{
# set ignore variable to 1
# later used in:
# proxy_no_cache $IGNORE_VARIABLE;
# proxy_cache_bypass $IGNORE_VARIABLE;
# makes sense ?
}
However this becomes a problem if I want to add more cookies to the ignore list. Not to mention that using too many "if" statements in NGINX is not recommended as per the docs.
My questions is, if this could be done using a map method ? I saw that regex in map is different( or maybe I am wrong ).
Or is there another way to efficiently ignore/bypass cookies ?
I have search a lot on stackoverflow, and whilst there are so many different examples; I could not find something specific for my needs.
Thank you
Update:
A lot of reading and "digging" on the internet ( we might as well just say Google ), and I found quite some interesting examples.
However I am very confused with these, as I do not fully understand the regex usage and I am afraid to implement such without understanding it.
Example 1:
map $http_cookie $cache_uid {
default nil;
~SESS[[:alnum:]]+=(?<session_id>[[:alnum:]]+) $session_id;
}
In this example I can notice that the regex is very different from
the ones used in "if" blocks. I don't understand why the pattern
starts without any "" and directly with just a ~ sign.
I don't understand what does [[:alnum:]]+ mean ? I search for this
but I was unable to find documentation. ( or maybe I missed it )
I can see that the author was setting "nil" as default, this will
not apply for my case.
Example 2:
map $http_cookie $cache_uid {
default '';
~SESS[[:alnum:]]+=(?<session_id>[[:graph:]]+) $session_id;
}
Same points as in Example 1, but this time I can see [[:graph:]]+.
What is that ?
My Example (not tested):
map $http_cookie $bypass_cache {
"~*wordpress_(?!test_)[a-zA-Z0-9_]+" 1;
"~*wp-postpass|wordpress_logged_in_[a-zA-Z0-9]+" 1;
"~*comment_author_[a-zA-Z0-9_]+" 1;
"~*[a-zA-Z0-9]+_session)" 1;
default 0;
}
In my pseudo example, the regex must be wrong since I did not find any map cookie examples with such regex.
So once again my goal is to have a map style list of cookies that I can bypass the cache for, with proper regex.
Any advice/examples much appreciated.
What exactly are you trying to do?
The way you're doing it, by trying to blacklist only certain cookies from being cached, through if ($http_cookie …, is a wrong approach — this means that one day, someone will find a cookie that is not blacklisted, and which your backend would nonetheless accept, and cause you cache poisoning or other security issues down the line.
There's also no reason to use the http://nginx.org/r/map approach to get the values of the individual cookies, either — all of this is already available through the http://nginx.org/r/$cookie_ paradigm, making the map code for parsing out $http_cookie rather redundant and unnecessary.
Are there any cookies which you actually want to cache? If not, why not just use proxy_no_cache $http_cookie; to disallow caching when any cookies are present?
What you'd probably want to do is first have a spec of what must be cached and under what circumstances, only then resorting to expressing such logic in a programming language like nginx.conf.
For example, a better approach would be to see which URLs should always be cached, clearing out the Cookie header to ensure that cache poisoning isn't possible (proxy_set_header Cookie "";). Else, if any cookies are present, it may either make sense to not cache anything at all (proxy_no_cache $http_cookie;), or to structure the cache such that certain combination of authentication credentials are used for http://nginx.org/r/proxy_cache_key; in this case, it might also make sense to reconstruct the Cookie request header manually through a whitelist-based approach to avoid cache-poisoning issues.
You 2nd example that you have is what you actually need
map $http_cookie $bypass_cache {
"~*wordpress_(?!test_)[a-zA-Z0-9_]+" 1;
"~*wp-postpass|wordpress_logged_in_[a-zA-Z0-9]+" 1;
"~*comment_author_[a-zA-Z0-9_]+" 1;
"~*[a-zA-Z0-9]+_session)" 1;
default 0;
}
Basically here what you are saying the bypass_cache value will be 1 if the regex is matched else 0.
So as long as you got the pattern right, it will work. And that list only you can have, since you would only know which cookies to bypass cache on

How to install feature based on the property set in custom action?

I am trying to install one from two features based on the value that should be set inside of the custom action.
Firstly, I set the value of a property:
UINT __stdcall ConfigurationCheckAction(MSIHANDLE hInstall)
{
HRESULT hr = S_OK;
UINT er = ERROR_INSTALL_FAILURE;
hr = WcaInitialize(hInstall, "ConfigurationCheckAction");
if (condition) {
MsiSetProperty( hInstall, TEXT("STREAM"), TEXT("RED") );
}
else {
MsiSetProperty( hInstall, TEXT("STREAM"), TEXT("BLUE") );
}
return WcaFinalize(er);
}
Secondly, I make two conditions per two features:
<Feature Id='Complete' Level='1'>
<Feature Id="Red" ConfigurableDirectory="TARGETDIR" Title="F1" Level="0">
<Condition Level="1">STREAM</Condition>
</Feature>
<Feature Id="Blue" ConfigurableDirectory="TARGETDIR" Title="F2" Level="0">
<Condition Level="1">NOT STREAM</Condition>
</Feature>
</Feature>
Note that I don't define property inside of the wxs file previously, as I would like to set it from the custom action.
My custom action is called before InstallInitialize and Execute is immediate.
From the installation log I have confirmation that the property is set.
However, my conditional installation does not work, as it seems like what is in the condition is always evaluated as false.
I tried evaluating conditions:
STREAM, STREAM=RED, STREAM="RED", < ![CDATA[STREAM=RED]]>
I am running out of ideas what to do and would appreciate help.
Too late to test all of this, but here goes with some information. I will check back tomorrow. Essentially I think the problem is your custom action sequencing. Try before Costing.
Some things to consider:
Custom action sequencing: you need to sequence your custom action right and it needs to be present in both silent and interactive installation modes.
Did you try to sequence the set property custom action before CostInitialize? You state you set it before InstallInitialize, but try it before CostInitialize instead (you might have tried).
And did you remember to insert this custom action in the InstallUISequence as well as the InstallExecuteSequence? You need to insert in both sequences in case the setup runs in silent mode. Before CostInitialize in both sequences I believe.
Feature Level: manipulating features via the feature level and INSTALLLEVEL is just one way to do feature control, you can also set features via the command line or using a custom action.
Setting a feature level to 0 should hide the feature from view in the setup's custom dialog.
Setting a feature level higher than the setup's INSTALLLEVEL will deselect the feature from installation.
And the other way around setting a feature level lower or equal to the setup's INSTALLLEVEL will select the feature for installation.
The conditional syntax allowed is quite flexible, and could provide the functionality you need outright - but I have never used them properly. Here is an example from the Installshield forum.
ADDLOCAL & REMOVE: you can manipulate the feature selection by changing the values of the ADDLOCAL and REMOVE properties from a custom action (technically also REINSTALL and ADVERTISE) - and these properties can be set via the command line as well.
Win32: you can also use the Win32 functions MsiGetFeatureState and MsiSetFeatureState - from a C++ custom action - to set feature selection.
Frankly it is a bit mad the whole thing. Also keep in mind that there are feature action states (what is going to happen to a feature) and feature installed states (what state it is in). The Win32 function documentation should explain.
Cross-linking for easy retrieval:
Unselected Feature Being Installed
I have done something similar, but we ended up controlling this at a component level(adding the condition to the <Component/> elements instead of the feature element using a transform during heat). But our condition utilizes CDATA while also using double quotes for the value, which you don't list in what you've tried. So first I'd try the following conditions in your features:
<Condition><![CDATA[STREAM="RED"]]></Condition>
<Condition><![CDATA[STREAM="BLUE"]]></Condition>
If that still does not work, I would try the following:
Add the STREAM property with a default value to your WiX. Then test it with that default value to see if having the default value set to begin with makes it work. That could mean you need to set the property sooner, possibly off a UI event. <Property Id="STREAM" Value="RED"/>
As a last resort, you could add the conditions to each component as I did, but we only did that for very specific reasons, hopefully you can get the conditional feature to work with the above suggestions!
I hope the above fixes your problem, or at least leads you to the answer!
Thank you for your replies. In the end, a combination of your suggestions helped me.
I want to state what did and what did not work:
Adding property to WiX with a default value was not necessary (as well with adding property of this property Secure='yes')
Calling custom action before CostInitialize did not solve the problem on its own, but I believe it was one of the factors that resolved an issue.
Conditional sintax was corrected by:
a) Putting condition inside of CDATA and adding quotes to the value of property as suggested: <Condition><![CDATA[STREAM="RED"]]></Condition>
b) Reversing condition levels so feature has condition level 1 and condition has level 0. This means that feature is always installed, unless the condition expression is false.
Concerning the correct order of the custom actions, the description of the custom action type 51 contains the decisive hint:
"To affect a property used in a condition on a component or feature, the custom action must come before the CostFinalize action in the action sequence."

How to write Bean Shell Script to compare two variables and print the output. JMETER

I have two variable 1)Expected(taken from excel file) & 2)Actual(regex from result)
Now i tried to compare both the variables using bean Shell Post processor Scripting.
if(("${Expected}").equals("${Actual}"))
{
IsSuccess = true;
}
else
{
IsSuccess = false;
}
which should actually mark sample as pass and fail according to the comparison.
But i can't find the sampler marked fail when the comparison returns false.
Is their any error in my condition.
Also Please help to print output to console
Help is appreciated.
Thank You
Don't inline JMeter Variables or Functions into a Beanshell (or any other) script, they might resolve into something which will cause compilation failure
If you want to mark sampler as passed or failed from the Post-Processor you should be doing it a little bit differently
Example suggested code:
if (vars.get("Expected").equals(vars.get("Actual"))) {
prev.setSuccessful(true);
}
else {
prev.setSuccessful(false);
}
Other recommendations:
Going forward consider switching to JSR223 PostProcessor and Groovy language as Groovy performance is much higher for any scripting implementations
You can achieve the same without having to write a single line of code via "normal" Response Assertion, example configuration would be something like:
See How to Use JMeter Assertions in Three Easy Steps article for more information on conditionally passing/failing your JMeter samplers using assertions.

How to implement If Else block in Jmeter test plan?

I have a task where I need to perform two tasks based on the previous Sampler result.
If Assertion fails
{
send email with the error message.
}else
{
perform the tasks in while controller.
}
I have achieved the first part easily by providing the condition in If controller ${JMeterThread.last_sample_ok} == false
I have problems going to else block. I have tried two IF controllers but with no success.
Case here is need to perform one task only either IF block or Else block. But In my case it goes to both the blocks and perform both the tasks.
Can anyone help how to achieve this?
There is no "Else" block in JMeter, you have only "If" therefore if you need "Else" behavior you need to use 2 IF Controllers with opposite conditions.
But, for 2nd If Controller you won't be able to use this as this ${JMeterThread.last_sample_ok} variable will be overwritten with the result of your SMTP Sampler so if your SMTP Sampler will be successful ${JMeterThread.last_sample_ok} variable will become true therefore second If Controller will be executed as well.
So I would recommend the following approach:
If your Assertion Fails
In Beanshell PreProcessor define a custom variable like:
vars.put("run_while_controller", "false");
Put your While Controller under another If Controller and use ${run_while_controller} as a condition
Alternative option is stopping the test after sending an email, this can be done using i.e. Test Action sampler
Going forward I would suggest using Debug Sampler and View Results Tree Listener to double check all the JMeter Variables values, this is most convenient way to see all JMeter variables and properties values. See How to Debug your Apache JMeter Script article for more information on getting to the bottom of your JMeter test unexpected behavior.

Use of if controller for check condition in jmeter

I need to add a check condition for the search result page that, if a search result is found, the script should run further otherwise it should stop on the same step.
This is my Condition in if controller:
${__javaScript("${depdate}"=! null)}
Here depdate is the regex parameter. If search results are found then its value will be null otherwise it will display content. It's a part of a json string.
I have put all further step in the if controller, but not success. Can anyone help me out of this? What is the reason that this is not working.
What is wrong here with what I am performing?
The reason is that your "${depdate}" will never be null.
If ${depdate} variable is set - it will be variable value
If ${depdate} variable is not set - it will be default value (which is ${depdate}
Demo:
So change your expression to be `${__javaScript(vars.get("depdate") != null)} and everything should start working fine.
See How to Use JMeter's 'IF' Controller and get Pie guide for more information on using IF conditions in your JMeter test.